Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/src/general.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub struct GeneralData {
}

impl GeneralData {
pub const VERSION: &str = "0.1";
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const AUTHOR: &str = "CortexFlow";
pub const DESCRIPTION: &str = "";

Expand Down
28 changes: 27 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod install;
mod general;
mod uninstall;
mod service;
mod status;

use clap::{ Error, Parser, Subcommand, Args };
use clap::command;
Expand All @@ -11,7 +12,8 @@ use tracing::debug;
use crate::essential::{ info, update_cli };
use crate::install::install_cortexflow;
use crate::uninstall::uninstall;
use crate::service::list_services;
use crate::service::{list_services, describe_service};
use crate::status::status_command;

use crate::general::GeneralData;

Expand Down Expand Up @@ -46,6 +48,8 @@ enum Commands {
Info,
#[command(name="service")]
Service(ServiceArgs),
#[command(name="status")]
Status(StatusArgs),
}
#[derive(Args, Debug, Clone)]
struct SetArgs {
Expand All @@ -65,6 +69,20 @@ enum ServiceCommands {
#[arg(long)]
namespace: Option<String>,
},
#[command(name="describe")]
Describe {
service_name: String,
#[arg(long)]
namespace: Option<String>,
},
}

#[derive(Args, Debug, Clone)]
struct StatusArgs {
#[arg(long)]
output: Option<String>,
#[arg(long)]
namespace: Option<String>,
}

fn args_parser() -> Result<(), Error> {
Expand Down Expand Up @@ -103,8 +121,16 @@ fn args_parser() -> Result<(), Error> {
list_services(namespace);
Ok(())
}
ServiceCommands::Describe { service_name, namespace } => {
describe_service(service_name, namespace);
Ok(())
}
}
}
Some(Commands::Status(status_args)) => {
status_command(status_args.output, status_args.namespace);
Ok(())
}
None => {
eprintln!("CLI unknown argument. Cli arguments passed: {:?}", args.cmd);
Ok(())
Expand Down
3 changes: 2 additions & 1 deletion cli/src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod essential;
pub mod install;
pub mod general;
pub mod uninstall;
pub mod service;
pub mod service;
pub mod status;
105 changes: 105 additions & 0 deletions cli/src/service.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,58 @@
use std::process::Command;
use std::str;

fn check_namespace_exists(namespace: &str) -> bool {
let output = Command::new("kubectl")
.args(["get", "namespace", namespace])
.output();

match output {
Ok(output) => output.status.success(),
Err(_) => false,
}
}

fn get_available_namespaces() -> Vec<String> {
let output = Command::new("kubectl")
.args(["get", "namespaces", "--no-headers", "-o", "custom-columns=NAME:.metadata.name"])
.output();

match output {
Ok(output) if output.status.success() => {
let stdout = str::from_utf8(&output.stdout).unwrap_or("");
stdout.lines()
.map(|line| line.trim().to_string())
.filter(|line| !line.is_empty())
.collect()
}
_ => Vec::new(),
}
}

pub fn list_services(namespace: Option<String>) {
let ns = namespace.unwrap_or_else(|| "cortexflow".to_string());

println!("Listing services in namespace: {}", ns);

// Check if namespace exists first
if !check_namespace_exists(&ns) {
let available_namespaces = get_available_namespaces();

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.");
}

std::process::exit(1);
}

// kubectl command to get services
let output = Command::new("kubectl")
.args(["get", "pods", "-n", &ns, "--no-headers"])
Expand Down Expand Up @@ -56,4 +103,62 @@ pub fn list_services(namespace: Option<String>) {
std::process::exit(1);
}
}
}

pub fn describe_service(service_name: String, namespace: Option<String>) {
let ns = namespace.unwrap_or_else(|| "cortexflow".to_string());

println!("Describing service '{}' in namespace: {}", service_name, ns);
println!("{}", "=".repeat(60));

// Check if namespace exists first
if !check_namespace_exists(&ns) {
let available_namespaces = get_available_namespaces();

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.");
}

std::process::exit(1);
}

// Execute kubectl describe pod command
let output = Command::new("kubectl")
.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);
std::process::exit(1);
}

let stdout = str::from_utf8(&output.stdout).unwrap_or("");

if stdout.trim().is_empty() {
println!("No description found for pod '{}'", service_name);
return;
}

// Print the full kubectl describe output
println!("{}", stdout);
}
Err(err) => {
eprintln!("Failed to execute kubectl describe command: {}", err);
eprintln!("Make sure kubectl is installed and configured properly");
std::process::exit(1);
}
}
}
Loading