use std::{ str, process::Command };
use colored::Colorize;
use clap::{ Args, Subcommand };
use kube::{ core::ErrorResponse, Error };
use crate::essential::{ BASE_COMMAND, connect_to_client, CliError };
use crate::logs::{ get_available_namespaces, check_namespace_exists };
#[derive(Subcommand, Debug, Clone)]
pub enum ServiceCommands {
#[command(name = "list", about = "Check services list")] List {
#[arg(long)]
namespace: Option<String>,
},
#[command(name = "describe", about = "Describe service")] Describe {
service_name: String,
#[arg(long)]
namespace: Option<String>,
},
}
#[derive(Args, Debug, Clone)]
pub struct ServiceArgs {
#[command(subcommand)]
pub service_cmd: ServiceCommands,
}
pub async fn list_services(namespace: Option<String>) -> Result<(), CliError> {
match connect_to_client().await {
Ok(_) => {
let ns = namespace.unwrap_or_else(|| "cortexflow".to_string());
println!("{} {} {}", "=====>".blue().bold(), "Listing services in namespace:", ns);
if !check_namespace_exists(&ns).await? {
let available_namespaces = get_available_namespaces().await?;
println!("\n❌ Namespace '{}' not found", ns);
println!("{}", "=".repeat(50));
if !available_namespaces.is_empty() {
println!("\n📋 Available namespaces:");
for available_ns in &available_namespaces {
println!(" • {}", available_ns);
}
} else {
println!("No namespaces found in the cluster.");
}
}
let output = Command::new(BASE_COMMAND)
.args(["get", "svc", "-n", &ns, "--no-headers"])
.output();
match output {
Ok(output) => {
if !output.status.success() {
let error = str::from_utf8(&output.stderr).unwrap_or("Unknown error");
eprintln!("Error executing {}: {}", BASE_COMMAND, error);
}
let stdout = str::from_utf8(&output.stdout).unwrap_or("");
if stdout.trim().is_empty() {
println!(
"{} {} {}",
"=====>".blue().bold(),
"No services found in namespace",
ns
);
}
println!("{:<40} {:<20} {:<10} {:<10}", "NAME", "STATUS", "RESTARTS", "AGE");
println!("{}", "-".repeat(80));
for line in stdout.lines() {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 5 {
let name = parts[0];
let ready = parts[1];
let status = parts[2];
let restarts = parts[3];
let age = parts[4];
let full_status = if ready.contains('/') {
format!("{} ({})", status, ready)
} else {
status.to_string()
};
println!(
"{:<40} {:<20} {:<10} {:<10}",
name,
full_status,
restarts,
age
);
}
}
Ok(())
}
Err(err) => {
Err(
CliError::ClientError(
Error::Api(ErrorResponse {
status: "failed".to_string(),
message: "Failed to execute the kubectl command".to_string(),
reason: "Your cluster is probably disconnected".to_string(),
code: 404,
})
)
)
}
}
}
Err(_) => {
Err(
CliError::ClientError(
Error::Api(ErrorResponse {
status: "failed".to_string(),
message: "Failed to connect to kubernetes client".to_string(),
reason: "Your cluster is probably disconnected".to_string(),
code: 404,
})
)
)
}
}
}
pub async fn describe_service(
service_name: String,
namespace: &Option<String>
) -> Result<(), CliError> {
match connect_to_client().await {
Ok(_) => {
match list_services(namespace.clone()).await {
Ok(_) => {
let ns = namespace.clone().unwrap_or_else(|| "cortexflow".to_string());
println!(
"{} {} {} {} {}",
"=====>".blue().bold(),
"Describing service",
"in namespace:",
service_name,
ns
);
println!("{}", "=".repeat(60));
if !check_namespace_exists(&ns).await? {
let available_namespaces = get_available_namespaces().await?;
println!("\n❌ Namespace '{}' not found", ns);
println!("{}", "=".repeat(50));
if !available_namespaces.is_empty() {
println!("\n📋 Available namespaces:");
for available_ns in &available_namespaces {
println!(" • {}", available_ns);
}
println!("\nTry: cortex service describe {} --namespace <namespace-name>", service_name);
} else {
println!("No namespaces found in the cluster.");
}
}
let output = Command::new(BASE_COMMAND)
.args(["describe", "pod", &service_name, "-n", &ns])
.output();
match output {
Ok(output) => {
if !output.status.success() {
let error = str
::from_utf8(&output.stderr)
.unwrap_or("Unknown error");
eprintln!("Error executing kubectl describe: {}", error);
eprintln!(
"Make sure the pod '{}' exists in namespace '{}'",
service_name,
ns
);
}
let stdout = str::from_utf8(&output.stdout).unwrap_or("");
if stdout.trim().is_empty() {
println!("No description found for pod '{}'", service_name);
}
println!("{}", stdout);
Ok(())
}
Err(err) => {
Err(
CliError::ClientError(
Error::Api(ErrorResponse {
status: "failed".to_string(),
message: "Failed to execute the kubectl command ".to_string(),
reason: "Your cluster is probably disconnected".to_string(),
code: 404,
})
)
)
}
}
}
Err(e) => todo!(),
}
}
Err(_) => {
Err(
CliError::ClientError(
Error::Api(ErrorResponse {
status: "failed".to_string(),
message: "Failed to connect to kubernetes client".to_string(),
reason: "Your cluster is probably disconnected".to_string(),
code: 404,
})
)
)
}
}
}