#![allow( dead_code, unused_imports, unused_variables, unused_assignments, unused, clippy::excessive_nesting )] //! Core provisioning engine for executing infrastructure commands use std::process::Stdio; use anyhow::{Context, Result}; use serde_json::Value; use tracing::{debug, info}; use crate::config::Config; use crate::errors::ProvisioningError; #[derive(Debug, Clone)] pub struct ServerConfig { pub hostname: String, pub instance_type: String, pub count: u32, pub provider: String, pub region: Option, pub purpose: Option, } pub struct ProvisioningEngine { config: Config, } impl ProvisioningEngine { pub fn new(config: &Config) -> Result { Ok(Self { config: config.clone(), }) } /// Create servers based on parsed configuration pub fn create_server(&self, server_config: &ServerConfig, check_mode: bool) -> Result { info!("Creating server: {:?}", server_config); let mut args = vec![ "server".to_string(), "create".to_string(), "--infra".to_string(), format!("ai-{}", server_config.hostname), ]; if check_mode { args.push("--check".to_string()); } if let Some(region) = &server_config.region { args.extend(vec!["--region".to_string(), region.clone()]); } args.push("--out".to_string()); args.push("json".to_string()); let result = self.execute_provisioning_command(&args)?; // Parse and format the result if let Ok(json_result) = serde_json::from_str::(&result) { Ok(self.format_server_result(&json_result, check_mode)) } else { Ok(result) } } /// Process natural language infrastructure queries pub fn process_query( &self, query: &str, infra_name: Option<&str>, output_format: &str, ) -> Result { info!("Processing query: {}", query); let mut args = vec!["show".to_string()]; // Determine what to show based on the query if query.to_lowercase().contains("server") || query.to_lowercase().contains("instance") { args.push("servers".to_string()); } else if query.to_lowercase().contains("cost") || query.to_lowercase().contains("price") { args.push("costs".to_string()); } else if query.to_lowercase().contains("status") { args.push("data".to_string()); } else { args.push("settings".to_string()); } if let Some(infra) = infra_name { args.extend(vec!["--infra".to_string(), infra.to_string()]); } args.extend(vec!["--out".to_string(), output_format.to_string()]); let result = self.execute_provisioning_command(&args)?; // Add natural language interpretation Ok(format!( "Based on your query: \"{}\"\n\n{}", query, self.interpret_query_result(query, &result) )) } /// Deploy a task service pub fn deploy_taskserv( &self, service_name: &str, infra_name: &str, _configuration: &Value, check_mode: bool, ) -> Result { info!("Deploying service {} to {}", service_name, infra_name); let mut args = vec![ "taskserv".to_string(), "create".to_string(), service_name.to_string(), "--infra".to_string(), infra_name.to_string(), ]; if check_mode { args.push("--check".to_string()); } args.extend(vec!["--out".to_string(), "json".to_string()]); let result = self.execute_provisioning_command(&args)?; Ok(format!( "🚀 Service '{}' deployment on '{}' infrastructure:\n\n{}", service_name, infra_name, result )) } /// Create a complete cluster pub fn create_cluster( &self, description: &str, cluster_type: &str, services: &[&str], infra_name: &str, ) -> Result { info!("Creating {} cluster: {}", cluster_type, description); // First create the infrastructure let mut results = Vec::new(); // Generate infrastructure let gen_args = vec![ "generate".to_string(), "infra".to_string(), "--new".to_string(), infra_name.to_string(), "--template".to_string(), format!("{}-cluster", cluster_type), ]; match self.execute_provisioning_command(&gen_args) { Ok(result) => results.push(format!("📋 Infrastructure generated:\n{}", result)), Err(e) => results.push(format!("⚠️ Infrastructure generation: {}", e)), } // Create servers let server_args = vec![ "server".to_string(), "create".to_string(), "--infra".to_string(), infra_name.to_string(), ]; match self.execute_provisioning_command(&server_args) { Ok(result) => results.push(format!("🖥️ Servers created:\n{}", result)), Err(e) => results.push(format!("⚠️ Server creation: {}", e)), } // Deploy each service for service in services { let service_args = vec![ "taskserv".to_string(), "create".to_string(), service.to_string(), "--infra".to_string(), infra_name.to_string(), ]; match self.execute_provisioning_command(&service_args) { Ok(result) => { results.push(format!("⚙️ Service '{}' deployed:\n{}", service, result)) } Err(e) => results.push(format!("⚠️ Service '{}': {}", service, e)), } } Ok(results.join("\n\n")) } /// Get status of infrastructure pub fn get_status(&self, infra_name: Option<&str>, detailed: bool) -> Result { let mut args = vec!["show".to_string()]; if detailed { args.push("alldata".to_string()); } else { args.push("data".to_string()); } if let Some(infra) = infra_name { args.extend(vec!["--infra".to_string(), infra.to_string()]); } args.extend(vec!["--out".to_string(), "json".to_string()]); let result = self.execute_provisioning_command(&args)?; // Parse and format the status if let Ok(json_result) = serde_json::from_str::(&result) { Ok(self.format_status_result(&json_result, detailed)) } else { Ok(result) } } /// Execute a provisioning command fn execute_provisioning_command(&self, args: &[String]) -> Result { debug!("Executing command: {:?}", args); let cmd_path = "provisioning"; // Use default command name let output = std::process::Command::new(cmd_path) .args(args) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .output() .with_context(|| format!("Failed to execute command: {}", cmd_path))?; if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr); return Err(ProvisioningError::command_failed(format!( "Command failed with status {}: {}", output.status.code().unwrap_or(-1), stderr )) .into()); } let stdout = String::from_utf8_lossy(&output.stdout); Ok(stdout.to_string()) } /// Format server creation result fn format_server_result(&self, result: &Value, check_mode: bool) -> String { let prefix = if check_mode { "🔍 Check mode result" } else { "✅ Server creation result" }; if let Some(servers) = result.get("servers").and_then(|s| s.as_array()) { let mut output = format!("{}\n\n", prefix); for server in servers { if let (Some(hostname), Some(status)) = ( server.get("hostname").and_then(|h| h.as_str()), server.get("status").and_then(|s| s.as_str()), ) { output.push_str(&format!("• {}: {}\n", hostname, status)); if let Some(ip) = server.get("public_ip").and_then(|ip| ip.as_str()) { output.push_str(&format!(" IP: {}\n", ip)); } if let Some(cost) = server.get("cost_hour").and_then(|c| c.as_str()) { output.push_str(&format!(" Cost: {}/hour\n", cost)); } } } output } else { format!( "{}\n\n{}", prefix, serde_json::to_string_pretty(result).unwrap_or_default() ) } } /// Format status result fn format_status_result(&self, result: &Value, detailed: bool) -> String { let mut output = String::new(); if let Some(main_name) = result.get("main_name").and_then(|n| n.as_str()) { output.push_str(&format!("📊 Infrastructure: {}\n\n", main_name)); } if let Some(servers) = result.get("servers").and_then(|s| s.as_array()) { output.push_str("🖥️ Servers:\n"); for server in servers { if let Some(hostname) = server.get("hostname").and_then(|h| h.as_str()) { let status = server .get("status") .and_then(|s| s.as_str()) .unwrap_or("unknown"); let emoji = match status { "running" => "🟢", "stopped" => "🔴", "pending" => "🟡", _ => "⚪", }; output.push_str(&format!(" {} {}: {}\n", emoji, hostname, status)); } } output.push('\n'); } if detailed { if let Some(costs) = result.get("costs") { output.push_str(&format!( "💰 Costs: {}\n", serde_json::to_string_pretty(costs).unwrap_or_default() )); } } output } /// Interpret query result with natural language fn interpret_query_result(&self, query: &str, result: &str) -> String { // Simple interpretation based on query keywords if query.to_lowercase().contains("cost") || query.to_lowercase().contains("price") { format!("💰 Cost analysis:\n{}", result) } else if query.to_lowercase().contains("status") || query.to_lowercase().contains("health") { format!("📊 System status:\n{}", result) } else if query.to_lowercase().contains("problem") || query.to_lowercase().contains("error") { format!("🔍 Issue analysis:\n{}", result) } else { result.to_string() } } }