diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2021-03-09 10:48:06 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-09 10:48:06 +0100 |
commit | 2a79c695b7fceb7b7f1a9ebf336a2fcd03714a0a (patch) | |
tree | f8d87b5d99419cc13f98363e28bd42739df94318 | |
parent | 007b05eaf5127bbaea27cfc816f307946bd7aa5f (diff) | |
parent | 3667ae716733b26526f6c16d8312bc22129430d6 (diff) |
Merge pull request #267 from elihunter173/modules-match-endpoints
Split lib.rs, builder.rs, and rep.rs into endpoint-specific modules
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | examples/volumecreate.rs | 2 | ||||
-rw-r--r-- | src/builder.rs | 2249 | ||||
-rw-r--r-- | src/container.rs | 1563 | ||||
-rw-r--r-- | src/datetime.rs | 26 | ||||
-rw-r--r-- | src/docker.rs | 651 | ||||
-rw-r--r-- | src/errors.rs | 3 | ||||
-rw-r--r-- | src/exec.rs | 367 | ||||
-rw-r--r-- | src/image.rs | 884 | ||||
-rw-r--r-- | src/lib.rs | 1614 | ||||
-rw-r--r-- | src/network.rs | 395 | ||||
-rw-r--r-- | src/rep.rs | 820 | ||||
-rw-r--r-- | src/service.rs | 524 | ||||
-rw-r--r-- | src/volume.rs | 190 |
14 files changed, 4712 insertions, 4580 deletions
@@ -38,6 +38,10 @@ tar = "0.4" tokio = "1.0" url = "2.1" +# XXX: This is a temporary dependency for the reexport! macro in lib.rs. Remove +# me before 0.9.0 is released. +paste = "1.0" + [dev-dependencies] env_logger = "0.8" # Required for examples to run diff --git a/examples/volumecreate.rs b/examples/volumecreate.rs index 95bc575..a95bb12 100644 --- a/examples/volumecreate.rs +++ b/examples/volumecreate.rs @@ -1,4 +1,4 @@ -use shiplift::{builder::VolumeCreateOptions, Docker}; +use shiplift::{Docker, VolumeCreateOptions}; use std::{collections::HashMap, env}; #[tokio::main] diff --git a/src/builder.rs b/src/builder.rs deleted file mode 100644 index 01a2d76..0000000 --- a/src/builder.rs +++ /dev/null @@ -1,2249 +0,0 @@ -//! Interfaces for building various structures - -use crate::{ - errors::Error, - rep::{EndpointSpec, Mode, NetworkAttachmentConfig, RollbackConfig, TaskSpec, UpdateConfig}, - Result, -}; -use serde::Serialize; -use serde_json::{self, json, map::Map, Value}; -use std::{ - cmp::Eq, - collections::{BTreeMap, HashMap}, - hash::Hash, - iter::{IntoIterator, Iterator, Peekable}, - time::Duration, -}; -use url::form_urlencoded; - -#[derive(Clone, Serialize, Debug)] -#[serde(untagged)] -pub enum RegistryAuth { - Password { - username: String, - password: String, - - #[serde(skip_serializing_if = "Option::is_none")] - email: Option<String>, - - #[serde(rename = "serveraddress")] - #[serde(skip_serializing_if = "Option::is_none")] - server_address: Option<String>, - }, - Token { - #[serde(rename = "identitytoken")] - identity_token: String, - }, -} - -impl RegistryAuth { - /// return a new instance with token authentication - pub fn token<S>(token: S) -> RegistryAuth - where - S: Into<String>, - { - RegistryAuth::Token { - identity_token: token.into(), - } - } - - /// return a new instance of a builder for authentication - pub fn builder() -> RegistryAuthBuilder { - RegistryAuthBuilder::default() - } - - /// serialize authentication as JSON in base64 - pub fn serialize(&self) -> String { - serde_json::to_string(self) - .map(|c| base64::encode_config(&c, base64::URL_SAFE)) - .unwrap() - } -} - -#[derive(Default)] -pub struct RegistryAuthBuilder { - username: Option<String>, - password: Option<String>, - email: Option<String>, - server_address: Option<String>, -} - -impl RegistryAuthBuilder { - pub fn username<I>( - &mut self, - username: I, - ) -> &mut Self - where - I: Into<String>, - { - self.username = Some(username.into()); - self - } - - pub fn password<I>( - &mut self, - password: I, - ) -> &mut Self - where - I: Into<String>, - { - self.password = Some(password.into()); - self - } - - pub fn email<I>( - &mut self, - email: I, - ) -> &mut Self - where - I: Into<String>, - { - self.email = Some(email.into()); - self - } - - pub fn server_address<I>( - &mut self, - server_address: I, - ) -> &mut Self - where - I: Into<String>, - { - self.server_address = Some(server_address.into()); - self - } - - pub fn build(&self) -> RegistryAuth { - RegistryAuth::Password { - username: self.username.clone().unwrap_or_else(String::new), - password: self.password.clone().unwrap_or_else(String::new), - email: self.email.clone(), - server_address: self.server_address.clone(), - } - } -} - -#[derive(Default, Debug)] -pub struct TagOptions { - pub params: HashMap<&'static str, String>, -} - -impl TagOptions { - /// return a new instance of a builder for options - pub fn builder() -> TagOptionsBuilder { - TagOptionsBuilder::default() - } - - /// serialize options as a string. returns None if no options are defined - pub fn serialize(&self) -> Option<String> { - if self.params.is_empty() { - None - } else { - Some( - form_urlencoded::Serializer::new(String::new()) - .extend_pairs(&self.params) - .finish(), - ) - } - } -} - -#[derive(Default)] -pub struct TagOptionsBuilder { - params: HashMap<&'static str, String>, -} - -impl TagOptionsBuilder { - pub fn repo<R>( - &mut self, - r: R, - ) -> &mut Self - where - R: Into<String>, - { - self.params.insert("repo", r.into()); - self - } - - pub fn tag<T>( - &mut self, - t: T, - ) -> &mut Self - where - T: Into<String>, - { - self.params.insert("tag", t.into()); - self - } - - pub fn build(&self) -> TagOptions { - TagOptions { - params: self.params.clone(), - } - } -} - -#[derive(Default, Debug)] -pub struct PullOptions { - auth: Option<RegistryAuth>, - params: HashMap<&'static str, String>, -} - -impl PullOptions { - /// return a new instance of a builder for options - pub fn builder() -> PullOptionsBuilder { - PullOptionsBuilder::default() - } - - /// serialize options as a string. returns None if no options are defined - pub fn serialize(&self) -> Option<String> { - if self.params.is_empty() { - None - } else { - Some( - form_urlencoded::Serializer::new(String::new()) - .extend_pairs(&self.params) - .finish(), - ) - } - } - - pub(crate) fn auth_header(&self) -> Option<String> { - self.auth.clone().map(|a| a.serialize()) - } -} - -#[derive(Default)] -pub struct PullOptionsBuilder { - auth: Option<RegistryAuth>, - params: HashMap<&'static str, String>, -} - -impl PullOptionsBuilder { - /// Name of the image to pull. The name may include a tag or digest. - /// This parameter may only be used when pulling an image. - /// If an untagged value is provided and no `tag` is provided, _all_ - /// tags will be pulled - /// The pull is cancelled if the HTTP connection is closed. - pub fn image<I>( - &mut self, - img: I, - ) -> &mut Self - where - I: Into<String>, - { - self.params.insert("fromImage", img.into()); - self - } - - pub fn src<S>( - &mut self, - s: S, - ) -> &mut Self - where - S: Into<String>, - { - self.params.insert("fromSrc", s.into()); - self - } - - /// Repository name given to an image when it is imported. The repo may include a tag. - /// This parameter may only be used when importing an image. - pub fn repo<R>( - &mut self, - r: R, - ) -> &mut Self - where - R: Into<String>, - { - self.params.insert("repo", r.into()); - self - } - - /// Tag or digest. If empty when pulling an image, - /// this causes all tags for the given image to be pulled. - pub fn tag<T>( - &mut self, - t: T, - ) -> &mut Self - where - T: Into<String>, - { - self.params.insert("tag", t.into()); - self - } - - pub fn auth( - &mut self, - auth: RegistryAuth, - ) -> &mut Self { - self.auth = Some(auth); - self - } - - pub fn build(&mut self) -> PullOptions { - PullOptions { - auth: self.auth.take(), - params: self.params.clone(), - } - } -} - -#[derive(Default, Debug)] -pub struct BuildOptions { - pub path: String, - params: HashMap<&'static str, String>, -} - -impl BuildOptions { - /// return a new instance of a builder for options - /// path is expected to be a file path to a directory containing a Dockerfile - /// describing how to build a Docker image - pub fn builder<S>(path: S) -> BuildOptionsBuilder - where - S: Into<String>, - { - BuildOptionsBuilder::new(path) - } - - /// serialize options as a string. returns None if no options are defined - pub fn serialize(&self) -> Option<String> { - if self.params.is_empty() { - None - } else { - Some( - form_urlencoded::Serializer::new(String::new()) - .extend_pairs(&self.params) - .finish(), - ) - } - } -} - -#[derive(Default)] -pub struct BuildOptionsBuilder { - path: String, - params: HashMap<&'static str, String>, -} - -impl BuildOptionsBuilder { - /// path is expected to be a file path to a directory containing a Dockerfile - /// describing how to build a Docker image - pub(crate) fn new<S>(path: S) -> Self - where - S: Into<String>, - { - BuildOptionsBuilder { - path: path.into(), - ..Default::default() - } - } - - /// set the name of the docker file. defaults to "DockerFile" - pub fn dockerfile<P>( - &mut self, - path: P, - ) -> &mut Self - where - P: Into<String>, - { - self.params.insert("dockerfile", path.into()); - self - } - - /// tag this image with a name after building it - pub fn tag<T>( - &mut self, - t: T, - ) -> &mut Self - where - T: Into<String>, - { - self.params.insert("t", t.into()); - self - } - - pub fn remote<R>( - &mut self, - r: R, - ) -> &mut Self - where - R: Into<String>, - { - self.params.insert("remote", r.into()); - self - } - - /// don't use the image cache when building image - pub fn nocache( - &mut self, - nc: bool, - ) -> &mut Self { - self.params.insert("nocache", nc.to_string()); - self - } - - pub fn rm( - &mut self, - r: bool, - ) -> &mut Self { - self.params.insert("rm", r.to_string()); - self - } - - pub fn forcerm( - &mut self, - fr: bool, - ) -> &mut Self { - self.params.insert("forcerm", fr.to_string()); - self - } - - /// `bridge`, `host`, `none`, `container:<name|id>`, or a custom network name. - pub fn network_mode<T>( - &mut self, - t: T, - ) -> &mut Self - where - T: Into<String>, - { - self.params.insert("networkmode", t.into()); - self - } - - pub fn memory( - &mut self, - memory: u64, - ) -> &mut Self { - self.params.insert("memory", memory.to_string()); - self - } - - pub fn cpu_shares( - &mut self, - cpu_shares: u32, - ) -> &mut Self { - self.params.insert("cpushares", cpu_shares.to_string()); - self - } - - // todo: memswap - // todo: cpusetcpus - // todo: cpuperiod - // todo: cpuquota - // todo: buildargs - - pub fn build(&self) -> BuildOptions { - BuildOptions { - path: self.path.clone(), - params: self.params.clone(), - } - } -} - -/// Options for filtering container list results -#[derive(Default, Debug)] -pub struct ContainerListOptions { - params: HashMap<&'static str, String>, -} - -impl ContainerListOptions { - /// return a new instance of a builder for options - pub fn builder() -> ContainerListOptionsBuilder { - ContainerListOptionsBuilder::default() - } - - /// serialize options as a string. returns None if no options are defined - pub fn serialize(&self) -> Option<String> { - if self.params.is_empty() { - None - } else { - Some( - form_urlencoded::Serializer::new(String::new()) - .extend_pairs(&self.params) - .finish(), - ) - } - } -} - -/// Filter options for container listings -pub enum ContainerFilter { - ExitCode(u64), - Status(String), - LabelName(String), - Label(String, String), -} - -/// Builder interface for `ContainerListOptions` -#[derive(Default)] -pub struct ContainerListOptionsBuilder { - params: HashMap<&'static str, String>, -} - -impl ContainerListOptionsBuilder { - pub fn filter( - &mut self, - filters: Vec<ContainerFilter>, - ) -> &mut Self { - let mut param = HashMap::new(); - for f in filters { - match f { - ContainerFilter::ExitCode(c) => param.insert("exit", vec![c.to_string()]), - ContainerFilter::Status(s) => param.insert("status", vec![s]), - ContainerFilter::LabelName(n) => param.insert("label", vec![n]), - ContainerFilter::Label(n, v) => param.insert("label", vec![format!("{}={}", n, v)]), - }; - } - // structure is a a json encoded object mapping string keys to a list - // of string values - self.params - .insert("filters", serde_json::to_string(¶m).unwrap()); - self - } - - pub fn all(&mut self) -> &mut Self { - self.params.insert("all", "true".to_owned()); - self - } - - pub fn since( - &mut self, - since: &str, - ) -> &mut Self { - self.params.insert("since", since.to_owned()); - self - } - - pub fn before( - &mut self, - before: &str, - ) -> &mut Self { - self.params.insert("before", before.to_owned()); - self - } - - pub fn sized(&mut self) -> &mut Self { - self.params.insert("size", "true".to_owned()); - self - } - - pub fn build(&self) -> ContainerListOptions { - ContainerListOptions { - params: self.params.clone(), - } - } -} - -/// Interface for building a new docker container from an existing image -#[derive(Serialize, Debug)] -pub struct ContainerOptions { - pub name: Option<String>, - params: HashMap<&'static str, Value>, -} - -/// Function to insert a JSON value into a tree where the desired -/// location of the value is given as a path of JSON keys. -fn insert<'a, I, V>( - key_path: &mut Peekable<I>, - value: &V, - parent_node: &mut Value, -) where - V: Serialize, - I: Iterator<Item = &'a str>, -{ - let local_key = key_path.next().unwrap(); - - if key_path.peek().is_some() { - let node = parent_node - .as_object_mut() - .unwrap() - .entry(local_key.to_string()) - .or_insert(Value::Object(Map::new())); - - insert(key_path, value, node); - } else { - parent_node - .as_object_mut() - .unwrap() - .insert(local_key.to_string(), serde_json::to_value(value).unwrap()); - } -} - -impl ContainerOptions { - /// return a new instance of a builder for options - pub fn builder(name: &str) -> ContainerOptionsBuilder { - ContainerOptionsBuilder::new(name) - } - - /// serialize options as a string. returns None if no options are defined - pub fn serialize(&self) -> Result<String> { - serde_json::to_string(&self.to_json()).map_err(Error::from) - } - - fn to_json(&self) -> Value { - let mut body_members = Map::new(); - // The HostConfig element gets initialized to an empty object, - // for backward compatibility. - body_members.insert("HostConfig".to_string(), Value::Object(Map::new())); - let mut body = Value::Object(body_members); - self.parse_from(&self.params, &mut body); - body - } - - pub fn parse_from<'a, K, V>( - &self, - params: &'a HashMap<K, V>, - body: &mut Value, - ) where - &'a HashMap<K, V>: IntoIterator, - K: ToString + Eq + Hash, - V: Serialize, - { - for (k, v) in params.iter() { - let key_string = k.to_string(); - insert(&mut key_string.split('.').peekable(), v, body) - } - } -} - -#[derive(Default)] -pub struct ContainerOptionsBuilder { - name: Option<String>, - params: HashMap<&'static str, Value>, -} - -impl ContainerOptionsBuilder { - pub(crate) fn new(image: &str) -> Self { - let mut params = HashMap::new(); - - params.insert("Image", Value::String(image.to_owned())); - ContainerOptionsBuilder { name: None, params } - } - - pub fn name( - &mut self, - name: &str, - ) -> &mut Self { - self.name = Some(name.to_owned()); - self - } - - /// Specify the working dir (corresponds to the `-w` docker cli argument) - pub fn working_dir( - &mut self, - working_dir: &str, - ) -> &mut Self { - self.params.insert("WorkingDir", json!(working_dir)); - self - } - - /// Specify any bind mounts, taking the form of `/some/host/path:/some/container/path` - pub fn volumes( - &mut self, - volumes: Vec<&str>, - ) -> &mut Self { - self.params.insert("HostConfig.Binds", json!(volumes)); - self - } - - /// enable all exposed ports on the container to be mapped to random, available, ports on the host - pub fn publish_all_ports(&mut self) -> &mut Self { - self.params - .insert("HostConfig.PublishAllPorts", json!(true)); - self - } - - pub fn expose( - &mut self, - srcport: u32, - protocol: &str, - hostport: u32, - ) -> &mut Self { - let mut exposedport: HashMap<String, String> = HashMap::new(); - exposedport.insert("HostPort".to_string(), hostport.to_string()); - - /* The idea here is to go thought the 'old' port binds - * and to apply them to the local 'port_bindings' variable, - * add the bind we want and replace the 'old' value */ - let mut port_bindings: HashMap<String, Value> = HashMap::new(); - for (key, val) in self - .params - .get("HostConfig.PortBindings") - .unwrap_or(&json!(null)) - .as_object() - .unwrap_or(&Map::new()) - .iter() - { - port_bindings.insert(key.to_string(), json!(val)); - } - port_bindings.insert( - format!("{}/{}", srcport, protocol), - json!(vec![exposedport]), - ); - - self.params - .insert("HostConfig.PortBindings", json!(port_bindings)); - - // Replicate the port bindings over to the exposed ports config - let mut exposed_ports: HashMap<String, Value> = HashMap::new(); - let empty_config: HashMap<String, Value> = HashMap::new(); - for key in port_bindings.keys() { - exposed_ports.insert(key.to_string(), json!(empty_config)); - } - - self.params.insert("ExposedPorts", json!(exposed_ports)); - - self - } - - /// Publish a port in the container without assigning a port on the host - pub fn publish( - &mut self, - srcport: u32, - protocol: &str, - ) -> &mut Self { - /* The idea here is to go thought the 'old' port binds - * and to apply them to the local 'exposedport_bindings' variable, - * add the bind we want and replace the 'old' value */ - let mut exposed_port_bindings: HashMap<String, Value> = HashMap::new(); - for (key, val) in self - .params - .get("ExposedPorts") - .unwrap_or(&json!(null)) - .as_object() - .unwrap_or(&Map::new()) - .iter() - { - exposed_port_bindings.insert(key.to_string(), json!(val)); - } - exposed_port_bindings.insert(format!("{}/{}", srcport, protocol), json!({})); - - // Replicate the port bindings over to the exposed ports config - let mut exposed_ports: HashMap<String, Value> = HashMap::new(); - let empty_config: HashMap<String, Value> = HashMap::new(); - for key in exposed_port_bindings.keys() { - exposed_ports.insert(key.to_string(), json!(empty_config)); - } - - self.params.insert("ExposedPorts", json!(exposed_ports)); - - self - } - - pub fn links( - &mut self, - links: Vec<&str>, - ) -> &mut Self { - self.params.insert("HostConfig.Links", json!(links)); - self - } - - pub fn memory( - &mut self, - memory: u64, - ) -> &mut Self { - self.params.insert("HostConfig.Memory", json!(memory)); - self - } - - /// Total memory limit (memory + swap) in bytes. Set to -1 (default) to enable unlimited swap. - pub fn memory_swap( - &mut self, - memory_swap: i64, - ) -> &mut Self { - self.params - .insert("HostConfig.MemorySwap", json!(memory_swap)); - self - } - - /// CPU quota in units of 10<sup>-9</sup> CPUs. Set to 0 (default) for there to be no limit. - /// - /// For example, setting `nano_cpus` to `500_000_000` results in the container being allocated - /// 50% of a single CPU, while `2_000_000_000` results in the container being allocated 2 CPUs. - pub fn nano_cpus( - &mut self, - nano_cpus: u64, - ) -> &mut Self { - self.params.insert("HostConfig.NanoCpus", json!(nano_cpus)); - self - } - - /// CPU quota in units of CPUs. This is a wrapper around `nano_cpus` to do the unit conversion. - /// - /// See [`nano_cpus`](#method.nano_cpus). - pub fn cpus( - &mut self, - cpus: f64, - ) -> &mut Self { - self.nano_cpus((1_000_000_000.0 * cpus) as u64) - } - - /// Sets an integer value representing the container's relative CPU weight versus other - /// containers. - pub fn cpu_shares( - &mut self, - cpu_shares: u32, - ) -> &mut Self { - self.params - .insert("HostConfig.CpuShares", json!(cpu_shares)); - self - } - - pub fn labels( - &mut self, - labels: &HashMap<&str, &str>, - ) -> &mut Self { - self.params.insert("Labels", json!(labels)); - self - } - - /// Whether to attach to `stdin`. - pub fn attach_stdin( - &mut self, - attach: bool, - ) -> &mut Self { - self.params.insert("AttachStdin", json!(attach)); - self.params.insert("OpenStdin", json!(attach)); - self - } - - /// Whether to attach to `stdout`. - pub fn attach_stdout( - &mut self, - attach: bool, - ) -> &mut Self { - self.params.insert("AttachStdout", json!(attach)); - self - } - - /// Whether to attach to `stderr`. - pub fn attach_stderr( - &mut self, - attach: bool, - ) -> &mut Self { - self.params.insert("AttachStderr", json!(attach)); - self - } - - /// Whether standard streams should be attached to a TTY. - pub fn tty( - &mut self, - tty: bool, - ) -> &mut Self { - self.params.insert("Tty", json!(tty)); - self - } - - pub fn extra_hosts( - &mut self, - hosts: Vec<&str>, - ) -> &mut Self { - self.params.insert("HostConfig.ExtraHosts", json!(hosts)); - self - } - - pub fn volumes_from( - &mut self, - volumes: Vec<&str>, - ) -> &mut Self { - self.params.insert("HostConfig.VolumesFrom", json!(volumes)); - self - } - - pub fn network_mode( - &mut self, - network: &str, - ) -> &mut Self { - self.params.insert("HostConfig.NetworkMode", json!(network)); - self - } - - pub fn env<E, S>( - &mut self, - envs: E, - ) -> &mut Self - where - S: AsRef<str> + Serialize, - E: AsRef<[S]> + Serialize, - { - self.params.insert("Env", json!(envs)); - self - } - - pub fn cmd( - &mut self, - cmds: Vec<&str>, - ) -> &mut Self { - self.params.insert("Cmd", json!(cmds)); - self - } - - pub fn entrypoint<I, S>( - &mut self, - entrypoint: I, - ) -> &mut Self - where - I: IntoIterator<Item = S> + Serialize, - S: AsRef<str>, - { - self.params.insert("Entrypoint", json!(entrypoint)); - self - } - - pub fn capabilities( - &mut self, - capabilities: Vec<&str>, - ) -> &mut Self { - self.params.insert("HostConfig.CapAdd", json!(capabilities)); - self - } - - pub fn devices( - &mut self, - devices: Vec<HashMap<String, String>>, - ) -> &mut Self { - self.params.insert("HostConfig.Devices", json!(devices)); - self - } - - pub fn log_driver( - &mut self, - log_driver: &str, - ) -> &mut Self { - self.params - .insert("HostConfig.LogConfig.Type", json!(log_driver)); - self - } - - pub fn restart_policy( - &mut self, - name: &str, - maximum_retry_count: u64, - ) -> &mut Self { - self.params - .insert("HostConfig.RestartPolicy.Name", json!(name)); - if name == "on-failure" { - self.params.insert( - "HostConfig.RestartPolicy.MaximumRetryCount", - json!(maximum_retry_count), - ); - } - self - } - - pub fn auto_remove( - &mut self, - set: bool, - ) -> &mut Self { - self.params.insert("HostConfig.AutoRemove", json!(set)); - self - } - - /// Signal to stop a container as a string. Default is "SIGTERM". - pub fn stop_signal( - &mut self, - sig: &str, - ) -> &mut Self { - self.params.insert("StopSignal", json!(sig)); - self - } - - /// Signal to stop a container as an integer. Default is 15 (SIGTERM). - pub fn stop_signal_num( - &mut self, - sig: u64, - ) -> &mut Self { - self.params.insert("StopSignal", json!(sig)); - self - } - - /// Timeout to stop a container. Only seconds are counted. Default is 10s - pub fn stop_timeout( - &mut self, - timeout: Duration, - ) -> &mut Self { - self.params.insert("StopTimeout", json!(timeout.as_secs())); - self - } - - pub fn userns_mode( - &mut self, - mode: &str, - ) -> &mut Self { - self.params.insert("HostConfig.UsernsMode", json!(mode)); - self - } - - pub fn privileged( - &mut self, - set: bool, - ) -> &mut Self { - self.params.insert("HostConfig.Privileged", json!(set)); - self - } - - pub fn user( - &mut self, - user: &str, - ) -> &mut Self { - self.params.insert("User", json!(user)); - self - } - - pub fn build(&self) -> ContainerOptions { - ContainerOptions { - name: self.name.clone(), - params: self.params.clone(), - } - } -} - -#[derive(Serialize, Debug)] -pub struct ExecContainerOptions { - params: HashMap<&'static str, Vec<String>>, - params_bool: HashMap<&'static str, bool>, -} - -impl ExecContainerOptions { - /// return a new instance of a builder for options - pub fn builder() -> ExecContainerOptionsBuilder { - ExecContainerOptionsBuilder::default() - } - - /// serialize options as a string. returns None if no options are defined - pub fn serialize(&self) -> Result<String> { - let mut body = serde_json::Map::new(); - - for (k, v) in &self.params { - body.insert( - (*k).to_owned(), - serde_json::to_value(v).map_err(Error::SerdeJsonError)?, - ); - } - - for (k, v) in &self.params_bool { - body.insert( - (*k).to_owned(), - serde_json::to_value(v).map_err(Error::SerdeJsonError)?, - ); - } - - serde_json::to_string(&body).map_err(Error::from) - } -} - -#[derive(Default)] -pub struct ExecContainerOptionsBuilder { - params: HashMap<&'static str, Vec<String>>, - params_bool: HashMap<&'static str, bool>, -} - -impl ExecContainerOptionsBuilder { - /// Command to run, as an array of strings - pub fn cmd( - &mut self, - cmds: Vec<&str>, - ) -> &mut Self { - for cmd in cmds { - self.params - .entry("Cmd") - .or_insert_with(Vec::new) |