2025-12-11 21:50:42 +00:00
|
|
|
# Quick Developer Guide: Adding New Providers
|
|
|
|
|
|
|
|
|
|
This guide shows how to quickly add a new provider to the provider-agnostic infrastructure system.
|
|
|
|
|
|
|
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
|
|
- Understand the [Provider-Agnostic Architecture](PROVIDER_AGNOSTIC_ARCHITECTURE.md)
|
|
|
|
|
- Have the provider's SDK or API available
|
|
|
|
|
- Know the provider's authentication requirements
|
|
|
|
|
|
|
|
|
|
## 5-Minute Provider Addition
|
|
|
|
|
|
|
|
|
|
### Step 1: Create Provider Directory
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
mkdir -p provisioning/extensions/providers/{provider_name}
|
|
|
|
|
mkdir -p provisioning/extensions/providers/{provider_name}/nulib/{provider_name}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Step 2: Copy Template and Customize
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Copy the local provider as a template
|
|
|
|
|
cp provisioning/extensions/providers/local/provider.nu \
|
|
|
|
|
provisioning/extensions/providers/{provider_name}/provider.nu
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Step 3: Update Provider Metadata
|
|
|
|
|
|
|
|
|
|
Edit `provisioning/extensions/providers/{provider_name}/provider.nu`:
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
export def get-provider-metadata []: nothing -> record {
|
|
|
|
|
{
|
|
|
|
|
name: "your_provider_name"
|
|
|
|
|
version: "1.0.0"
|
|
|
|
|
description: "Your Provider Description"
|
|
|
|
|
capabilities: {
|
|
|
|
|
server_management: true
|
|
|
|
|
network_management: true # Set based on provider features
|
|
|
|
|
auto_scaling: false # Set based on provider features
|
|
|
|
|
multi_region: true # Set based on provider features
|
|
|
|
|
serverless: false # Set based on provider features
|
|
|
|
|
# ... customize other capabilities
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Step 4: Implement Core Functions
|
|
|
|
|
|
|
|
|
|
The provider interface requires these essential functions:
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
# Required: Server operations
|
|
|
|
|
export def query_servers [find?: string, cols?: string]: nothing -> list {
|
|
|
|
|
# Call your provider's server listing API
|
|
|
|
|
your_provider_query_servers $find $cols
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export def create_server [settings: record, server: record, check: bool, wait: bool]: nothing -> bool {
|
|
|
|
|
# Call your provider's server creation API
|
|
|
|
|
your_provider_create_server $settings $server $check $wait
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export def server_exists [server: record, error_exit: bool]: nothing -> bool {
|
|
|
|
|
# Check if server exists in your provider
|
|
|
|
|
your_provider_server_exists $server $error_exit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export def get_ip [settings: record, server: record, ip_type: string, error_exit: bool]: nothing -> string {
|
|
|
|
|
# Get server IP from your provider
|
|
|
|
|
your_provider_get_ip $settings $server $ip_type $error_exit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Required: Infrastructure operations
|
|
|
|
|
export def delete_server [settings: record, server: record, keep_storage: bool, error_exit: bool]: nothing -> bool {
|
|
|
|
|
your_provider_delete_server $settings $server $keep_storage $error_exit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export def server_state [server: record, new_state: string, error_exit: bool, wait: bool, settings: record]: nothing -> bool {
|
|
|
|
|
your_provider_server_state $server $new_state $error_exit $wait $settings
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Step 5: Create Provider-Specific Functions
|
|
|
|
|
|
|
|
|
|
Create `provisioning/extensions/providers/{provider_name}/nulib/{provider_name}/servers.nu`:
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
# Example: DigitalOcean provider functions
|
|
|
|
|
export def digitalocean_query_servers [find?: string, cols?: string]: nothing -> list {
|
|
|
|
|
# Use DigitalOcean API to list droplets
|
|
|
|
|
let droplets = (http get "https://api.digitalocean.com/v2/droplets"
|
|
|
|
|
--headers { Authorization: $"Bearer ($env.DO_TOKEN)" })
|
|
|
|
|
|
|
|
|
|
$droplets.droplets | select name status memory disk region.name networks.v4
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export def digitalocean_create_server [settings: record, server: record, check: bool, wait: bool]: nothing -> bool {
|
|
|
|
|
# Use DigitalOcean API to create droplet
|
|
|
|
|
let payload = {
|
|
|
|
|
name: $server.hostname
|
|
|
|
|
region: $server.zone
|
|
|
|
|
size: $server.plan
|
|
|
|
|
image: ($server.image? | default "ubuntu-20-04-x64")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if $check {
|
|
|
|
|
print $"Would create DigitalOcean droplet: ($payload)"
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let result = (http post "https://api.digitalocean.com/v2/droplets"
|
|
|
|
|
--headers { Authorization: $"Bearer ($env.DO_TOKEN)" }
|
|
|
|
|
--content-type application/json
|
|
|
|
|
$payload)
|
|
|
|
|
|
|
|
|
|
$result.droplet.id != null
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Step 6: Test Your Provider
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Test provider discovery
|
|
|
|
|
nu -c "use provisioning/core/nulib/lib_provisioning/providers/registry.nu *; init-provider-registry; list-providers"
|
|
|
|
|
|
|
|
|
|
# Test provider loading
|
|
|
|
|
nu -c "use provisioning/core/nulib/lib_provisioning/providers/loader.nu *; load-provider 'your_provider_name'"
|
|
|
|
|
|
|
|
|
|
# Test provider functions
|
|
|
|
|
nu -c "use provisioning/extensions/providers/your_provider_name/provider.nu *; query_servers"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Step 7: Add Provider to Infrastructure
|
|
|
|
|
|
2026-01-08 09:55:37 +00:00
|
|
|
Add to your Nickel configuration:
|
2025-12-11 21:50:42 +00:00
|
|
|
|
2026-01-08 09:55:37 +00:00
|
|
|
```nickel
|
|
|
|
|
# workspace/infra/example/servers.ncl
|
|
|
|
|
let servers = [
|
2025-12-11 21:50:42 +00:00
|
|
|
{
|
2026-01-08 09:55:37 +00:00
|
|
|
hostname = "test-server",
|
|
|
|
|
provider = "your_provider_name",
|
|
|
|
|
zone = "your-region-1",
|
|
|
|
|
plan = "your-instance-type",
|
2025-12-11 21:50:42 +00:00
|
|
|
}
|
2026-01-08 09:55:37 +00:00
|
|
|
] in
|
|
|
|
|
servers
|
2025-12-11 21:50:42 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Provider Templates
|
|
|
|
|
|
|
|
|
|
### Cloud Provider Template
|
|
|
|
|
|
|
|
|
|
For cloud providers (AWS, GCP, Azure, etc.):
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
# Use HTTP calls to cloud APIs
|
|
|
|
|
export def cloud_query_servers [find?: string, cols?: string]: nothing -> list {
|
|
|
|
|
let auth_header = { Authorization: $"Bearer ($env.PROVIDER_TOKEN)" }
|
|
|
|
|
let servers = (http get $"($env.PROVIDER_API_URL)/servers" --headers $auth_header)
|
|
|
|
|
|
|
|
|
|
$servers | select name status region instance_type public_ip
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Container Platform Template
|
|
|
|
|
|
|
|
|
|
For container platforms (Docker, Podman, etc.):
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
# Use CLI commands for container platforms
|
|
|
|
|
export def container_query_servers [find?: string, cols?: string]: nothing -> list {
|
|
|
|
|
let containers = (docker ps --format json | from json)
|
|
|
|
|
|
|
|
|
|
$containers | select Names State Status Image
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Bare Metal Provider Template
|
|
|
|
|
|
|
|
|
|
For bare metal or existing servers:
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
# Use SSH or local commands
|
|
|
|
|
export def baremetal_query_servers [find?: string, cols?: string]: nothing -> list {
|
|
|
|
|
# Read from inventory file or ping servers
|
|
|
|
|
let inventory = (open inventory.yaml | from yaml)
|
|
|
|
|
|
|
|
|
|
$inventory.servers | select hostname ip_address status
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Best Practices
|
|
|
|
|
|
|
|
|
|
### 1. Error Handling
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
export def provider_operation []: nothing -> any {
|
|
|
|
|
try {
|
|
|
|
|
# Your provider operation
|
|
|
|
|
provider_api_call
|
|
|
|
|
} catch {|err|
|
|
|
|
|
log-error $"Provider operation failed: ($err.msg)" "provider"
|
|
|
|
|
if $error_exit { exit 1 }
|
|
|
|
|
null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 2. Authentication
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
# Check for required environment variables
|
|
|
|
|
def check_auth []: nothing -> bool {
|
|
|
|
|
if ($env | get -o PROVIDER_TOKEN) == null {
|
|
|
|
|
log-error "PROVIDER_TOKEN environment variable required" "auth"
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3. Rate Limiting
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
# Add delays for API rate limits
|
|
|
|
|
def api_call_with_retry [url: string]: nothing -> any {
|
|
|
|
|
mut attempts = 0
|
|
|
|
|
mut max_attempts = 3
|
|
|
|
|
|
|
|
|
|
while $attempts < $max_attempts {
|
|
|
|
|
try {
|
|
|
|
|
return (http get $url)
|
|
|
|
|
} catch {
|
|
|
|
|
$attempts += 1
|
|
|
|
|
sleep 1sec
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error make { msg: "API call failed after retries" }
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 4. Provider Capabilities
|
|
|
|
|
|
|
|
|
|
Set capabilities accurately:
|
|
|
|
|
|
|
|
|
|
```nushell
|
|
|
|
|
capabilities: {
|
|
|
|
|
server_management: true # Can create/delete servers
|
|
|
|
|
network_management: true # Can manage networks/VPCs
|
|
|
|
|
storage_management: true # Can manage block storage
|
|
|
|
|
load_balancer: false # No load balancer support
|
|
|
|
|
dns_management: false # No DNS support
|
|
|
|
|
auto_scaling: true # Supports auto-scaling
|
|
|
|
|
spot_instances: false # No spot instance support
|
|
|
|
|
multi_region: true # Supports multiple regions
|
|
|
|
|
containers: false # No container support
|
|
|
|
|
serverless: false # No serverless support
|
|
|
|
|
encryption_at_rest: true # Supports encryption
|
|
|
|
|
compliance_certifications: ["SOC2"] # Available certifications
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Testing Checklist
|
|
|
|
|
|
|
|
|
|
- [ ] Provider discovered by registry
|
|
|
|
|
- [ ] Provider loads without errors
|
|
|
|
|
- [ ] All required interface functions implemented
|
|
|
|
|
- [ ] Provider metadata correct
|
|
|
|
|
- [ ] Authentication working
|
|
|
|
|
- [ ] Can query existing resources
|
|
|
|
|
- [ ] Can create new resources (in test mode)
|
|
|
|
|
- [ ] Error handling working
|
|
|
|
|
- [ ] Compatible with existing infrastructure configs
|
|
|
|
|
|
|
|
|
|
## Common Issues
|
|
|
|
|
|
|
|
|
|
### Provider Not Found
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Check provider directory structure
|
|
|
|
|
ls -la provisioning/extensions/providers/your_provider_name/
|
|
|
|
|
|
|
|
|
|
# Ensure provider.nu exists and has get-provider-metadata function
|
|
|
|
|
grep "get-provider-metadata" provisioning/extensions/providers/your_provider_name/provider.nu
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Interface Validation Failed
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Check which functions are missing
|
|
|
|
|
nu -c "use provisioning/core/nulib/lib_provisioning/providers/interface.nu *; validate-provider-interface 'your_provider_name'"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Authentication Errors
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Check environment variables
|
|
|
|
|
env | grep PROVIDER
|
|
|
|
|
|
|
|
|
|
# Test API access manually
|
|
|
|
|
curl -H "Authorization: Bearer $PROVIDER_TOKEN" https://api.provider.com/test
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Next Steps
|
|
|
|
|
|
|
|
|
|
1. **Documentation**: Add provider-specific documentation to `docs/providers/`
|
|
|
|
|
2. **Examples**: Create example infrastructure using your provider
|
|
|
|
|
3. **Testing**: Add integration tests for your provider
|
|
|
|
|
4. **Optimization**: Implement caching and performance optimizations
|
|
|
|
|
5. **Features**: Add provider-specific advanced features
|
|
|
|
|
|
|
|
|
|
## Getting Help
|
|
|
|
|
|
|
|
|
|
- Check existing providers for implementation patterns
|
|
|
|
|
- Review the [Provider Interface Documentation](PROVIDER_AGNOSTIC_ARCHITECTURE.md#provider-interface)
|
|
|
|
|
- Test with the provider test suite: `./provisioning/tools/test-provider-agnostic.nu`
|
2026-01-08 09:55:37 +00:00
|
|
|
- Run migration checks: `./provisioning/tools/migrate-to-provider-agnostic.nu status`
|