1174 lines
34 KiB
Plaintext
1174 lines
34 KiB
Plaintext
|
|
# Provider Creation Tool
|
||
|
|
# Quickly create a new provider with proper structure and templates
|
||
|
|
|
||
|
|
use ../core/nulib/lib_provisioning/utils/logging.nu *
|
||
|
|
use ../core/nulib/lib_provisioning/providers/registry.nu *
|
||
|
|
|
||
|
|
# Create a new provider
|
||
|
|
export def main [
|
||
|
|
provider_name: string # Name of the new provider (e.g., "digitalocean")
|
||
|
|
--description: string = "" # Description of the provider
|
||
|
|
--api-base: string = "" # Base API URL for the provider
|
||
|
|
--auth-type: string = "token" # Authentication type (token, key, oauth)
|
||
|
|
--template: string = "cloud" # Template type (cloud, container, baremetal)
|
||
|
|
--dry-run # Show what would be created without executing
|
||
|
|
] {
|
||
|
|
log-section "Creating new provider: $provider_name" "create-provider"
|
||
|
|
|
||
|
|
# Validate provider name
|
||
|
|
if ($provider_name | str contains " ") {
|
||
|
|
log-error "Provider name cannot contain spaces" "validation"
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($provider_name | str length) < 2 {
|
||
|
|
log-error "Provider name must be at least 2 characters" "validation"
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if provider already exists
|
||
|
|
let provider_path = $"../extensions/providers/($provider_name)"
|
||
|
|
if ($provider_path | path exists) {
|
||
|
|
log-error $"Provider ($provider_name) already exists at ($provider_path)" "validation"
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
# Create directory structure
|
||
|
|
let directories = [
|
||
|
|
$"../extensions/providers/($provider_name)"
|
||
|
|
$"../extensions/providers/($provider_name)/nulib"
|
||
|
|
$"../extensions/providers/($provider_name)/nulib/($provider_name)"
|
||
|
|
]
|
||
|
|
|
||
|
|
if $dry_run {
|
||
|
|
log-info "DRY RUN MODE - No files will be created" "create-provider"
|
||
|
|
print "Directories to create:"
|
||
|
|
for dir in $directories {
|
||
|
|
print $" 📁 ($dir)"
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
for dir in $directories {
|
||
|
|
mkdir $dir
|
||
|
|
log-success $"Created directory: ($dir)" "create-provider"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate provider metadata
|
||
|
|
let metadata = generate_provider_metadata $provider_name $description $template
|
||
|
|
|
||
|
|
# Generate provider adapter
|
||
|
|
let adapter_content = generate_provider_adapter $provider_name $template $auth_type
|
||
|
|
|
||
|
|
# Generate provider implementation
|
||
|
|
let implementation_content = generate_provider_implementation $provider_name $template $api_base $auth_type
|
||
|
|
|
||
|
|
# Create files
|
||
|
|
let files = [
|
||
|
|
{
|
||
|
|
path: $"../extensions/providers/($provider_name)/provider.nu"
|
||
|
|
content: $adapter_content
|
||
|
|
description: "Provider adapter implementing standard interface"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
path: $"../extensions/providers/($provider_name)/nulib/($provider_name)/servers.nu"
|
||
|
|
content: $implementation_content
|
||
|
|
description: "Provider-specific implementation functions"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
path: $"../extensions/providers/($provider_name)/README.md"
|
||
|
|
content: (generate_provider_readme $provider_name $description $auth_type)
|
||
|
|
description: "Provider documentation"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
if $dry_run {
|
||
|
|
print "\nFiles to create:"
|
||
|
|
for file in $files {
|
||
|
|
print $" 📄 ($file.path) - ($file.description)"
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
for file in $files {
|
||
|
|
$file.content | save $file.path
|
||
|
|
log-success $"Created file: ($file.path)" "create-provider"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate usage examples
|
||
|
|
let usage_examples = generate_usage_examples $provider_name
|
||
|
|
|
||
|
|
if not $dry_run {
|
||
|
|
$usage_examples | save $"../extensions/providers/($provider_name)/USAGE.md"
|
||
|
|
log-success "Created usage examples" "create-provider"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Show next steps
|
||
|
|
log-section "Next Steps" "create-provider"
|
||
|
|
let next_steps = [
|
||
|
|
$"1. Edit authentication in: ../extensions/providers/($provider_name)/nulib/($provider_name)/servers.nu"
|
||
|
|
$"2. Implement provider-specific API calls"
|
||
|
|
$"3. Test provider: nu -c \"use provisioning/core/nulib/lib_provisioning/providers/loader.nu *; load-provider '($provider_name)'\""
|
||
|
|
$"4. Validate interface: nu -c \"use provisioning/core/nulib/lib_provisioning/providers/interface.nu *; validate-provider-interface '($provider_name)'\""
|
||
|
|
$"5. Add provider to infrastructure configs"
|
||
|
|
$"6. Run tests: ./provisioning/tools/test-provider-agnostic.nu"
|
||
|
|
]
|
||
|
|
|
||
|
|
for step in $next_steps {
|
||
|
|
print $step
|
||
|
|
}
|
||
|
|
|
||
|
|
if not $dry_run {
|
||
|
|
log-success $"Provider ($provider_name) created successfully!" "create-provider"
|
||
|
|
} else {
|
||
|
|
log-info "Use --dry-run=false to create the provider" "create-provider"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate provider metadata
|
||
|
|
def generate_provider_metadata [name: string, description: string, template: string]: nothing -> record {
|
||
|
|
let desc = if ($description | is-empty) {
|
||
|
|
match $template {
|
||
|
|
"cloud" => $"($name | str title-case) cloud provider"
|
||
|
|
"container" => $"($name | str title-case) container platform"
|
||
|
|
"baremetal" => $"($name | str title-case) bare metal provider"
|
||
|
|
_ => $"($name | str title-case) infrastructure provider"
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$description
|
||
|
|
}
|
||
|
|
|
||
|
|
let capabilities = match $template {
|
||
|
|
"cloud" => {
|
||
|
|
server_management: true
|
||
|
|
network_management: true
|
||
|
|
storage_management: true
|
||
|
|
load_balancer: true
|
||
|
|
dns_management: false
|
||
|
|
cdn: false
|
||
|
|
backup_service: true
|
||
|
|
monitoring: false
|
||
|
|
logging: false
|
||
|
|
auto_scaling: true
|
||
|
|
spot_instances: false
|
||
|
|
containers: false
|
||
|
|
serverless: false
|
||
|
|
multi_region: true
|
||
|
|
encryption_at_rest: true
|
||
|
|
encryption_in_transit: true
|
||
|
|
compliance_certifications: []
|
||
|
|
}
|
||
|
|
"container" => {
|
||
|
|
server_management: false
|
||
|
|
network_management: true
|
||
|
|
storage_management: true
|
||
|
|
load_balancer: false
|
||
|
|
dns_management: false
|
||
|
|
cdn: false
|
||
|
|
backup_service: false
|
||
|
|
monitoring: false
|
||
|
|
logging: false
|
||
|
|
auto_scaling: true
|
||
|
|
spot_instances: false
|
||
|
|
containers: true
|
||
|
|
serverless: false
|
||
|
|
multi_region: false
|
||
|
|
encryption_at_rest: false
|
||
|
|
encryption_in_transit: true
|
||
|
|
compliance_certifications: []
|
||
|
|
}
|
||
|
|
"baremetal" => {
|
||
|
|
server_management: true
|
||
|
|
network_management: false
|
||
|
|
storage_management: true
|
||
|
|
load_balancer: false
|
||
|
|
dns_management: false
|
||
|
|
cdn: false
|
||
|
|
backup_service: false
|
||
|
|
monitoring: false
|
||
|
|
logging: false
|
||
|
|
auto_scaling: false
|
||
|
|
spot_instances: false
|
||
|
|
containers: true
|
||
|
|
serverless: false
|
||
|
|
multi_region: false
|
||
|
|
encryption_at_rest: false
|
||
|
|
encryption_in_transit: false
|
||
|
|
compliance_certifications: []
|
||
|
|
}
|
||
|
|
_ => {
|
||
|
|
server_management: true
|
||
|
|
network_management: false
|
||
|
|
storage_management: false
|
||
|
|
load_balancer: false
|
||
|
|
dns_management: false
|
||
|
|
cdn: false
|
||
|
|
backup_service: false
|
||
|
|
monitoring: false
|
||
|
|
logging: false
|
||
|
|
auto_scaling: false
|
||
|
|
spot_instances: false
|
||
|
|
containers: false
|
||
|
|
serverless: false
|
||
|
|
multi_region: false
|
||
|
|
encryption_at_rest: false
|
||
|
|
encryption_in_transit: false
|
||
|
|
compliance_certifications: []
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
name: $name
|
||
|
|
description: $desc
|
||
|
|
capabilities: $capabilities
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate provider adapter content
|
||
|
|
def generate_provider_adapter [name: string, template: string, auth_type: string]: nothing -> string {
|
||
|
|
let name_title = ($name | str title-case)
|
||
|
|
let metadata = generate_provider_metadata $name "" $template
|
||
|
|
|
||
|
|
$"# ($name_title) Provider Adapter
|
||
|
|
# Implements the standard provider interface for ($name_title)
|
||
|
|
|
||
|
|
use nulib/($name)/servers.nu *
|
||
|
|
|
||
|
|
# Provider metadata
|
||
|
|
export def get-provider-metadata []: nothing -> record {
|
||
|
|
{
|
||
|
|
name: \"($name)\"
|
||
|
|
version: \"1.0.0\"
|
||
|
|
description: \"($metadata.description)\"
|
||
|
|
capabilities: ($metadata.capabilities | to nuon)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Server query operations
|
||
|
|
export def query_servers [
|
||
|
|
find?: string
|
||
|
|
cols?: string
|
||
|
|
]: nothing -> list {
|
||
|
|
let str_find = if \\$find != null { \\$find } else { \"\" }
|
||
|
|
let str_cols = if \\$cols != null { \\$cols } else { \"\" }
|
||
|
|
($name)_query_servers \\$str_find \\$str_cols
|
||
|
|
}
|
||
|
|
|
||
|
|
# Server information operations
|
||
|
|
export def server_info [
|
||
|
|
server: record
|
||
|
|
check: bool
|
||
|
|
find?: string
|
||
|
|
cols?: string
|
||
|
|
]: nothing -> record {
|
||
|
|
($name)_server_info \\$server \\$check
|
||
|
|
}
|
||
|
|
|
||
|
|
# Server existence and status operations
|
||
|
|
export def server_exists [
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_server_exists \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def server_is_running [
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_server_is_running \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
# Server lifecycle operations
|
||
|
|
export def check_server_requirements [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
check: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_check_server_requirements \\$settings \\$server \\$check
|
||
|
|
}
|
||
|
|
|
||
|
|
export def create_server [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
check: bool
|
||
|
|
wait: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_create_server \\$settings \\$server \\$check \\$wait
|
||
|
|
}
|
||
|
|
|
||
|
|
export def delete_server [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
keep_storage: bool
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_delete_server \\$settings \\$server \\$keep_storage \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def delete_server_storage [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_delete_server_storage \\$settings \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def post_create_server [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
check: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_post_create_server \\$settings \\$server \\$check
|
||
|
|
}
|
||
|
|
|
||
|
|
export def modify_server [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
new_values: list
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_modify_server \\$settings \\$server \\$new_values \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
# Server state management
|
||
|
|
export def server_state [
|
||
|
|
server: record
|
||
|
|
new_state: string
|
||
|
|
error_exit: bool
|
||
|
|
wait: bool
|
||
|
|
settings: record
|
||
|
|
]: nothing -> bool {
|
||
|
|
($name)_server_state \\$server \\$new_state \\$error_exit \\$wait \\$settings
|
||
|
|
}
|
||
|
|
|
||
|
|
# Network operations
|
||
|
|
export def get_ip [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
ip_type: string
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> string {
|
||
|
|
let use_type = match \\$ip_type {
|
||
|
|
\"\\$network_public_ip\" => \"public\"
|
||
|
|
\"\\$network_private_ip\" => \"private\"
|
||
|
|
_ => \\$ip_type
|
||
|
|
}
|
||
|
|
|
||
|
|
let result = (($name)_get_ip \\$settings \\$server \\$use_type \\$error_exit)
|
||
|
|
\\$result | str trim
|
||
|
|
}
|
||
|
|
|
||
|
|
export def servers_ips [
|
||
|
|
settings: record
|
||
|
|
data: list
|
||
|
|
prov?: string
|
||
|
|
serverpos?: int
|
||
|
|
]: nothing -> list {
|
||
|
|
($name)_servers_ips \\$settings \\$data \\$prov \\$serverpos
|
||
|
|
}
|
||
|
|
|
||
|
|
# Infrastructure operations
|
||
|
|
export def load_infra_servers_info [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> record {
|
||
|
|
($name)_load_infra_servers_info \\$settings \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def load_infra_storages_info [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> record {
|
||
|
|
($name)_load_infra_storages_info \\$settings \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def get_infra_storage [
|
||
|
|
server: record
|
||
|
|
settings: record
|
||
|
|
cloud_data: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> list {
|
||
|
|
($name)_get_infra_storage \\$server \\$settings \\$cloud_data \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def get_infra_item [
|
||
|
|
server: record
|
||
|
|
settings: record
|
||
|
|
cloud_data: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> record {
|
||
|
|
($name)_get_infra_item \\$server \\$settings \\$cloud_data \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def get_infra_price [
|
||
|
|
server: record
|
||
|
|
data: record
|
||
|
|
key: string
|
||
|
|
error_exit: bool
|
||
|
|
price_col?: string
|
||
|
|
]: nothing -> float {
|
||
|
|
($name)_get_infra_price \\$server \\$data \\$key \\$error_exit \\$price_col
|
||
|
|
}
|
||
|
|
|
||
|
|
# Cache operations
|
||
|
|
export def start_cache_info [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
]: nothing -> nothing {
|
||
|
|
($name)_start_cache_info \\$settings \\$server
|
||
|
|
}
|
||
|
|
|
||
|
|
export def create_cache [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> nothing {
|
||
|
|
($name)_create_cache \\$settings \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def read_cache [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> nothing {
|
||
|
|
($name)_read_cache \\$settings \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def clean_cache [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> nothing {
|
||
|
|
($name)_clean_cache \\$settings \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ip_from_cache [
|
||
|
|
settings: record
|
||
|
|
server: record
|
||
|
|
error_exit: bool
|
||
|
|
]: nothing -> string {
|
||
|
|
($name)_ip_from_cache \\$settings \\$server \\$error_exit
|
||
|
|
}
|
||
|
|
|
||
|
|
# Provider metadata operations
|
||
|
|
export def on_prov_server [
|
||
|
|
server: record
|
||
|
|
]: nothing -> string {
|
||
|
|
($name)_on_prov_server \\$server
|
||
|
|
}
|
||
|
|
|
||
|
|
# Provider validation
|
||
|
|
export def validate_provider []: nothing -> record {
|
||
|
|
{
|
||
|
|
provider: \"($name)\"
|
||
|
|
valid: true
|
||
|
|
interface_version: \"1.0.0\"
|
||
|
|
capabilities: (get-provider-metadata).capabilities
|
||
|
|
last_validated: (date now)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate provider implementation content
|
||
|
|
def generate_provider_implementation [name: string, template: string, api_base: string, auth_type: string]: nothing -> string {
|
||
|
|
let name_title = ($name | str title-case)
|
||
|
|
let auth_var = match $auth_type {
|
||
|
|
"token" => $"($name | str upcase)_TOKEN"
|
||
|
|
"key" => $"($name | str upcase)_API_KEY"
|
||
|
|
"oauth" => $"($name | str upcase)_CLIENT_ID"
|
||
|
|
_ => $"($name | str upcase)_TOKEN"
|
||
|
|
}
|
||
|
|
|
||
|
|
let api_url = if ($api_base | is-empty) {
|
||
|
|
$"https://api.($name).com"
|
||
|
|
} else {
|
||
|
|
$api_base
|
||
|
|
}
|
||
|
|
|
||
|
|
let implementation = match $template {
|
||
|
|
"cloud" => generate_cloud_implementation $name $auth_var $api_url
|
||
|
|
"container" => generate_container_implementation $name
|
||
|
|
"baremetal" => generate_baremetal_implementation $name
|
||
|
|
_ => generate_generic_implementation $name $auth_var $api_url
|
||
|
|
}
|
||
|
|
|
||
|
|
$"# ($name_title) Provider Implementation
|
||
|
|
# Provider-specific functions for ($name_title)
|
||
|
|
|
||
|
|
use ../../core/nulib/lib_provisioning/utils/logging.nu *
|
||
|
|
|
||
|
|
# Authentication check
|
||
|
|
def check_auth []: nothing -> bool {
|
||
|
|
if (\\$env | get -o ($auth_var)) == null {
|
||
|
|
log-error \"($auth_var) environment variable required\" \"auth\"
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
($implementation)
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate cloud provider implementation
|
||
|
|
def generate_cloud_implementation [name: string, auth_var: string, api_url: string]: nothing -> string {
|
||
|
|
$"# Cloud provider implementation for ($name)
|
||
|
|
|
||
|
|
export def ($name)_query_servers [find?: string, cols?: string]: nothing -> list {
|
||
|
|
if not (check_auth) { return [] }
|
||
|
|
|
||
|
|
let auth_header = { Authorization: \\$\"Bearer (\\$env.($auth_var))\" }
|
||
|
|
|
||
|
|
try {
|
||
|
|
let servers = (http get \\$\"($api_url)/servers\" --headers \\$auth_header)
|
||
|
|
|
||
|
|
# Filter results if find parameter provided
|
||
|
|
let filtered = if (\\$find != null) and (\\$find != \"\") {
|
||
|
|
\\$servers | where {|server| \\$server.name =~ \\$find}
|
||
|
|
} else {
|
||
|
|
\\$servers
|
||
|
|
}
|
||
|
|
|
||
|
|
# Select columns if specified
|
||
|
|
if (\\$cols != null) and (\\$cols != \"\") {
|
||
|
|
let field_list = (\\$cols | split row \",\")
|
||
|
|
\\$filtered | select ...(\\$field_list)
|
||
|
|
} else {
|
||
|
|
\\$filtered | select name status region instance_type public_ip
|
||
|
|
}
|
||
|
|
} catch {|err|
|
||
|
|
log-error \\$\"Failed to query servers: (\\$err.msg)\" \"($name)\"
|
||
|
|
[]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_create_server [settings: record, server: record, check: bool, wait: bool]: nothing -> bool {
|
||
|
|
if not (check_auth) { return false }
|
||
|
|
|
||
|
|
let payload = {
|
||
|
|
name: \\$server.hostname
|
||
|
|
region: (\\$server.zone? | default \"us-east-1\")
|
||
|
|
instance_type: (\\$server.plan? | default \"t3.micro\")
|
||
|
|
image: (\\$server.image? | default \"ubuntu-20.04\")
|
||
|
|
}
|
||
|
|
|
||
|
|
if \\$check {
|
||
|
|
log-info \\$\"Would create ($name) server: (\\$payload)\" \"($name)\"
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
let auth_header = { Authorization: \\$\"Bearer (\\$env.($auth_var))\" }
|
||
|
|
let result = (http post \\$\"($api_url)/servers\"
|
||
|
|
--headers \\$auth_header
|
||
|
|
--content-type application/json
|
||
|
|
\\$payload)
|
||
|
|
|
||
|
|
if \\$wait {
|
||
|
|
# Poll for server to be ready
|
||
|
|
mut attempts = 0
|
||
|
|
while \\$attempts < 60 { # 5 minutes max
|
||
|
|
let status = (($name)_server_exists \\$server false)
|
||
|
|
if \\$status {
|
||
|
|
log-success \\$\"Server (\\$server.hostname) is ready\" \"($name)\"
|
||
|
|
break
|
||
|
|
}
|
||
|
|
sleep 5sec
|
||
|
|
\\$attempts += 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
log-success \\$\"Created server: (\\$server.hostname)\" \"($name)\"
|
||
|
|
true
|
||
|
|
} catch {|err|
|
||
|
|
log-error \\$\"Failed to create server: (\\$err.msg)\" \"($name)\"
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_server_exists [server: record, error_exit: bool]: nothing -> bool {
|
||
|
|
if not (check_auth) { return false }
|
||
|
|
|
||
|
|
try {
|
||
|
|
let auth_header = { Authorization: \\$\"Bearer (\\$env.($auth_var))\" }
|
||
|
|
let servers = (http get \\$\"($api_url)/servers\" --headers \\$auth_header)
|
||
|
|
let found = (\\$servers | where name == \\$server.hostname)
|
||
|
|
(\\$found | length) > 0
|
||
|
|
} catch {|err|
|
||
|
|
if \\$error_exit {
|
||
|
|
log-error \\$\"Error checking server existence: (\\$err.msg)\" \"($name)\"
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_get_ip [settings: record, server: record, ip_type: string, error_exit: bool]: nothing -> string {
|
||
|
|
if not (check_auth) { return \"\" }
|
||
|
|
|
||
|
|
try {
|
||
|
|
let auth_header = { Authorization: \\$\"Bearer (\\$env.($auth_var))\" }
|
||
|
|
let servers = (http get \\$\"($api_url)/servers\" --headers \\$auth_header)
|
||
|
|
let found = (\\$servers | where name == \\$server.hostname | get 0)
|
||
|
|
|
||
|
|
match \\$ip_type {
|
||
|
|
\"public\" => (\\$found.public_ip? | default \"\")
|
||
|
|
\"private\" => (\\$found.private_ip? | default \"\")
|
||
|
|
_ => (\\$found.public_ip? | default \"\")
|
||
|
|
}
|
||
|
|
} catch {|err|
|
||
|
|
if \\$error_exit {
|
||
|
|
log-error \\$\"Error getting IP: (\\$err.msg)\" \"($name)\"
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
\"\"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_delete_server [settings: record, server: record, keep_storage: bool, error_exit: bool]: nothing -> bool {
|
||
|
|
if not (check_auth) { return false }
|
||
|
|
|
||
|
|
try {
|
||
|
|
let auth_header = { Authorization: \\$\"Bearer (\\$env.($auth_var))\" }
|
||
|
|
http delete \\$\"($api_url)/servers/(\\$server.hostname)\" --headers \\$auth_header
|
||
|
|
|
||
|
|
log-success \\$\"Deleted server: (\\$server.hostname)\" \"($name)\"
|
||
|
|
true
|
||
|
|
} catch {|err|
|
||
|
|
if \\$error_exit {
|
||
|
|
log-error \\$\"Error deleting server: (\\$err.msg)\" \"($name)\"
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Implement other required functions...
|
||
|
|
export def ($name)_server_info [server: record, check: bool]: nothing -> record {
|
||
|
|
{ hostname: \\$server.hostname, provider: \"($name)\", status: \"unknown\" }
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_server_is_running [server: record, error_exit: bool]: nothing -> bool {
|
||
|
|
# Implementation depends on your provider's API
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_check_server_requirements [settings: record, server: record, check: bool]: nothing -> bool {
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_delete_server_storage [settings: record, server: record, error_exit: bool]: nothing -> bool {
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_post_create_server [settings: record, server: record, check: bool]: nothing -> bool {
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_modify_server [settings: record, server: record, new_values: list, error_exit: bool]: nothing -> bool {
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_server_state [server: record, new_state: string, error_exit: bool, wait: bool, settings: record]: nothing -> bool {
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_servers_ips [settings: record, data: list, prov?: string, serverpos?: int]: nothing -> list {
|
||
|
|
[]
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_load_infra_servers_info [settings: record, server: record, error_exit: bool]: nothing -> record {
|
||
|
|
{ provider: \"($name)\", server: \\$server.hostname }
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_load_infra_storages_info [settings: record, server: record, error_exit: bool]: nothing -> record {
|
||
|
|
{ provider: \"($name)\", storage: \"managed\" }
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_get_infra_storage [server: record, settings: record, cloud_data: record, error_exit: bool]: nothing -> list {
|
||
|
|
[]
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_get_infra_item [server: record, settings: record, cloud_data: record, error_exit: bool]: nothing -> record {
|
||
|
|
{ provider: \"($name)\", hostname: \\$server.hostname }
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_get_infra_price [server: record, data: record, key: string, error_exit: bool, price_col?: string]: nothing -> float {
|
||
|
|
0.0
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_start_cache_info [settings: record, server: record]: nothing -> nothing {
|
||
|
|
# No-op
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_create_cache [settings: record, server: record, error_exit: bool]: nothing -> nothing {
|
||
|
|
# No-op
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_read_cache [settings: record, server: record, error_exit: bool]: nothing -> nothing {
|
||
|
|
# No-op
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_clean_cache [settings: record, server: record, error_exit: bool]: nothing -> nothing {
|
||
|
|
# No-op
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_ip_from_cache [settings: record, server: record, error_exit: bool]: nothing -> string {
|
||
|
|
\"\"
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_on_prov_server [server: record]: nothing -> string {
|
||
|
|
\\$\"Using ($name) provider for (\\$server.hostname)\"
|
||
|
|
}
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate container provider implementation
|
||
|
|
def generate_container_implementation [name: string]: nothing -> string {
|
||
|
|
$"# Container provider implementation for ($name)
|
||
|
|
|
||
|
|
export def ($name)_query_servers [find?: string, cols?: string]: nothing -> list {
|
||
|
|
try {
|
||
|
|
let containers = (docker ps --format json | from json)
|
||
|
|
|
||
|
|
let filtered = if (\\$find != null) and (\\$find != \"\") {
|
||
|
|
\\$containers | where {|container| \\$container.Names =~ \\$find}
|
||
|
|
} else {
|
||
|
|
\\$containers
|
||
|
|
}
|
||
|
|
|
||
|
|
if (\\$cols != null) and (\\$cols != \"\") {
|
||
|
|
let field_list = (\\$cols | split row \",\")
|
||
|
|
\\$filtered | select ...(\\$field_list)
|
||
|
|
} else {
|
||
|
|
\\$filtered | select Names State Status Image
|
||
|
|
}
|
||
|
|
} catch {|err|
|
||
|
|
log-error \\$\"Failed to query containers: (\\$err.msg)\" \"($name)\"
|
||
|
|
[]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_create_server [settings: record, server: record, check: bool, wait: bool]: nothing -> bool {
|
||
|
|
let image = (\\$server.image? | default \"ubuntu:20.04\")
|
||
|
|
let command = [\"docker\", \"run\", \"-d\", \"--name\", \\$server.hostname, \\$image]
|
||
|
|
|
||
|
|
if \\$check {
|
||
|
|
log-info \\$\"Would create container: (\\$command | str join ' ')\" \"($name)\"
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
let result = (run-external \"docker\" \"run\" \"-d\" \"--name\" \\$server.hostname \\$image)
|
||
|
|
log-success \\$\"Created container: (\\$server.hostname)\" \"($name)\"
|
||
|
|
true
|
||
|
|
} catch {|err|
|
||
|
|
log-error \\$\"Failed to create container: (\\$err.msg)\" \"($name)\"
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Implement other required functions for container platform...
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate baremetal provider implementation
|
||
|
|
def generate_baremetal_implementation [name: string]: nothing -> string {
|
||
|
|
$"# Bare metal provider implementation for ($name)
|
||
|
|
|
||
|
|
export def ($name)_query_servers [find?: string, cols?: string]: nothing -> list {
|
||
|
|
try {
|
||
|
|
# Read from inventory file or configuration
|
||
|
|
let inventory_file = \\$\"inventory.(\\$name).yaml\"
|
||
|
|
if not (\\$inventory_file | path exists) {
|
||
|
|
log-warning \\$\"Inventory file not found: (\\$inventory_file)\" \"($name)\"
|
||
|
|
return []
|
||
|
|
}
|
||
|
|
|
||
|
|
let inventory = (open \\$inventory_file | from yaml)
|
||
|
|
let servers = \\$inventory.servers
|
||
|
|
|
||
|
|
let filtered = if (\\$find != null) and (\\$find != \"\") {
|
||
|
|
\\$servers | where {|server| \\$server.hostname =~ \\$find}
|
||
|
|
} else {
|
||
|
|
\\$servers
|
||
|
|
}
|
||
|
|
|
||
|
|
if (\\$cols != null) and (\\$cols != \"\") {
|
||
|
|
let field_list = (\\$cols | split row \",\")
|
||
|
|
\\$filtered | select ...(\\$field_list)
|
||
|
|
} else {
|
||
|
|
\\$filtered | select hostname ip_address status
|
||
|
|
}
|
||
|
|
} catch {|err|
|
||
|
|
log-error \\$\"Failed to query servers: (\\$err.msg)\" \"($name)\"
|
||
|
|
[]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_create_server [settings: record, server: record, check: bool, wait: bool]: nothing -> bool {
|
||
|
|
# For bare metal, \"creation\" means ensuring server is accessible
|
||
|
|
if \\$check {
|
||
|
|
log-info \\$\"Would validate bare metal server: (\\$server.hostname)\" \"($name)\"
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
# Test SSH connectivity
|
||
|
|
let test_result = (ssh -o ConnectTimeout=5 \\$server.hostname \"echo 'connection test'\")
|
||
|
|
if (\\$test_result | str contains \"connection test\") {
|
||
|
|
log-success \\$\"Bare metal server (\\$server.hostname) is accessible\" \"($name)\"
|
||
|
|
true
|
||
|
|
} else {
|
||
|
|
log-error \\$\"Cannot connect to bare metal server (\\$server.hostname)\" \"($name)\"
|
||
|
|
false
|
||
|
|
}
|
||
|
|
} catch {|err|
|
||
|
|
log-error \\$\"SSH connection failed: (\\$err.msg)\" \"($name)\"
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Implement other required functions for bare metal...
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate generic provider implementation
|
||
|
|
def generate_generic_implementation [name: string, auth_var: string, api_url: string]: nothing -> string {
|
||
|
|
$"# Generic provider implementation for ($name)
|
||
|
|
|
||
|
|
export def ($name)_query_servers [find?: string, cols?: string]: nothing -> list {
|
||
|
|
# TODO: Implement your provider's server listing logic
|
||
|
|
log-warning \"($name)_query_servers not yet implemented\" \"($name)\"
|
||
|
|
[]
|
||
|
|
}
|
||
|
|
|
||
|
|
export def ($name)_create_server [settings: record, server: record, check: bool, wait: bool]: nothing -> bool {
|
||
|
|
# TODO: Implement your provider's server creation logic
|
||
|
|
if \\$check {
|
||
|
|
log-info \\$\"Would create server: (\\$server.hostname)\" \"($name)\"
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
log-warning \"($name)_create_server not yet implemented\" \"($name)\"
|
||
|
|
false
|
||
|
|
}
|
||
|
|
|
||
|
|
# TODO: Implement all other required functions...
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate provider README
|
||
|
|
def generate_provider_readme [name: string, description: string, auth_type: string]: nothing -> string {
|
||
|
|
let name_title = ($name | str title-case)
|
||
|
|
let auth_var = match $auth_type {
|
||
|
|
"token" => $"($name | str upcase)_TOKEN"
|
||
|
|
"key" => $"($name | str upcase)_API_KEY"
|
||
|
|
"oauth" => $"($name | str upcase)_CLIENT_ID"
|
||
|
|
_ => $"($name | str upcase)_TOKEN"
|
||
|
|
}
|
||
|
|
|
||
|
|
$"# ($name_title) Provider
|
||
|
|
|
||
|
|
($description)
|
||
|
|
|
||
|
|
## Authentication
|
||
|
|
|
||
|
|
Set the following environment variable:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
export ($auth_var)=\"your-($auth_type)-here\"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Configuration
|
||
|
|
|
||
|
|
Add servers using the ($name) provider in your KCL configuration:
|
||
|
|
|
||
|
|
```kcl
|
||
|
|
servers = [
|
||
|
|
{
|
||
|
|
hostname = \"my-server\"
|
||
|
|
provider = \"($name)\"
|
||
|
|
zone = \"region-1\"
|
||
|
|
plan = \"small\"
|
||
|
|
image = \"ubuntu-20.04\"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
## Features
|
||
|
|
|
||
|
|
- ✅ Server management
|
||
|
|
- ✅ Basic operations
|
||
|
|
- ⚠️ Advanced features (in development)
|
||
|
|
|
||
|
|
## Usage
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Query servers
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/provider.nu *; query_servers\"
|
||
|
|
|
||
|
|
# Test provider
|
||
|
|
./provisioning/tools/test-provider-agnostic.nu
|
||
|
|
```
|
||
|
|
|
||
|
|
## Development
|
||
|
|
|
||
|
|
This provider was generated using the provider creation tool. See `USAGE.md` for implementation examples.
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
🚧 **Work in Progress** - This provider needs implementation of core functions.
|
||
|
|
|
||
|
|
## Support
|
||
|
|
|
||
|
|
- Check the [Provider Development Guide](../../../docs/development/QUICK_PROVIDER_GUIDE.md)
|
||
|
|
- Review existing providers for implementation patterns
|
||
|
|
- Run tests with: `./provisioning/tools/test-provider-agnostic.nu`
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate usage examples
|
||
|
|
def generate_usage_examples [name: string]: nothing -> string {
|
||
|
|
let name_title = ($name | str title-case)
|
||
|
|
|
||
|
|
$"# ($name_title) Provider Usage Examples
|
||
|
|
|
||
|
|
## Basic Server Operations
|
||
|
|
|
||
|
|
### Query Servers
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# List all servers
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/provider.nu *; query_servers\"
|
||
|
|
|
||
|
|
# Find servers by name
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/provider.nu *; query_servers 'web'\"
|
||
|
|
|
||
|
|
# Select specific columns
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/provider.nu *; query_servers '' 'name,status,region'\"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Server Information
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Get detailed server info
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/provider.nu *; server_info {hostname: 'my-server'} false\"
|
||
|
|
|
||
|
|
# Check if server exists
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/provider.nu *; server_exists {hostname: 'my-server'} false\"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Infrastructure Configuration
|
||
|
|
|
||
|
|
### KCL Configuration Example
|
||
|
|
|
||
|
|
```kcl
|
||
|
|
# workspace/infra/example/servers.k
|
||
|
|
servers = [
|
||
|
|
{
|
||
|
|
hostname = \"web-01\"
|
||
|
|
provider = \"($name)\"
|
||
|
|
zone = \"us-east-1\"
|
||
|
|
plan = \"t3.micro\"
|
||
|
|
image = \"ubuntu-20.04\"
|
||
|
|
network_public_ip = \"auto\"
|
||
|
|
network_private_ip = \"auto\"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
hostname = \"db-01\"
|
||
|
|
provider = \"($name)\"
|
||
|
|
zone = \"us-east-1\"
|
||
|
|
plan = \"t3.small\"
|
||
|
|
image = \"ubuntu-20.04\"
|
||
|
|
network_public_ip = \"auto\"
|
||
|
|
network_private_ip = \"auto\"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
### Multi-Provider Configuration
|
||
|
|
|
||
|
|
```kcl
|
||
|
|
# Mix ($name) with other providers
|
||
|
|
servers = [
|
||
|
|
{
|
||
|
|
hostname = \"compute-01\"
|
||
|
|
provider = \"($name)\"
|
||
|
|
zone = \"us-east-1\"
|
||
|
|
plan = \"large\"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
hostname = \"backup-01\"
|
||
|
|
provider = \"upcloud\"
|
||
|
|
zone = \"us-nyc1\"
|
||
|
|
plan = \"1xCPU-2GB\"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
## Provider Testing
|
||
|
|
|
||
|
|
### Test Provider Loading
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Test provider registration
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/registry.nu *; init-provider-registry; is-provider-available '($name)'\"
|
||
|
|
|
||
|
|
# Test provider loading
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/loader.nu *; load-provider '($name)'\"
|
||
|
|
|
||
|
|
# Validate interface compliance
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/interface.nu *; validate-provider-interface '($name)'\"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Run Full Test Suite
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Run all provider tests
|
||
|
|
./provisioning/tools/test-provider-agnostic.nu run-all-tests
|
||
|
|
|
||
|
|
# Test specific provider
|
||
|
|
./provisioning/tools/test-provider-agnostic.nu test-provider-loading
|
||
|
|
```
|
||
|
|
|
||
|
|
## Integration with Provisioning System
|
||
|
|
|
||
|
|
### Using with Core CLI
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create servers using the ($name) provider
|
||
|
|
./provisioning/core/cli/provisioning server create --infra example --check
|
||
|
|
|
||
|
|
# List servers from ($name) provider
|
||
|
|
./provisioning/core/cli/provisioning server list --provider ($name)
|
||
|
|
|
||
|
|
# Get server info
|
||
|
|
./provisioning/core/cli/provisioning server info web-01
|
||
|
|
```
|
||
|
|
|
||
|
|
### Provider-Agnostic Operations
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Query servers across all providers
|
||
|
|
nu -c \"use provisioning/extensions/providers/prov_lib/middleware_provider_agnostic.nu *; mw_query_servers {data: {servers: []}}\"
|
||
|
|
|
||
|
|
# Get provider status
|
||
|
|
nu -c \"use provisioning/extensions/providers/prov_lib/middleware_provider_agnostic.nu *; mw_provider_status\"
|
||
|
|
|
||
|
|
# Multi-provider deployment
|
||
|
|
nu -c \"use provisioning/extensions/providers/prov_lib/middleware_provider_agnostic.nu *; mw_deploy_multi_provider_infra \\$settings \\$plan\"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Debugging
|
||
|
|
|
||
|
|
### Check Provider Status
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# List all providers
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/registry.nu *; list-providers\"
|
||
|
|
|
||
|
|
# Get provider capabilities
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/registry.nu *; get-provider-capabilities-for '($name)'\"
|
||
|
|
|
||
|
|
# Check provider health
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/loader.nu *; check-provider-health '($name)'\"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Common Issues
|
||
|
|
|
||
|
|
1. **Provider not found**
|
||
|
|
```bash
|
||
|
|
# Refresh provider registry
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/registry.nu *; init-provider-registry\"
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Authentication failed**
|
||
|
|
```bash
|
||
|
|
# Check environment variables
|
||
|
|
env | grep ($name | str upcase)
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Interface validation failed**
|
||
|
|
```bash
|
||
|
|
# Check missing functions
|
||
|
|
nu -c \"use provisioning/core/nulib/lib_provisioning/providers/interface.nu *; validate-provider-interface '($name)'\"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Advanced Usage
|
||
|
|
|
||
|
|
### Custom Provider Functions
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Call provider-specific functions directly
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/nulib/($name)/servers.nu *; ($name)_query_servers\"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Provider Capabilities
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Check what the provider supports
|
||
|
|
nu -c \"use provisioning/extensions/providers/($name)/provider.nu *; get-provider-metadata\"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Next Steps
|
||
|
|
|
||
|
|
1. Implement missing provider functions in `nulib/($name)/servers.nu`
|
||
|
|
2. Add authentication and API integration
|
||
|
|
3. Test with real infrastructure
|
||
|
|
4. Add provider-specific features and optimizations
|
||
|
|
5. Contribute improvements back to the project
|
||
|
|
"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Show help
|
||
|
|
export def help []: nothing -> nothing {
|
||
|
|
let help_text = $"
|
||
|
|
Provider Creation Tool
|
||
|
|
|
||
|
|
USAGE:
|
||
|
|
./provisioning/tools/create-provider.nu <provider_name> [options]
|
||
|
|
|
||
|
|
ARGUMENTS:
|
||
|
|
provider_name Name of the new provider (e.g., 'digitalocean', 'linode')
|
||
|
|
|
||
|
|
OPTIONS:
|
||
|
|
--description Description of the provider (optional)
|
||
|
|
--api-base Base API URL for the provider (optional)
|
||
|
|
--auth-type Authentication type: token, key, oauth (default: token)
|
||
|
|
--template Template type: cloud, container, baremetal (default: cloud)
|
||
|
|
--dry-run Show what would be created without executing
|
||
|
|
|
||
|
|
EXAMPLES:
|
||
|
|
# Create a cloud provider with token auth
|
||
|
|
./provisioning/tools/create-provider.nu digitalocean --description \"DigitalOcean cloud provider\"
|
||
|
|
|
||
|
|
# Create a container platform provider
|
||
|
|
./provisioning/tools/create-provider.nu podman --template container
|
||
|
|
|
||
|
|
# Create a bare metal provider
|
||
|
|
./provisioning/tools/create-provider.nu datacenter --template baremetal
|
||
|
|
|
||
|
|
# Preview what would be created
|
||
|
|
./provisioning/tools/create-provider.nu newprovider --dry-run
|
||
|
|
|
||
|
|
TEMPLATES:
|
||
|
|
cloud - Full cloud provider with API integration (AWS, GCP, Azure style)
|
||
|
|
container - Container platform provider (Docker, Podman style)
|
||
|
|
baremetal - Bare metal or existing server provider (Local, SSH style)
|
||
|
|
|
||
|
|
NEXT STEPS:
|
||
|
|
1. Run the tool to create provider structure
|
||
|
|
2. Implement authentication in the generated files
|
||
|
|
3. Add provider-specific API calls
|
||
|
|
4. Test with: ./provisioning/tools/test-provider-agnostic.nu
|
||
|
|
5. Validate interface compliance
|
||
|
|
6. Add to infrastructure configurations
|
||
|
|
|
||
|
|
For more information, see docs/development/QUICK_PROVIDER_GUIDE.md
|
||
|
|
"
|
||
|
|
|
||
|
|
print $help_text
|
||
|
|
}
|