diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/container.rs | 152 | ||||
-rw-r--r-- | src/exec.rs | 10 | ||||
-rw-r--r-- | src/image.rs | 24 | ||||
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/network.rs | 16 | ||||
-rw-r--r-- | src/volume.rs | 56 |
6 files changed, 194 insertions, 68 deletions
diff --git a/src/container.rs b/src/container.rs index ec2033d..ad26238 100644 --- a/src/container.rs +++ b/src/container.rs @@ -20,7 +20,7 @@ use crate::{ errors::{Error, Result}, exec::{Exec, ExecContainerOptions}, image::Config, - network::{NetworkInfo, NetworkSettings}, + network::NetworkSettings, transport::Payload, tty::{self, Multiplexer as TtyMultiPlexer}, }; @@ -32,7 +32,7 @@ use chrono::{DateTime, Utc}; /// Interface for accessing and manipulating a docker container /// -/// Api Reference: <https://docs.docker.com/engine/api/v1.41/#tag/Container> +/// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Container) pub struct Container<'docker> { docker: &'docker Docker, id: String, @@ -60,7 +60,7 @@ impl<'docker> Container<'docker> { /// Inspects the current docker container instance's details /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerInspect> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerInspect) pub async fn inspect(&self) -> Result<ContainerDetails> { self.docker .get_json::<ContainerDetails>(&format!("/containers/{}/json", self.id)[..]) @@ -69,7 +69,7 @@ impl<'docker> Container<'docker> { /// Returns a `top` view of information about the container process /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerTop> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerTop) pub async fn top( &self, psargs: Option<&str>, @@ -86,7 +86,7 @@ impl<'docker> Container<'docker> { /// Returns a stream of logs emitted but the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerLogs> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerLogs) pub fn logs( &self, opts: &LogsOptions, @@ -114,13 +114,15 @@ impl<'docker> Container<'docker> { .await } - /// Attaches a `[TtyMultiplexer]` to the container. + /// Attaches a [Multiplexer](crate::tty::Multiplexer) to the container. /// - /// The `[TtyMultiplexer]` implements Stream for returning Stdout and Stderr chunks. It also implements `[AsyncWrite]` for writing to Stdin. + /// The [Multiplexer](crate::tty::Multiplexer) implements Stream for returning Stdout and + /// Stderr chunks. It also implements `[AsyncWrite]` for writing to Stdin. /// - /// The multiplexer can be split into its read and write halves with the `[split](TtyMultiplexer::split)` method + /// The multiplexer can be split into its read and write halves with the + /// [split](crate::tty::Multiplexer::split) method /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerAttach> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerAttach) pub async fn attach(&self) -> Result<TtyMultiPlexer<'docker>> { let tcp_stream = self.attach_raw().await?; @@ -129,7 +131,7 @@ impl<'docker> Container<'docker> { /// Returns a set of changes made to the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerChanges> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerChanges) pub async fn changes(&self) -> Result<Vec<Change>> { self.docker .get_json::<Vec<Change>>(&format!("/containers/{}/changes", self.id)[..]) @@ -138,7 +140,7 @@ impl<'docker> Container<'docker> { /// Exports the current docker container into a tarball /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerExport> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerExport) pub fn export(&self) -> impl Stream<Item = Result<Vec<u8>>> + 'docker { self.docker .stream_get(format!("/containers/{}/export", self.id)) @@ -147,7 +149,7 @@ impl<'docker> Container<'docker> { /// Returns a stream of stats specific to this container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerStats> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerStats) pub fn stats(&self) -> impl Stream<Item = Result<Stats>> + Unpin + 'docker { let codec = futures_codec::LinesCodec {}; @@ -169,7 +171,7 @@ impl<'docker> Container<'docker> { /// Start the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerStart> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerStart) pub async fn start(&self) -> Result<()> { self.docker .post(&format!("/containers/{}/start", self.id)[..], None) @@ -179,7 +181,7 @@ impl<'docker> Container<'docker> { /// Stop the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerStop> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerStop) pub async fn stop( &self, wait: Option<Duration>, @@ -198,7 +200,7 @@ impl<'docker> Container<'docker> { /// Restart the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerRestart> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerRestart) pub async fn restart( &self, wait: Option<Duration>, @@ -216,7 +218,7 @@ impl<'docker> Container<'docker> { /// Kill the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerKill> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerKill) pub async fn kill( &self, signal: Option<&str>, @@ -234,7 +236,7 @@ impl<'docker> Container<'docker> { /// Rename the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerRename> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerRename) pub async fn rename( &self, name: &str, @@ -253,7 +255,7 @@ impl<'docker> Container<'docker> { /// Pause the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerPause> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerPause) pub async fn pause(&self) -> Result<()> { self.docker .post(&format!("/containers/{}/pause", self.id)[..], None) @@ -263,7 +265,7 @@ impl<'docker> Container<'docker> { /// Unpause the container instance /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerUnpause> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerUnpause) pub async fn unpause(&self) -> Result<()> { self.docker .post(&format!("/containers/{}/unpause", self.id)[..], None) @@ -273,7 +275,7 @@ impl<'docker> Container<'docker> { /// Wait until the container stops /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerWait> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerWait) pub async fn wait(&self) -> Result<Exit> { self.docker .post_json(format!("/containers/{}/wait", self.id), Payload::None) @@ -284,7 +286,7 @@ impl<'docker> Container<'docker> { /// /// Use remove instead to use the force/v options. /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerDelete> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerDelete) pub async fn delete(&self) -> Result<()> { self.docker .delete(&format!("/containers/{}", self.id)[..]) @@ -294,7 +296,7 @@ impl<'docker> Container<'docker> { /// Delete the container instance (todo: force/v) /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerRemove> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerRemove) pub async fn remove( &self, opts: RmContainerOptions, @@ -309,7 +311,7 @@ impl<'docker> Container<'docker> { /// Execute a command in this container /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#tag/Exec> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Exec) pub fn exec( &self, opts: &ExecContainerOptions, @@ -326,7 +328,7 @@ impl<'docker> Container<'docker> { /// ends in `/.` then this indicates that only the contents of the path directory should be /// copied. A symlink is always resolved to its target. /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerArchive> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerArchive) pub fn copy_from( &self, path: &Path, @@ -344,7 +346,7 @@ impl<'docker> Container<'docker> { /// The file will be copied at the given location (see `path`) and will be owned by root /// with access mask 644. /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/PutContainerArchive> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/PutContainerArchive) pub async fn copy_file_into<P: AsRef<Path>>( &self, path: P, @@ -374,7 +376,7 @@ impl<'docker> Container<'docker> { /// /// The tarball will be copied to the container and extracted at the given location (see `path`). /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/PutContainerArchive> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/PutContainerArchive) pub async fn copy_to( &self, path: &Path, @@ -398,7 +400,7 @@ impl<'docker> Container<'docker> { /// Interface for docker containers /// -/// Api Reference: <https://docs.docker.com/engine/api/v1.41/#tag/Containers> +/// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Containers) pub struct Containers<'docker> { docker: &'docker Docker, } @@ -411,7 +413,7 @@ impl<'docker> Containers<'docker> { /// Lists the container instances on the docker host /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerList> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerList) pub async fn list( &self, opts: &ContainerListOptions, @@ -490,6 +492,7 @@ pub enum ContainerFilter { Status(String), LabelName(String), Label(String, String), + Name(String), } /// Builder interface for `ContainerListOptions` @@ -503,14 +506,17 @@ impl ContainerListOptionsBuilder { &mut self, filters: Vec<ContainerFilter>, ) -> &mut Self { - let mut param = HashMap::new(); + let mut param: HashMap<&str, Vec<String>> = 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)]), + let (key, value) = match f { + ContainerFilter::ExitCode(c) => ("exited", c.to_string()), + ContainerFilter::Status(s) => ("status", s), + ContainerFilter::LabelName(n) => ("label", n), + ContainerFilter::Label(n, v) => ("label", format!("{}={}", n, v)), + ContainerFilter::Name(n) => ("name", n.to_string()), }; + + param.entry(key).or_insert_with(Vec::new).push(value); } // structure is a a json encoded object mapping string keys to a list // of string values @@ -1287,13 +1293,25 @@ pub struct Port { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Stats { pub read: String, - pub networks: HashMap<String, NetworkInfo>, + pub networks: HashMap<String, NetworkStats>, pub memory_stats: MemoryStats, pub blkio_stats: BlkioStats, pub cpu_stats: CpuStats, } #[derive(Clone, Debug, Serialize, Deserialize)] +pub struct NetworkStats { + pub rx_dropped: u64, + pub rx_bytes: u64, + pub rx_errors: u64, + pub tx_packets: u64, + pub tx_dropped: u64, + pub rx_packets: u64, + pub tx_errors: u64, + pub tx_bytes: u64, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct MemoryStats { pub max_usage: u64, pub usage: u64, @@ -1408,6 +1426,7 @@ pub struct Exit { #[cfg(test)] mod tests { use super::*; + use crate::container::ContainerFilter::{ExitCode, Label, LabelName, Status}; #[test] fn container_options_simple() { @@ -1561,6 +1580,69 @@ mod tests { ); } + #[test] + fn container_list_options_multiple_labels() { + let options = ContainerListOptions::builder() + .filter(vec![ + Label("label1".to_string(), "value".to_string()), + LabelName("label2".to_string()), + ]) + .build(); + + let form = form_urlencoded::Serializer::new(String::new()) + .append_pair("filters", r#"{"label":["label1=value","label2"]}"#) + .finish(); + + assert_eq!(form, options.serialize().unwrap()) + } + + #[test] + fn container_list_options_exit_code() { + let options = ContainerListOptions::builder() + .filter(vec![ExitCode(0)]) + .build(); + + let form = form_urlencoded::Serializer::new(String::new()) + .append_pair("filters", r#"{"exited":["0"]}"#) + .finish(); + + assert_eq!(form, options.serialize().unwrap()) + } + + #[test] + fn container_list_options_status() { + let options = ContainerListOptions::builder() + .filter(vec![Status("running".to_string())]) + .build(); + + let form = form_urlencoded::Serializer::new(String::new()) + .append_pair("filters", r#"{"status":["running"]}"#) + .finish(); + + assert_eq!(form, options.serialize().unwrap()) + } + + #[test] + fn container_list_options_combined() { + let options = ContainerListOptions::builder() + .all() + .filter(vec![ + Label("label1".to_string(), "value".to_string()), + LabelName("label2".to_string()), + ExitCode(0), + Status("running".to_string()), + ]) + .build(); + + let serialized = options.serialize().unwrap(); + + assert!(serialized.contains("all=true")); + assert!(serialized.contains("filters=")); + assert!(serialized.contains("%22label%22%3A%5B%22label1%3Dvalue%22%2C%22label2%22%5D")); + assert!(serialized.contains("%22status%22%3A%5B%22running%22%5D")); + assert!(serialized.contains("%22exited%22%3A%5B%220%22%5D")); + } + #[cfg(feature = "chrono")] #[test] fn logs_options() { diff --git a/src/exec.rs b/src/exec.rs index 2f512a9..2eedb7b 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -20,7 +20,7 @@ use crate::{ /// Interface for docker exec instance /// -/// Api Reference: <https://docs.docker.com/engine/api/v1.41/#tag/Exec> +/// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Exec) pub struct Exec<'docker> { docker: &'docker Docker, id: String, @@ -42,7 +42,7 @@ impl<'docker> Exec<'docker> { /// Creates a new exec instance that will be executed in a container with id == container_id /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ContainerExec> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerExec) pub async fn create( docker: &'docker Docker, container_id: &str, @@ -137,7 +137,7 @@ impl<'docker> Exec<'docker> { /// Starts this exec instance returning a multiplexed tty stream /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ExecStart> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ExecStart) pub fn start(&self) -> impl Stream<Item = Result<tty::TtyChunk>> + 'docker { // We must take ownership of the docker reference to not needlessly tie the stream to the // lifetime of `self`. @@ -161,7 +161,7 @@ impl<'docker> Exec<'docker> { /// Inspect this exec instance to aquire detailed information /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ExecInpsect> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ExecInpsect) pub async fn inspect(&self) -> Result<ExecDetails> { self.docker .get_json(&format!("/exec/{}/json", &self.id)[..]) @@ -171,7 +171,7 @@ impl<'docker> Exec<'docker> { /// Resize the TTY session used by an exec instance. This only works if the exec was created /// with `tty` enabled. /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ExecResize> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ExecResize) pub async fn resize( &self, opts: &ExecResizeOptions, diff --git a/src/image.rs b/src/image.rs index e69f85a..addf4ee 100644 --- a/src/image.rs +++ b/src/image.rs @@ -19,7 +19,7 @@ use chrono::{DateTime, Utc}; /// Interface for accessing and manipulating a named docker image /// -/// Api Reference: <https://docs.docker.com/engine/api/v1.41/#tag/Image> +/// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Image) pub struct Image<'docker> { docker: &'docker Docker, name: String, @@ -42,7 +42,7 @@ impl<'docker> Image<'docker> { /// Inspects a named image's details /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageInspect> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageInspect) pub async fn inspect(&self) -> Result<ImageDetails> { self.docker .get_json(&format!("/images/{}/json", self.name)[..]) @@ -51,7 +51,7 @@ impl<'docker> Image<'docker> { /// Lists the history of the images set of changes /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageHistory> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageHistory) pub async fn history(&self) -> Result<Vec<History>> { self.docker .get_json(&format!("/images/{}/history", self.name)[..]) @@ -60,7 +60,7 @@ impl<'docker> Image<'docker> { /// Deletes an image /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImagePrune> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImagePrune) pub async fn delete(&self) -> Result<Vec<Status>> { self.docker .delete_json::<Vec<Status>>(&format!("/images/{}", self.name)[..]) @@ -69,7 +69,7 @@ impl<'docker> Image<'docker> { /// Export this image to a tarball /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageGet> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageGet) pub fn export(&self) -> impl Stream<Item = Result<Vec<u8>>> + Unpin + 'docker { Box::pin( self.docker @@ -80,7 +80,7 @@ impl<'docker> Image<'docker> { /// Adds a tag to an image /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageTag> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageTag) pub async fn tag( &self, opts: &TagOptions, @@ -107,7 +107,7 @@ impl<'docker> Images<'docker> { /// Builds a new image build by reading a Dockerfile in a target directory /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageBuild> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageBuild) pub fn build( &self, opts: &BuildOptions, @@ -145,7 +145,7 @@ impl<'docker> Images<'docker> { /// Lists the docker images on the current docker host /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageList> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageList) pub async fn list( &self, opts: &ImageListOptions, @@ -172,7 +172,7 @@ impl<'docker> Images<'docker> { /// Search for docker images by term /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageSearch> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageSearch) pub async fn search( &self, term: &str, @@ -187,7 +187,7 @@ impl<'docker> Images<'docker> { /// Pull and create a new docker images from an existing image /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImagePull> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImagePull) pub fn pull( &self, opts: &PullOptions, @@ -209,7 +209,7 @@ impl<'docker> Images<'docker> { /// exports a collection of named images, /// either by name, name:tag, or image id, into a tarball /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageGetAll> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageGetAll) pub fn export( &self, names: Vec<&str>, @@ -226,7 +226,7 @@ impl<'docker> Images<'docker> { /// imports an image or set of images from a given tarball source /// source can be uncompressed on compressed via gzip, bzip2 or xz /// - /// Api Reference: <https://docs.docker.com/engine/api/v1.41/#operation/ImageLoad> + /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ImageLoad) pub fn import<R>( self, mut tarball: R, @@ -113,7 +113,7 @@ reexport! { mod rep; container::{ ContainerInfo as Container, ContainerDetails, Mount, State, HostConfig, Port, Stats, - MemoryStats, MemoryStat, CpuStats, CpuUsage, ThrottlingData, BlkioStats, BlkioStat, Change, + MemoryStats, MemoryStat, NetworkStats as Network, CpuStats, CpuUsage, ThrottlingData, BlkioStats, BlkioStat, Change, Top, ContainerCreateInfo, Exit, }; docker::{Version, Info, Event, Actor}; @@ -122,7 +122,7 @@ reexport! { SearchResult, ImageInfo as Image, ImageDetails, Config, History, Status, }; network::{ - NetworkSettings, NetworkEntry, NetworkInfo as Network, Ipam, NetworkDetails, + NetworkSettings, NetworkEntry, Ipam, NetworkDetails, NetworkContainerDetails, NetworkCreateInfo, }; service::{ diff --git a/src/network.rs b/src/network.rs index ff2c83f..6dd4eb3 100644 --- a/src/network.rs +++ b/src/network.rs @@ -36,7 +36,7 @@ impl<'docker> Networks<'docker> { pub async fn list( &self, opts: &NetworkListOptions, - ) -> Result<Vec<NetworkInfo>> { + ) -> Result<Vec<NetworkDetails>> { let mut path = vec!["/networks".to_owned()]; if let Some(query) = opts.serialize() { path.push(query); @@ -100,7 +100,7 @@ impl<'docker> Network<'docker> { /// Inspects the current docker network instance's details /// /// API Reference: <https://docs.docker.com/engine/api/v1.41/#operation/NetworkInspect> - pub async fn inspect(&self) -> Result<NetworkInfo> { + pub async fn inspect(&self) -> Result<NetworkDetails> { self.docker .get_json(&format!("/networks/{}", self.id)[..]) .await @@ -367,18 +367,6 @@ pub struct EndpointIPAMConfig { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct NetworkInfo { - pub rx_dropped: u64, - pub rx_bytes: u64, - pub rx_errors: u64, - pub tx_packets: u64, - pub tx_dropped: u64, - pub rx_packets: u64, - pub tx_errors: u64, - pub tx_bytes: u64, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Ipam { pub driver: String, diff --git a/src/volume.rs b/src/volume.rs index 50f0f7a..1a95626 100644 --- a/src/volume.rs +++ b/src/volume.rs @@ -149,6 +149,18 @@ impl VolumeCreateOptionsBuilder { VolumeCreateOptionsBuilder { params } } + pub fn driver( + &mut self, + driver_name: &str, + driver_opts: Option<&HashMap<&str, &str>>, + ) -> &mut Self { + self.params.insert("Driver", json!(driver_name)); + if let Some(opts) = driver_opts { + self.params.insert("DriverOpts", json!(opts)); + } + self + } + pub fn name( &mut self, name: &str, @@ -199,3 +211,47 @@ pub struct VolumeInfo { pub options: Option<HashMap<String, String>>, pub scope: String, } + +#[cfg(test)] +mod test { + use super::*; + + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + pub struct VolumeTestInfo { + pub driver: Option<String>, + pub name: Option<String>, + pub driver_opts: Option<HashMap<String, String>>, + } + + #[test] + fn test_volumecreateoptionsbuilder_driver() { + let volume = VolumeCreateOptions::builder() + .driver("my_driver", None) + .build(); + + let serialized = volume.serialize().unwrap(); + let volume_info: VolumeTestInfo = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(volume_info.driver, Some("my_driver".to_string())); + assert_eq!(volume_info.name, None); + assert_eq!(volume_info.driver_opts, None) + } + + #[test] + fn test_volumecreateoptionsbuilder_driver_opts() { + let opts: HashMap<&str, &str> = [("option", "value")].iter().cloned().collect(); + let volume = VolumeCreateOptions::builder() + .driver("my_driver", Some(&opts)) + .build(); + + let serialized = volume.serialize().unwrap(); + let volume_info: VolumeTestInfo = serde_json::from_str(&serialized).unwrap(); + let mut driver_options = HashMap::new(); + driver_options.insert("option".to_string(), "value".to_string()); + + assert_eq!(volume_info.driver, Some("my_driver".to_string())); + assert_eq!(volume_info.name, None); + assert_eq!(volume_info.driver_opts, Some(driver_options)) + } +} |