Jesús Pérez a395bd972f
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
mdBook Build & Deploy / Build mdBook (push) Has been cancelled
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
mdBook Build & Deploy / Documentation Quality Check (push) Has been cancelled
mdBook Build & Deploy / Deploy to GitHub Pages (push) Has been cancelled
mdBook Build & Deploy / Notification (push) Has been cancelled
chore: add cd/ci ops
2026-01-12 03:36:55 +00:00

406 lines
12 KiB
Plaintext
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env nu
# VAPORA Deployment Pipeline Orchestration
# Handles configuration generation, validation, and deployment to all platforms
# Version: 1.0.0
def main [
--mode: string = "multiuser"
--output-dir: string = "dist"
--target: string = "docker"
--validate-only: bool = false
--dry-run: bool = false
] {
let timestamp = (date now | format date '%Y%m%d-%H%M%S')
let log_file = ($output_dir | path join $"deploy-($timestamp).log")
# Create output directory
do {
mkdir ($output_dir | path expand)
} | complete | if $in.exit_code != 0 {
error make {msg: $"Failed to create output directory: ($in.stderr)"}
}
print $"🚀 VAPORA Deployment Pipeline - Mode: ($mode), Target: ($target)"
print $"📝 Logging to: ($log_file)"
print ""
# Step 1: Generate configuration
print "Step 1⃣ - Generating configuration from Nickel..."
let config_json = (generate-config $mode $output_dir)
if $config_json == null {
error make {msg: "Configuration generation failed"}
}
print "✓ Configuration generated"
print ""
# Step 2: Validate configuration
print "Step 2⃣ - Validating configuration..."
let validation = (validate-config $config_json)
if not $validation.valid {
error make {msg: $"Validation failed: ($validation.errors | str join ', ')"}
}
print "✓ Configuration valid"
print ""
# Step 3: Render templates based on target
print "Step 3⃣ - Rendering output templates..."
let rendered = (render-templates $config_json $mode $output_dir $target)
if not $rendered {
error make {msg: "Template rendering failed"}
}
print "✓ Templates rendered"
print ""
# Step 4: Validate rendered outputs
print "Step 4⃣ - Validating rendered outputs..."
let output_validation = (validate-outputs $output_dir $target)
if not $output_validation.valid {
error make {msg: $"Output validation failed: ($output_validation.errors | str join ', ')"}
}
print "✓ Outputs validated"
print ""
if $validate_only {
print "✅ Validation complete (--validate-only specified)"
return
}
# Step 5: Deploy based on target
print "Step 5⃣ - Deploying..."
match $target {
"docker" => {
print "📦 Deploying to Docker Compose..."
deploy-docker $mode $output_dir $dry_run
}
"kubernetes" => {
print "☸️ Deploying to Kubernetes..."
deploy-kubernetes $mode $output_dir $dry_run
}
"both" => {
print "📦 Deploying to Docker Compose..."
deploy-docker $mode $output_dir $dry_run
print "☸️ Deploying to Kubernetes..."
deploy-kubernetes $mode $output_dir $dry_run
}
_ => {
error make {msg: $"Unknown target: ($target). Use 'docker', 'kubernetes', or 'both'"}
}
}
print ""
print "✅ Deployment complete!"
print $"Outputs saved to: ($output_dir)"
}
def generate-config [mode: string, output_dir: string] {
let config_file = $"schemas/platform/configs/vapora-($mode).ncl"
if not ($config_file | path exists) {
error make {msg: $"Config not found: ($config_file)"}
}
let output_path = ($output_dir | path join $"config-($mode).json")
let result = do {
nickel export $config_file
} | complete
if $result.exit_code != 0 {
error make {msg: $"Nickel export failed: ($result.stderr)"}
}
let json_output = $result.stdout
do {
$json_output | save -f $output_path
} | complete | if $in.exit_code != 0 {
error make {msg: $"Failed to save config: ($in.stderr)"}
}
$output_path
}
def validate-config [config_path: string] {
let config = do {
open $config_path
} | complete
if $config.exit_code != 0 {
return {
valid: false
errors: [
$"Failed to parse config: ($config.stderr)"
]
}
}
let parsed = ($config.stdout | from json)
let errors = []
# Validate required fields
let required_fields = [
"deployment_mode"
"backend"
"agents"
"llm_router"
"database"
"frontend"
]
let missing_fields = $required_fields | where { |field|
not ($parsed | has $field)
}
if ($missing_fields | length) > 0 {
return {
valid: false
errors: [
$"Missing required fields: ($missing_fields | str join ', ')"
]
}
}
# Validate deployment mode
let valid_modes = ["solo", "multiuser", "enterprise"]
if not ($valid_modes | any { |mode| $mode == $parsed.deployment_mode }) {
return {
valid: false
errors: [
$"Invalid deployment_mode: ($parsed.deployment_mode)"
]
}
}
{valid: true, errors: []}
}
def render-templates [config_path: string, mode: string, output_dir: string, target: string] {
let config = (open $config_path)
# Render TOML
print " → Rendering TOML configuration..."
let toml_result = do {
jinja2 schemas/platform/templates/configs/vapora.toml.j2 $config_path
} | complete
if $toml_result.exit_code != 0 {
print $" ✗ TOML rendering failed: ($toml_result.stderr)"
return false
}
do {
$toml_result.stdout | save -f ($output_dir | path join $"vapora-($mode).toml")
} | complete | if $in.exit_code != 0 {
return false
}
print " ✓ TOML"
# Render YAML
print " → Rendering YAML configuration..."
let yaml_result = do {
jinja2 schemas/platform/templates/configs/vapora.yaml.j2 $config_path
} | complete
if $yaml_result.exit_code != 0 {
print $" ✗ YAML rendering failed: ($yaml_result.stderr)"
return false
}
do {
$yaml_result.stdout | save -f ($output_dir | path join $"vapora-($mode).yaml")
} | complete | if $in.exit_code != 0 {
return false
}
print " ✓ YAML"
# Render Kubernetes templates if needed
if ($target == "kubernetes") or ($target == "both") {
print " → Rendering Kubernetes ConfigMap..."
let cm_result = do {
jinja2 schemas/platform/templates/kubernetes/configmap.yaml.j2 $config_path
} | complete
if $cm_result.exit_code != 0 {
print $" ✗ ConfigMap rendering failed: ($cm_result.stderr)"
return false
}
do {
$cm_result.stdout | save -f ($output_dir | path join "configmap.yaml")
} | complete | if $in.exit_code != 0 {
return false
}
print " ✓ ConfigMap"
print " → Rendering Kubernetes Deployment..."
let deploy_result = do {
jinja2 schemas/platform/templates/kubernetes/deployment.yaml.j2 $config_path
} | complete
if $deploy_result.exit_code != 0 {
print $" ✗ Deployment rendering failed: ($deploy_result.stderr)"
return false
}
do {
$deploy_result.stdout | save -f ($output_dir | path join "deployment.yaml")
} | complete | if $in.exit_code != 0 {
return false
}
print " ✓ Deployment"
}
# Render Docker Compose if needed
if ($target == "docker") or ($target == "both") {
print " → Rendering Docker Compose..."
let dc_result = do {
jinja2 schemas/platform/templates/docker-compose/docker-compose.yaml.j2 $config_path
} | complete
if $dc_result.exit_code != 0 {
print $" ✗ Docker Compose rendering failed: ($dc_result.stderr)"
return false
}
do {
$dc_result.stdout | save -f ($output_dir | path join "docker-compose.yml")
} | complete | if $in.exit_code != 0 {
return false
}
print " ✓ Docker Compose"
}
true
}
def validate-outputs [output_dir: string, target: string] {
let errors = []
# Validate YAML files
let yaml_files = if ($target == "docker") {
["vapora-solo.yaml", "vapora-multiuser.yaml", "vapora-enterprise.yaml"]
} else if ($target == "kubernetes") {
["configmap.yaml", "deployment.yaml"]
} else {
["vapora-solo.yaml", "configmap.yaml", "deployment.yaml"]
}
$yaml_files | each { |file|
let path = ($output_dir | path join $file)
if not ($path | path exists) {
$errors | append $"Missing file: ($file)"
} else {
let validate = do {
yq eval '.' $path
} | complete
if $validate.exit_code != 0 {
$errors | append $"Invalid YAML in ($file): ($validate.stderr)"
}
}
}
{
valid: ($errors | length) == 0
errors: $errors
}
}
def deploy-docker [mode: string, output_dir: string, dry_run: bool] {
let compose_file = ($output_dir | path join "docker-compose.yml")
if not ($compose_file | path exists) {
error make {msg: "Docker Compose file not found"}
}
print " 📍 Docker Compose file: $compose_file"
if $dry_run {
print " 🔍 [DRY RUN] Would execute: docker compose -f $compose_file up -d"
return
}
print " 🚀 Starting Docker Compose services..."
let result = do {
docker compose -f $compose_file up -d
} | complete
if $result.exit_code != 0 {
error make {msg: $"Docker Compose failed: ($result.stderr)"}
}
print " ✓ Services started"
print ""
print " 📊 Running services:"
do {
docker compose -f $compose_file ps
} | complete | if $in.exit_code == 0 {
print $in.stdout
}
}
def deploy-kubernetes [mode: string, output_dir: string, dry_run: bool] {
let configmap_file = ($output_dir | path join "configmap.yaml")
let deployment_file = ($output_dir | path join "deployment.yaml")
if not ($configmap_file | path exists) {
error make {msg: "Kubernetes ConfigMap not found"}
}
if not ($deployment_file | path exists) {
error make {msg: "Kubernetes Deployment not found"}
}
# Ensure namespace exists
if $dry_run {
print " 🔍 [DRY RUN] Would create namespace: vapora"
} else {
do {
kubectl create namespace vapora --dry-run=client -o yaml | kubectl apply -f -
} | complete | if $in.exit_code != 0 {
print " ⚠️ Namespace creation (may already exist)"
}
}
# Apply ConfigMap
print " 📍 Applying ConfigMap..."
if $dry_run {
print " 🔍 [DRY RUN] Would apply: ($configmap_file)"
} else {
let cm_result = do {
kubectl apply -f $configmap_file
} | complete
if $cm_result.exit_code != 0 {
error make {msg: $"ConfigMap deployment failed: ($cm_result.stderr)"}
}
print " ✓ ConfigMap applied"
}
# Apply Deployments
print " 📍 Applying Deployments..."
if $dry_run {
print " 🔍 [DRY RUN] Would apply: ($deployment_file)"
} else {
let deploy_result = do {
kubectl apply -f $deployment_file
} | complete
if $deploy_result.exit_code != 0 {
error make {msg: $"Deployment failed: ($deploy_result.stderr)"}
}
print " ✓ Deployments applied"
}
print ""
print " 📊 Deployment status:"
do {
kubectl get deployment -n vapora -o wide
} | complete | if $in.exit_code == 0 {
print $in.stdout
}
}
# Run main function
main