From 818d4ad76592c87a5c0c7bbd728636023c07daa0 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Wed, 1 May 2024 13:59:33 -0700 Subject: tools/unitctl: API Plumbing for docker deployments * refactored "instance" command out of enum * plumbed through function stub from client library * error handling Signed-off-by: Ava Hahn --- tools/unitctl/unit-client-rs/src/unitd_docker.rs | 12 ++++++ tools/unitctl/unitctl/src/cmd/instances.rs | 41 +++++++++++++----- tools/unitctl/unitctl/src/main.rs | 10 ++--- tools/unitctl/unitctl/src/unitctl.rs | 55 ++++++++++++++++++------ 4 files changed, 91 insertions(+), 27 deletions(-) diff --git a/tools/unitctl/unit-client-rs/src/unitd_docker.rs b/tools/unitctl/unit-client-rs/src/unitd_docker.rs index d5028afc..0f30ae8a 100644 --- a/tools/unitctl/unit-client-rs/src/unitd_docker.rs +++ b/tools/unitctl/unit-client-rs/src/unitd_docker.rs @@ -3,6 +3,7 @@ use std::fs::read_to_string; use std::path::PathBuf; use crate::unitd_process::UnitdProcess; +use crate::unit_client::UnitClientError; use bollard::secret::ContainerInspectResponse; use regex::Regex; @@ -212,6 +213,17 @@ impl UnitdContainer { } } +/* deploys a new docker image of tag $image_tag. + * mounts $socket to /var/run in the new container. + * mounts $application to /www in the new container. */ +pub fn deploy_new_container( + _socket: &String, + _application: &String, + _image: &String +) -> Result<(), UnitClientError> { + todo!() +} + /* Returns either 64 char docker container ID or None */ pub fn pid_is_dockerized(pid: u64) -> bool { let cg_filepath = format!("/proc/{}/cgroup", pid); diff --git a/tools/unitctl/unitctl/src/cmd/instances.rs b/tools/unitctl/unitctl/src/cmd/instances.rs index 09e3eb0f..84725957 100644 --- a/tools/unitctl/unitctl/src/cmd/instances.rs +++ b/tools/unitctl/unitctl/src/cmd/instances.rs @@ -1,16 +1,37 @@ use crate::{OutputFormat, UnitctlError}; +use crate::unitctl::{InstanceArgs, InstanceCommands}; use unit_client_rs::unitd_instance::UnitdInstance; +use unit_client_rs::unitd_docker::deploy_new_container; +use std::path::PathBuf; -pub(crate) async fn cmd(output_format: OutputFormat) -> Result<(), UnitctlError> { - let instances = UnitdInstance::running_unitd_instances().await; - if instances.is_empty() { - Err(UnitctlError::NoUnitInstancesError) - } else if output_format.eq(&OutputFormat::Text) { - instances.iter().for_each(|instance| { - println!("{}", instance); - }); - Ok(()) +pub(crate) async fn cmd(args: InstanceArgs) -> Result<(), UnitctlError> { + if let Some(cmd) = args.command { + match cmd { + InstanceCommands::New{ + ref socket, + ref application, + ref image + } => { + if !PathBuf::from(socket).is_dir() || !PathBuf::from(application).is_dir() { + eprintln!("application and socket paths must be directories"); + Err(UnitctlError::NoFilesImported) + } else { + deploy_new_container(socket, application, image) + .or_else(|e| Err(UnitctlError::UnitClientError{source: e})) + } + } + } } else { - output_format.write_to_stdout(&instances) + let instances = UnitdInstance::running_unitd_instances().await; + if instances.is_empty() { + Err(UnitctlError::NoUnitInstancesError) + } else if args.output_format.eq(&OutputFormat::Text) { + instances.iter().for_each(|instance| { + println!("{}", instance); + }); + Ok(()) + } else { + args.output_format.write_to_stdout(&instances) + } } } diff --git a/tools/unitctl/unitctl/src/main.rs b/tools/unitctl/unitctl/src/main.rs index a52c4ed3..9c42bdf0 100644 --- a/tools/unitctl/unitctl/src/main.rs +++ b/tools/unitctl/unitctl/src/main.rs @@ -28,11 +28,11 @@ async fn main() -> Result<(), UnitctlError> { let cli = UnitCtl::parse(); match cli.command { - Commands::Instances { output_format } => instances::cmd(output_format).await, + Commands::Instances(args) => instances::cmd(args).await, - Commands::Edit { output_format } => edit::cmd(&cli, output_format).await, + Commands::Edit{output_format} => edit::cmd(&cli, output_format).await, - Commands::Import { ref directory } => import::cmd(&cli, directory).await, + Commands::Import{ref directory} => import::cmd(&cli, directory).await, Commands::Execute { ref output_format, @@ -41,9 +41,9 @@ async fn main() -> Result<(), UnitctlError> { ref path, } => execute_cmd::cmd(&cli, output_format, input_file, method, path).await, - Commands::Status { output_format } => status::cmd(&cli, output_format).await, + Commands::Status{output_format} => status::cmd(&cli, output_format).await, - Commands::Listeners { output_format } => listeners::cmd(&cli, output_format).await, + Commands::Listeners{output_format}=> listeners::cmd(&cli, output_format).await, } .map_err(|error| { eprint_error(&error); diff --git a/tools/unitctl/unitctl/src/unitctl.rs b/tools/unitctl/unitctl/src/unitctl.rs index 49e87e8e..eb7da1b0 100644 --- a/tools/unitctl/unitctl/src/unitctl.rs +++ b/tools/unitctl/unitctl/src/unitctl.rs @@ -2,7 +2,7 @@ extern crate clap; use crate::output_format::OutputFormat; use clap::error::ErrorKind::ValueValidation; -use clap::{Error as ClapError, Parser, Subcommand}; +use clap::{Error as ClapError, Parser, Subcommand, Args}; use std::path::PathBuf; use unit_client_rs::control_socket_address::ControlSocket; @@ -42,17 +42,7 @@ pub(crate) struct UnitCtl { #[derive(Debug, Subcommand)] pub(crate) enum Commands { #[command(about = "List all running UNIT processes")] - Instances { - #[arg( - required = false, - global = true, - short = 't', - long = "output-format", - default_value = "text", - help = "Output format: text, yaml, json, json-pretty (default)" - )] - output_format: OutputFormat, - }, + Instances(InstanceArgs), #[command(about = "Open current UNIT configuration in editor")] Edit { #[arg( @@ -126,6 +116,47 @@ pub(crate) enum Commands { }, } +#[derive(Debug, Args)] +pub struct InstanceArgs { + #[arg( + required = false, + global = true, + short = 't', + long = "output-format", + default_value = "text", + help = "Output format: text, yaml, json, json-pretty (default)" + )] + pub output_format: OutputFormat, + + #[command(subcommand)] + pub command: Option, +} + +#[derive(Debug, Subcommand)] +#[command(args_conflicts_with_subcommands = true)] +pub enum InstanceCommands { + #[command(about = "deploy a new docker instance of unitd")] + New { + #[arg( + required = true, + help = "Path to mount control socket to host", + )] + socket: String, + + #[arg( + required = true, + help = "Path to mount application into container", + )] + application: String, + + #[arg( + help = "Unitd Image to deploy", + default_value = env!("CARGO_PKG_VERSION"), + )] + image: String, + } +} + fn parse_control_socket_address(s: &str) -> Result { ControlSocket::try_from(s).map_err(|e| ClapError::raw(ValueValidation, e.to_string())) } -- cgit