summaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
authorAva Hahn <a.hahn@f5.com>2024-05-01 18:21:55 -0700
committeravahahn <110854134+avahahn@users.noreply.github.com>2024-05-08 13:30:08 -0700
commit1d237990c589a90d7ec85f211c01b709b1e5dc65 (patch)
treecf22dcc26a81a111615918d3243c32dfdc3550cb /tools
parentf6989dd67965c7489f8c68ecd0e25f0358b5993f (diff)
downloadunit-1d237990c589a90d7ec85f211c01b709b1e5dc65.tar.gz
unit-1d237990c589a90d7ec85f211c01b709b1e5dc65.tar.bz2
tools/unitctl: Add new functionality to README.md and fmt code
Signed-off-by: Ava Hahn <a.hahn@f5.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/unitctl/README.md40
-rw-r--r--tools/unitctl/unit-client-rs/src/unitd_docker.rs145
-rw-r--r--tools/unitctl/unit-client-rs/src/unitd_instance.rs13
-rw-r--r--tools/unitctl/unitctl/src/cmd/instances.rs28
-rw-r--r--tools/unitctl/unitctl/src/main.rs8
-rw-r--r--tools/unitctl/unitctl/src/unitctl.rs14
6 files changed, 140 insertions, 108 deletions
diff --git a/tools/unitctl/README.md b/tools/unitctl/README.md
index 7292cd86..e514cd56 100644
--- a/tools/unitctl/README.md
+++ b/tools/unitctl/README.md
@@ -36,9 +36,9 @@ desired.
## Features (Current)
-### Consumes alternative configuration formats Like YAML and converts them
-### Syntactic highlighting of JSON output
-### Interpretation of UNIT errors with (arguably more) useful error messages
+- Consumes alternative configuration formats Like YAML and converts them
+- Syntactic highlighting of JSON output
+- Interpretation of UNIT errors with (arguably more) useful error messages
### Lists all running UNIT processes and provides details about each process.
```
@@ -52,6 +52,30 @@ unitd instance [pid: 79489, version: 1.32.0]:
Configure options: --prefix=/opt/unit --user=elijah --group=elijah --openssl
```
+### Start a new UNIT process via docker
+```
+$ unitctl instances new /tmp/2 $(pwd) 'unit:wasm'
+Pulling and starting a container from unit:wasm
+Will mount /tmp/2 to /var/run for socket access
+Will READ ONLY mount /home/ava/repositories/nginx/unit/tools/unitctl to /www for application access
+Note: Container will be on host network
+
+```
+
+To the subcommand `unitctl instances new` the user must provide three things:
+1. **A directory such as `/tmp/2`.**
+ The UNIT container will mount this to `/var/run` internally.
+ Thus, the control socket and pid file will be accessible from the host.
+2. **A path to an application.**
+ In the example, `$(pwd)` is provided. The UNIT container will mount
+ this READ ONLY to `/www/`. This will allow the user to configure
+ their UNIT container to expose an application stored on the host.
+3. **An image tag.**
+ In the example, `unit:wasm` is used. This will be the image that unitctl
+ will deploy. Custom repos and images can be deployed in this manner.
+
+After deployment the user will have one UNIT container running on the host network.
+
### Lists active listeners from running UNIT processes
```
unitctl listeners
@@ -109,13 +133,6 @@ $ unitctl edit
}
```
-### Display interactive OpenAPI control panel
-```
-$ unitctl ui
-Starting UI server on http://127.0.0.1:3000/control-ui/
-Press Ctrl-C to stop the server
-```
-
### Import configuration, certificates, and NJS modules from directory
```
$ unitctl import /opt/unit/config
@@ -124,6 +141,7 @@ Imported /opt/unit/config/hello.js -> /js_modules/hello.js
Imported /opt/unit/config/put.json -> /config
Imported 3 files
```
+
### Wait for socket to become available
```
$ unitctl --wait-timeout-seconds=3 --wait-max-tries=4 import /opt/unit/config`
@@ -131,4 +149,4 @@ Waiting for 3s control socket to be available try 2/4...
Waiting for 3s control socket to be available try 3/4...
Waiting for 3s control socket to be available try 4/4...
Timeout waiting for unit to start has been exceeded
-``` \ No newline at end of file
+```
diff --git a/tools/unitctl/unit-client-rs/src/unitd_docker.rs b/tools/unitctl/unit-client-rs/src/unitd_docker.rs
index 47f017a9..2b51ddd3 100644
--- a/tools/unitctl/unit-client-rs/src/unitd_docker.rs
+++ b/tools/unitctl/unit-client-rs/src/unitd_docker.rs
@@ -2,18 +2,17 @@ use std::collections::HashMap;
use std::fs::read_to_string;
use std::path::PathBuf;
-use crate::unitd_process::UnitdProcess;
+use crate::futures::StreamExt;
use crate::unit_client::UnitClientError;
-use bollard::{models::ContainerSummary, Docker};
-use bollard::container::{Config, StartContainerOptions, ListContainersOptions};
+use crate::unitd_process::UnitdProcess;
+use bollard::container::{Config, ListContainersOptions, StartContainerOptions};
use bollard::image::CreateImageOptions;
+use bollard::models::{ContainerCreateResponse, HostConfig, Mount, MountTypeEnum};
use bollard::secret::ContainerInspectResponse;
-use bollard::models::{HostConfig, MountTypeEnum, Mount, ContainerCreateResponse};
+use bollard::{models::ContainerSummary, Docker};
use regex::Regex;
use serde::ser::SerializeMap;
use serde::{Serialize, Serializer};
-use crate::futures::StreamExt;
-
#[derive(Clone, Debug)]
pub struct UnitdContainer {
@@ -75,7 +74,8 @@ impl From<&UnitdContainer> for UnitdProcess {
cmd.strip_prefix("/usr/local/bin/docker-entrypoint.sh")
.or_else(|| Some(""))
.unwrap()
- .to_string())
+ .to_string()
+ )
))
});
let mut cmds = vec![];
@@ -197,13 +197,15 @@ impl UnitdContainer {
pub fn rewrite_socket(&self, command: String) -> String {
command
.split(" ")
- .map(|tok| if tok.starts_with("unix:") {
- format!("unix:{}", self.host_path(
- tok.strip_prefix("unix:")
- .unwrap()
- .to_string()))
- } else {
- tok.to_string()
+ .map(|tok| {
+ if tok.starts_with("unix:") {
+ format!(
+ "unix:{}",
+ self.host_path(tok.strip_prefix("unix:").unwrap().to_string())
+ )
+ } else {
+ tok.to_string()
+ }
})
.collect::<Vec<_>>()
.join(" ")
@@ -227,18 +229,18 @@ impl UnitdContainer {
pub async fn deploy_new_container(
socket: &String,
application: &String,
- image: &String
+ image: &String,
) -> Result<Vec<String>, UnitClientError> {
match Docker::connect_with_local_defaults() {
Ok(docker) => {
let mut mounts = vec![];
- mounts.push(Mount{
+ mounts.push(Mount {
typ: Some(MountTypeEnum::BIND),
source: Some(socket.clone()),
target: Some("/var/run".to_string()),
..Default::default()
});
- mounts.push(Mount{
+ mounts.push(Mount {
typ: Some(MountTypeEnum::BIND),
source: Some(application.clone()),
target: Some("/www".to_string()),
@@ -246,65 +248,88 @@ pub async fn deploy_new_container(
..Default::default()
});
- let _ = docker.create_image(
- Some(CreateImageOptions {
- from_image: image.as_str(),
- ..Default::default()
- }), None, None)
+ let _ = docker
+ .create_image(
+ Some(CreateImageOptions {
+ from_image: image.as_str(),
+ ..Default::default()
+ }),
+ None,
+ None,
+ )
.next()
.await
.unwrap()
- .or_else(|err| Err(UnitClientError::UnitdDockerError{message: err.to_string()}));
+ .or_else(|err| {
+ Err(UnitClientError::UnitdDockerError {
+ message: err.to_string(),
+ })
+ });
let resp: ContainerCreateResponse;
- match docker.create_container::<String, String>(
- None, Config {
- image: Some(image.clone()),
- host_config: Some(HostConfig {
- network_mode: Some("host".to_string()),
- mounts: Some(mounts),
+ match docker
+ .create_container::<String, String>(
+ None,
+ Config {
+ image: Some(image.clone()),
+ host_config: Some(HostConfig {
+ network_mode: Some("host".to_string()),
+ mounts: Some(mounts),
+ ..Default::default()
+ }),
..Default::default()
- }), ..Default::default()})
- .await {
- Err(err) => return Err(UnitClientError::UnitdDockerError{message: err.to_string()}),
- Ok(response) => resp = response,
+ },
+ )
+ .await
+ {
+ Err(err) => {
+ return Err(UnitClientError::UnitdDockerError {
+ message: err.to_string(),
+ })
}
+ Ok(response) => resp = response,
+ }
let mut list_container_filters = HashMap::new();
list_container_filters.insert("id".to_string(), vec![resp.id]);
- match docker.list_containers::<String>(
- Some(ListContainersOptions{
+ match docker
+ .list_containers::<String>(Some(ListContainersOptions {
all: true,
limit: None,
size: false,
filters: list_container_filters,
}))
- .await {
- Err(e) => Err(UnitClientError::UnitdDockerError{message: e.to_string()}),
- Ok(info) => {
- if info.len() < 1 {
- return Err(UnitClientError::UnitdDockerError{message: "couldnt find new container".to_string()});
- }
- if info[0].names.is_none() || info[0].names.clone().unwrap().len() < 1 {
- return Err(UnitClientError::UnitdDockerError{message: "new container has no name".to_string()});
- }
+ .await
+ {
+ Err(e) => Err(UnitClientError::UnitdDockerError { message: e.to_string() }),
+ Ok(info) => {
+ if info.len() < 1 {
+ return Err(UnitClientError::UnitdDockerError {
+ message: "couldnt find new container".to_string(),
+ });
+ }
+ if info[0].names.is_none() || info[0].names.clone().unwrap().len() < 1 {
+ return Err(UnitClientError::UnitdDockerError {
+ message: "new container has no name".to_string(),
+ });
+ }
- match docker.start_container(
- info[0]
- .names
- .clone()
- .unwrap()[0]
- .strip_prefix("/")
- .unwrap(),
- None::<StartContainerOptions<String>>
- ).await {
- Err(err) => Err(UnitClientError::UnitdDockerError{message: err.to_string()}),
- Ok(_) => Ok(resp.warnings)
- }
+ match docker
+ .start_container(
+ info[0].names.clone().unwrap()[0].strip_prefix("/").unwrap(),
+ None::<StartContainerOptions<String>>,
+ )
+ .await
+ {
+ Err(err) => Err(UnitClientError::UnitdDockerError {
+ message: err.to_string(),
+ }),
+ Ok(_) => Ok(resp.warnings),
}
}
- },
- Err(e) => Err(UnitClientError::UnitdDockerError{message: e.to_string()})
+ }
+ }
+ Err(e) => Err(UnitClientError::UnitdDockerError { message: e.to_string() }),
}
}
@@ -372,7 +397,7 @@ mod tests {
assert_eq!(
ctr.rewrite_socket("unitd --no-daemon --control unix:/var/run/control.unit.sock".to_string()),
- "unitd --no-daemon --control unix:/tmp/control.unit.sock".to_string());
-
+ "unitd --no-daemon --control unix:/tmp/control.unit.sock".to_string()
+ );
}
}
diff --git a/tools/unitctl/unit-client-rs/src/unitd_instance.rs b/tools/unitctl/unit-client-rs/src/unitd_instance.rs
index 86f8e73d..a7fb1bdc 100644
--- a/tools/unitctl/unit-client-rs/src/unitd_instance.rs
+++ b/tools/unitctl/unit-client-rs/src/unitd_instance.rs
@@ -121,13 +121,10 @@ impl UnitdInstance {
Ok(_) if process.container.is_some() => {
let mut err = vec![];
// double check that it is running
- let running = process.container
- .as_ref()
- .unwrap()
- .container_is_running();
+ let running = process.container.as_ref().unwrap().container_is_running();
if running.is_none() || !running.unwrap() {
- err.push(UnitClientError::UnitdProcessParseError{
+ err.push(UnitClientError::UnitdProcessParseError {
message: "process container is not running".to_string(),
pid: process.process_id,
});
@@ -138,10 +135,8 @@ impl UnitdInstance {
configure_options: None,
errors: err,
}
- },
- Ok(unitd_path) => match UnitdConfigureOptions::new(
- &unitd_path.clone()
- .into_path_buf()) {
+ }
+ Ok(unitd_path) => match UnitdConfigureOptions::new(&unitd_path.clone().into_path_buf()) {
Ok(configure_options) => UnitdInstance {
process: process.to_owned(),
configure_options: Some(configure_options),
diff --git a/tools/unitctl/unitctl/src/cmd/instances.rs b/tools/unitctl/unitctl/src/cmd/instances.rs
index cd59b436..b9af75f6 100644
--- a/tools/unitctl/unitctl/src/cmd/instances.rs
+++ b/tools/unitctl/unitctl/src/cmd/instances.rs
@@ -1,16 +1,16 @@
-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 crate::{OutputFormat, UnitctlError};
use std::path::PathBuf;
+use unit_client_rs::unitd_docker::deploy_new_container;
+use unit_client_rs::unitd_instance::UnitdInstance;
pub(crate) async fn cmd(args: InstanceArgs) -> Result<(), UnitctlError> {
if let Some(cmd) = args.command {
match cmd {
- InstanceCommands::New{
+ InstanceCommands::New {
ref socket,
ref application,
- ref image
+ ref image,
} => {
println!("Pulling and starting a container from {}", image);
println!("Will mount {} to /var/run for socket access", socket);
@@ -20,15 +20,15 @@ pub(crate) async fn cmd(args: InstanceArgs) -> Result<(), UnitctlError> {
eprintln!("application and socket paths must be directories");
Err(UnitctlError::NoFilesImported)
} else {
- deploy_new_container(socket, application, image)
- .await
- .map_or_else(|e| Err(UnitctlError::UnitClientError{source: e}),
- |warn| {
- for i in warn {
- println!("warning from docker: {}", i);
- }
- Ok(())
- })
+ deploy_new_container(socket, application, image).await.map_or_else(
+ |e| Err(UnitctlError::UnitClientError { source: e }),
+ |warn| {
+ for i in warn {
+ println!("warning from docker: {}", i);
+ }
+ Ok(())
+ },
+ )
}
}
}
diff --git a/tools/unitctl/unitctl/src/main.rs b/tools/unitctl/unitctl/src/main.rs
index 9c42bdf0..12322873 100644
--- a/tools/unitctl/unitctl/src/main.rs
+++ b/tools/unitctl/unitctl/src/main.rs
@@ -30,9 +30,9 @@ async fn main() -> Result<(), UnitctlError> {
match cli.command {
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 eb7da1b0..b1bdbbd1 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, Args};
+use clap::{Args, Error as ClapError, Parser, Subcommand};
use std::path::PathBuf;
use unit_client_rs::control_socket_address::ControlSocket;
@@ -137,16 +137,10 @@ pub struct InstanceArgs {
pub enum InstanceCommands {
#[command(about = "deploy a new docker instance of unitd")]
New {
- #[arg(
- required = true,
- help = "Path to mount control socket to host",
- )]
+ #[arg(required = true, help = "Path to mount control socket to host")]
socket: String,
- #[arg(
- required = true,
- help = "Path to mount application into container",
- )]
+ #[arg(required = true, help = "Path to mount application into container")]
application: String,
#[arg(
@@ -154,7 +148,7 @@ pub enum InstanceCommands {
default_value = env!("CARGO_PKG_VERSION"),
)]
image: String,
- }
+ },
}
fn parse_control_socket_address(s: &str) -> Result<ControlSocket, ClapError> {