# 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

Add to your Nickel configuration:

```nickel
# workspace/infra/example/servers.ncl
let servers = [
    {
        hostname = "test-server",
        provider = "your_provider_name",
        zone = "your-region-1",
        plan = "your-instance-type",
    }
] in
servers
```

## 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`
- Run migration checks: `./provisioning/tools/migrate-to-provider-agnostic.nu status`
