314 lines
9.6 KiB
Text
314 lines
9.6 KiB
Text
#!/usr/bin/env nu
|
|
# Configuration Deployment Orchestrator
|
|
# Orchestrates Nickel configuration + SOPS secrets workflow
|
|
# Handles: config generation → secrets decryption → deployment
|
|
# Usage: config-deploy <action> [options]
|
|
|
|
use std log
|
|
|
|
def get-vault-url [] {
|
|
$env.VAULT_SERVICE_URL? // "http://localhost:9094"
|
|
}
|
|
|
|
def get-vault-token [] {
|
|
$env.VAULT_SERVICE_TOKEN? // ""
|
|
}
|
|
|
|
def check-nickel [] {
|
|
let result = (^nickel --version | complete)
|
|
if $result.exit_code != 0 {
|
|
error make {
|
|
msg: "Nickel not found or not in PATH"
|
|
label: {
|
|
text: "Install Nickel or add to PATH: https://github.com/tweag/nickel"
|
|
}
|
|
}
|
|
}
|
|
true
|
|
}
|
|
|
|
def check-sops [] {
|
|
let result = (^sops --version | complete)
|
|
if $result.exit_code != 0 {
|
|
error make {
|
|
msg: "SOPS not found or not in PATH"
|
|
label: {
|
|
text: "Install SOPS: https://github.com/mozilla/sops"
|
|
}
|
|
}
|
|
}
|
|
true
|
|
}
|
|
|
|
def validate-environment [environment: string] {
|
|
if $environment not-in ["dev", "staging", "prod"] {
|
|
error make {
|
|
msg: "Invalid environment"
|
|
label: {
|
|
text: "Must be: dev, staging, or prod"
|
|
}
|
|
}
|
|
}
|
|
true
|
|
}
|
|
|
|
def decrypt-secrets [environment: string] {
|
|
let secrets_file = $"provisioning/config/secrets/secrets.($environment).yaml.enc"
|
|
|
|
if not ($secrets_file | path exists) {
|
|
print $"⚠️ Secrets file not found: ($secrets_file)"
|
|
return {}
|
|
}
|
|
|
|
print $"Decrypting secrets for ($environment)..."
|
|
let token = (get-vault-token)
|
|
if ($token | is-empty) {
|
|
error make {
|
|
msg: "VAULT_SERVICE_TOKEN required for secret decryption"
|
|
label: {
|
|
text: "Set environment variable: export VAULT_SERVICE_TOKEN=..."
|
|
}
|
|
}
|
|
}
|
|
|
|
let output_file = $"provisioning/config/secrets/secrets.($environment).yaml"
|
|
let result = (
|
|
nu provisioning/scripts/secrets-decrypt.nu $secrets_file --environment $environment --output $output_file
|
|
)
|
|
|
|
if not ($result.success) {
|
|
error make {
|
|
msg: "Failed to decrypt secrets"
|
|
label: {
|
|
text: $result
|
|
}
|
|
}
|
|
}
|
|
|
|
print "✓ Secrets decrypted successfully"
|
|
$output_file
|
|
}
|
|
|
|
def generate-nickel-config [config_path: string, environment: string, secrets_path: string] {
|
|
print "Generating configuration from Nickel..."
|
|
|
|
let result = (
|
|
^nickel eval -f json provisioning/schemas/examples/deployment-with-secrets.ncl | complete
|
|
)
|
|
|
|
if $result.exit_code != 0 {
|
|
error make {
|
|
msg: "Nickel evaluation failed"
|
|
label: {
|
|
text: $result.stderr
|
|
}
|
|
}
|
|
}
|
|
|
|
print "✓ Configuration generated"
|
|
$result.stdout | from json
|
|
}
|
|
|
|
def validate-config [config: record] {
|
|
print "Validating configuration..."
|
|
|
|
let required_keys = ["database", "redis", "api"]
|
|
let missing = (
|
|
$required_keys
|
|
| where {|key| not ($key in ($config | keys))}
|
|
)
|
|
|
|
if ($missing | length) > 0 {
|
|
let missing_str = ($missing | str join ", ")
|
|
error make {
|
|
msg: "Configuration validation failed"
|
|
label: {
|
|
text: $"Missing required sections: ($missing_str)"
|
|
}
|
|
}
|
|
}
|
|
|
|
print "✓ Configuration validated"
|
|
true
|
|
}
|
|
|
|
def create-deployment-package [config: record, environment: string, output_dir: string] {
|
|
print $"Creating deployment package for ($environment)..."
|
|
|
|
if not ($output_dir | path exists) {
|
|
^mkdir -p $output_dir
|
|
}
|
|
|
|
# Write configuration as JSON
|
|
let config_file = $"($output_dir)/config.json"
|
|
$config | to json | save -f $config_file
|
|
print $"✓ Config: ($config_file)"
|
|
|
|
# Write configuration as YAML (for readability)
|
|
let yaml_file = $"($output_dir)/config.yaml"
|
|
# Note: Would use actual JSON-to-YAML converter in production
|
|
$config | to json | save -f $yaml_file
|
|
print $"✓ Config: ($yaml_file)"
|
|
|
|
# Create deployment manifest
|
|
let manifest = {
|
|
environment: $environment,
|
|
timestamp: (date now | format date "%Y-%m-%dT%H:%M:%SZ"),
|
|
config_version: "1.0",
|
|
components: [
|
|
{ name: "database", host: ($config.database.host // "unknown") },
|
|
{ name: "redis", host: ($config.redis.host // "unknown") },
|
|
{ name: "api", port: ($config.api.port // 0) },
|
|
],
|
|
}
|
|
|
|
let manifest_file = $"($output_dir)/manifest.json"
|
|
$manifest | to json | save -f $manifest_file
|
|
print $"✓ Manifest: ($manifest_file)"
|
|
|
|
$output_dir
|
|
}
|
|
|
|
def main [
|
|
action: string = "help"
|
|
--environment: string = "dev"
|
|
--config-path: string = "provisioning/schemas/examples/deployment-with-secrets.ncl"
|
|
--output-dir: string = "deploy/output"
|
|
--clean
|
|
] {
|
|
match $action {
|
|
"validate-tools" => {
|
|
print "Checking required tools..."
|
|
check-nickel
|
|
print "✓ Nickel: installed"
|
|
check-sops
|
|
print "✓ SOPS: installed"
|
|
print ""
|
|
print "All tools present"
|
|
},
|
|
|
|
"generate" => {
|
|
validate-environment $environment
|
|
|
|
print ""
|
|
print $"====== Generate Configuration for ($environment) ======"
|
|
print ""
|
|
|
|
print "Step 1: Checking tools..."
|
|
check-nickel
|
|
check-sops
|
|
print "✓ Tools validated"
|
|
|
|
print ""
|
|
print "Step 2: Decrypting secrets..."
|
|
let secrets_file = (decrypt-secrets $environment)
|
|
|
|
print ""
|
|
print "Step 3: Generating configuration..."
|
|
let config = (generate-nickel-config $config_path $environment $secrets_file)
|
|
|
|
print ""
|
|
print "Step 4: Validating configuration..."
|
|
validate-config $config
|
|
|
|
print ""
|
|
print "Step 5: Creating deployment package..."
|
|
let output = (create-deployment-package $config $environment $output_dir)
|
|
|
|
print ""
|
|
print $"====== Configuration Ready for Deployment ======"
|
|
print $"Output directory: ($output)"
|
|
print ""
|
|
|
|
if $clean {
|
|
print "Cleaning up decrypted secrets..."
|
|
rm -f $secrets_file
|
|
print "✓ Secrets cleaned up"
|
|
}
|
|
},
|
|
|
|
"validate-nickel" => {
|
|
print "Validating Nickel configuration..."
|
|
|
|
let result = (^nickel check $config_path | complete)
|
|
if $result.exit_code == 0 {
|
|
print "✓ Nickel configuration valid"
|
|
} else {
|
|
error make {
|
|
msg: "Nickel validation failed"
|
|
label: {
|
|
text: $result.stderr
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
"list-environments" => {
|
|
print "Available environments:"
|
|
["dev", "staging", "prod"] | each {|env_name|
|
|
let secrets_file = $"provisioning/config/secrets/secrets.($env_name).yaml.enc"
|
|
let exists = if ($secrets_file | path exists) { "✓" } else { "✗" }
|
|
print $" ($exists) ($env_name) - ($secrets_file)"
|
|
}
|
|
},
|
|
|
|
"status" => {
|
|
print ""
|
|
print "====== Deployment Configuration Status ======"
|
|
print ""
|
|
|
|
print "Tools:"
|
|
(check-nickel) | if $in { print " ✓ Nickel" } else { print " ✗ Nickel" }
|
|
(check-sops) | if $in { print " ✓ SOPS" } else { print " ✗ SOPS" }
|
|
|
|
print ""
|
|
print "Vault Service:"
|
|
print $" URL: (get-vault-url)"
|
|
print $" Token: $(if (get-vault-token | is-empty) { 'not set' } else { 'set' })"
|
|
|
|
print ""
|
|
print "Configuration:"
|
|
print $" Nickel config: ($config_path)"
|
|
print $" Output dir: ($output_dir)"
|
|
|
|
print ""
|
|
print "Secrets:"
|
|
(main "list-environments")
|
|
|
|
print ""
|
|
},
|
|
|
|
"help" => {
|
|
print "Configuration Deployment Orchestrator"
|
|
print ""
|
|
print "Combines Nickel infrastructure-as-code with SOPS secrets"
|
|
print ""
|
|
print "Usage: config-deploy <action> [--environment dev|staging|prod] [--config-path <path>] [--output-dir <dir>]"
|
|
print ""
|
|
print "Actions:"
|
|
print " validate-tools - Check Nickel and SOPS installation"
|
|
print " validate-nickel - Validate Nickel configuration syntax"
|
|
print " list-environments - List available secret environments"
|
|
print " status - Show deployment configuration status"
|
|
print " generate - Full workflow: decrypt → generate → validate → package"
|
|
print " help - Show this help message"
|
|
print ""
|
|
print "Examples:"
|
|
print " config-deploy validate-tools"
|
|
print " config-deploy status"
|
|
print " config-deploy generate --environment prod --clean"
|
|
print " config-deploy generate --environment dev --output-dir ./deploy/dev"
|
|
print ""
|
|
print "Environment Variables:"
|
|
print " VAULT_SERVICE_URL - Vault endpoint (default: http://localhost:9094)"
|
|
print " VAULT_SERVICE_TOKEN - Vault authentication token (required for decrypt)"
|
|
print " PROVISIONING_ENV - Environment (dev, staging, prod)"
|
|
print ""
|
|
},
|
|
|
|
_ => {
|
|
print $"Unknown action: ($action)"
|
|
print "Run 'config-deploy help' for available commands"
|
|
}
|
|
}
|
|
}
|