diff --git a/Cargo.lock b/Cargo.lock index 794286c..6f916d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1059,11 +1059,12 @@ dependencies = [ [[package]] name = "gevulot-rs" -version = "0.1.0" -source = "git+https://github.com/gevulotnetwork/gevulot-rs.git?rev=f6657f57771b1c549a83cfe6fc822c3db687707e#f6657f57771b1c549a83cfe6fc822c3db687707e" +version = "0.1.3" +source = "git+https://github.com/gevulotnetwork/gevulot-rs.git?rev=0b3c05e34c7680c2dd3ef6caaf27b2f96bca279d#0b3c05e34c7680c2dd3ef6caaf27b2f96bca279d" dependencies = [ "backon", "bip32", + "const_format", "cosmos-sdk-proto", "cosmrs", "derivative", @@ -1076,6 +1077,7 @@ dependencies = [ "prost-build", "rand 0.8.5", "rand_core 0.6.4", + "semver", "serde", "serde_json", "tendermint", @@ -1117,7 +1119,7 @@ dependencies = [ [[package]] name = "gvltctl" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "bip32", @@ -1125,7 +1127,7 @@ dependencies = [ "clap_complete", "cosmrs", "env_logger 0.11.5", - "gevulot-rs 0.1.0 (git+https://github.com/gevulotnetwork/gevulot-rs.git?rev=f6657f57771b1c549a83cfe6fc822c3db687707e)", + "gevulot-rs 0.1.3", "log", "mia-installer", "num_cpus", @@ -1662,7 +1664,7 @@ dependencies = [ "env_logger 0.11.5", "flate2", "fs_extra", - "gevulot-rs 0.1.0 (git+https://github.com/gevulotnetwork/gevulot-rs.git?rev=997bd6c5266a98a69253c58b4bd1a35e8d3ec7ae)", + "gevulot-rs 0.1.0", "log", "octocrab", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index 46bde2d..950f31f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gvltctl" -version = "0.1.2" +version = "0.1.3" edition = "2021" authors = ["Gevulot Team"] license = "MIT OR Apache-2.0" @@ -11,7 +11,7 @@ description = "Gevulot Control CLI" # TODO: change rev to tag when available # NOTE: this revision is aligned with `mia-installer` dependency. # Be careful changing it. -gevulot-rs = { git = "https://github.com/gevulotnetwork/gevulot-rs.git", rev = "f6657f57771b1c549a83cfe6fc822c3db687707e" } +gevulot-rs = { git = "https://github.com/gevulotnetwork/gevulot-rs.git", rev = "0b3c05e34c7680c2dd3ef6caaf27b2f96bca279d" } bip32 = "0.5.1" clap = { version = "4", features = ["env", "cargo"] } @@ -26,7 +26,8 @@ tokio = { version = "1", features = ["full"] } toml = "0.8.19" [target.'cfg(target_os = "linux")'.dependencies] -mia-installer = { git = "https://github.com/gevulotnetwork/mia.git", tag = "mia-installer-0.2.3" } +mia-installer = { git = "https://github.com/gevulotnetwork/mia.git", rev = "026b84dbe7c3fcc9e0ec644c59a7b7123738104e" } +#mia-installer = { git = "https://github.com/gevulotnetwork/mia.git", tag = "mia-installer-0.2.3" } anyhow = "1" log = "0.4.22" diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 41e92b0..ec0c342 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -2,5 +2,6 @@ pub mod build; pub mod pins; pub mod tasks; +pub mod workflows; pub mod workers; pub mod sudo; diff --git a/src/commands/pins.rs b/src/commands/pins.rs index bc82975..ab010d3 100644 --- a/src/commands/pins.rs +++ b/src/commands/pins.rs @@ -30,8 +30,8 @@ pub async fn list_pins(_sub_m: &clap::ArgMatches) -> Result<(), Box Result<(), Box> { - let mut client = connect_to_gevulot(_sub_m).await?; if let Some(pin_cid) = _sub_m.get_one::("cid") { + let mut client = connect_to_gevulot(_sub_m).await?; let pin = client.pins.get(pin_cid).await?; // Convert the pin to the gevulot_rs::models::Pin type let pin: gevulot_rs::models::Pin = pin.into(); @@ -85,10 +85,13 @@ pub async fn create_pin(_sub_m: &clap::ArgMatches) -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { - let mut client = crate::connect_to_gevulot(_sub_m).await?; if let Some(task_id) = _sub_m.get_one::("id") { + let mut client = crate::connect_to_gevulot(_sub_m).await?; let task = client.tasks.get(task_id).await?; let task: gevulot_rs::models::Task = task.into(); print_object(_sub_m, &task)?; diff --git a/src/commands/workers.rs b/src/commands/workers.rs index 7aefaa2..97d2863 100644 --- a/src/commands/workers.rs +++ b/src/commands/workers.rs @@ -31,8 +31,8 @@ pub async fn list_workers(_sub_m: &clap::ArgMatches) -> Result<(), Box if an error occurs. pub async fn get_worker(_sub_m: &clap::ArgMatches) -> Result<(), Box> { - let mut client = connect_to_gevulot(_sub_m).await?; if let Some(worker_id) = _sub_m.get_one::("id") { + let mut client = connect_to_gevulot(_sub_m).await?; let worker = client.workers.get(worker_id).await?; let worker: gevulot_rs::models::Worker = worker.into(); print_object(_sub_m, &worker)?; diff --git a/src/commands/workflows.rs b/src/commands/workflows.rs new file mode 100644 index 0000000..2505518 --- /dev/null +++ b/src/commands/workflows.rs @@ -0,0 +1,97 @@ +use gevulot_rs::proto::gevulot::gevulot::{workflow_spec::Stage, InputContext, MsgCreateWorkflow, MsgDeleteWorkflow, OutputContext, TaskEnv, TaskSpec, WorkflowSpec}; + +use crate::{connect_to_gevulot, print_object, read_file}; + + + + +pub async fn list_workflows(_sub_m: &clap::ArgMatches) -> Result<(), Box> { + let mut client = crate::connect_to_gevulot(_sub_m).await?; + let workflows = client.workflows.list().await?; + let workflows: Vec = workflows.into_iter().map(Into::into).collect(); + print_object(_sub_m, &workflows)?; + Ok(()) +} + +pub async fn get_workflow(_sub_m: &clap::ArgMatches) -> Result<(), Box> { + if let Some(workflow_id) = _sub_m.get_one::("id") { + let mut client = crate::connect_to_gevulot(_sub_m).await?; + let workflow = client.workflows.get(workflow_id).await?; + let workflow: gevulot_rs::models::Workflow = workflow.into(); + print_object(_sub_m, &workflow)?; + } else { + println!("Workflow ID is required"); + } + Ok(()) +} + +pub async fn create_workflow(_sub_m: &clap::ArgMatches) -> Result<(), Box> { + let workflow: gevulot_rs::models::Workflow = read_file(_sub_m).await?; + let mut client = connect_to_gevulot(_sub_m).await?; + let me = client + .base_client + .write() + .await + .address + .clone() + .ok_or("No address found, did you set a mnemonic?")?; + + let resp = client + .workflows + .create(MsgCreateWorkflow{ + creator: me, + spec: Some(WorkflowSpec{ + stages: workflow.spec.stages.iter().map(|s| Stage{ + tasks: s.tasks.iter().map(|t| TaskSpec{ + image: t.image.clone(), + command: t.command.clone(), + args: t.args.clone(), + env: t.env.iter().map(|e| TaskEnv{ + name: e.name.clone(), + value: e.value.clone() + }).collect(), + input_contexts: t.input_contexts.iter().map(|ic| InputContext{ + source: ic.source.clone(), + target: ic.target.clone() + }).collect(), + output_contexts: t.output_contexts.iter().map(|oc| OutputContext{ + source: oc.source.clone(), + retention_period: oc.retention_period as u64 + }).collect(), + cpus: t.resources.cpus as u64, + gpus: t.resources.gpus as u64, + memory: t.resources.memory as u64, + time: t.resources.time as u64, + store_stdout: t.store_stdout.unwrap_or(false), + store_stderr: t.store_stderr.unwrap_or(false), + workflow_ref: "".to_string(), + }).collect::>(), + }).collect::>(), + }), + }).await?; + + println!("Created workflow with ID: {}", resp.id); + Ok(()) +} + +pub async fn delete_workflow(_sub_m: &clap::ArgMatches) -> Result<(), Box> { + if let Some(workflow_id) = _sub_m.get_one::("id") { + let mut client = crate::connect_to_gevulot(_sub_m).await?; + let me = client + .base_client + .write() + .await + .address + .clone() + .ok_or("No address found, did you set a mnemonic?")?; + + client.workflows.delete(MsgDeleteWorkflow{ + creator: me, + id: workflow_id.clone(), + }).await?; + println!("ok"); + } else { + println!("Workflow ID is required"); + } + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index d31f8ea..ff49554 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ mod commands; #[cfg(target_os = "linux")] use commands::build::*; -use commands::{pins::*, sudo::*, tasks::*, workers::*}; +use commands::{pins::*, sudo::*, tasks::*, workers::*, workflows::*}; /// Main entry point for the Gevulot Control CLI application. /// @@ -761,26 +761,3 @@ async fn generate_completion(_sub_m: &clap::ArgMatches) -> Result<(), Box Result<(), Box> { - let output = serde_json::json!({ - "message": "Listing all workflows", - "status": "not_implemented" - }); - print_object(_sub_m, &output)?; - todo!(); -} - -async fn get_workflow(_sub_m: &clap::ArgMatches) -> Result<(), Box> { - println!("Getting a specific workflow"); - todo!(); -} - -async fn create_workflow(_sub_m: &clap::ArgMatches) -> Result<(), Box> { - println!("Creating a new workflow"); - todo!(); -} - -async fn delete_workflow(_sub_m: &clap::ArgMatches) -> Result<(), Box> { - println!("Deleting a workflow"); - todo!(); -}