bollard_next/
container.rs

1//! Container API: run docker containers and manage their lifecycle
2
3use futures_core::Stream;
4use futures_util::{StreamExt, TryStreamExt};
5use http::header::{CONNECTION, CONTENT_TYPE, UPGRADE};
6use http::request::Builder;
7use http_body_util::Full;
8use hyper::{body::Bytes, Method};
9use serde::Serialize;
10use serde_derive::Deserialize;
11use tokio::io::AsyncWrite;
12use tokio_util::codec::FramedRead;
13
14use std::cmp::Eq;
15use std::collections::HashMap;
16use std::fmt;
17use std::hash::Hash;
18use std::pin::Pin;
19
20use super::Docker;
21use crate::docker::{body_stream, BodyType};
22use crate::errors::Error;
23use crate::models::*;
24use crate::read::NewlineLogOutputDecoder;
25
26/// Parameters used in the [List Container API](Docker::list_containers())
27///
28/// ## Examples
29///
30/// ```rust
31/// use bollard_next::container::ListContainersOptions;
32///
33/// use std::collections::HashMap;
34/// use std::default::Default;
35///
36/// let mut filters = HashMap::new();
37/// filters.insert("health", vec!["unhealthy"]);
38///
39/// ListContainersOptions{
40///     all: true,
41///     filters,
42///     ..Default::default()
43/// };
44/// ```
45///
46/// ```rust
47/// # use bollard_next::container::ListContainersOptions;
48/// # use std::default::Default;
49/// ListContainersOptions::<String>{
50///     ..Default::default()
51/// };
52/// ```
53#[derive(Debug, Clone, Default, PartialEq, Serialize)]
54pub struct ListContainersOptions<T>
55where
56    T: Into<String> + Eq + Hash + Serialize,
57{
58    /// Return all containers. By default, only running containers are shown
59    pub all: bool,
60    /// Return this number of most recently created containers, including non-running ones
61    pub limit: Option<isize>,
62    /// Return the size of container as fields `SizeRw` and `SizeRootFs`
63    pub size: bool,
64    /// Filters to process on the container list, encoded as JSON. Available filters:
65    ///  - `ancestor`=`(<image-name>[:<tag>]`, `<image id>`, or `<image@digest>`)
66    ///  - `before`=(`<container id>` or `<container name>`)
67    ///  - `expose`=(`<port>[/<proto>]`|`<startport-endport>`/`[<proto>]`)
68    ///  - `exited`=`<int>` containers with exit code of `<int>`
69    ///  - `health`=(`starting`|`healthy`|`unhealthy`|`none`)
70    ///  - `id`=`<ID>` a container's ID
71    ///  - `isolation`=(`default`|`process`|`hyperv`) (Windows daemon only)
72    ///  - `is-task`=`(true`|`false`)
73    ///  - `label`=`key` or `label`=`"key=value"` of a container label
74    ///  - `name`=`<name>` a container's name
75    ///  - `network`=(`<network id>` or `<network name>`)
76    ///  - `publish`=(`<port>[/<proto>]`|`<startport-endport>`/`[<proto>]`)
77    ///  - `since`=(`<container id>` or `<container name>`)
78    ///  - `status`=(`created`|`restarting`|`running`|`removing`|`paused`|`exited`|`dead`)
79    ///  - `volume`=(`<volume name>` or `<mount point destination>`)
80    #[serde(serialize_with = "crate::docker::serialize_as_json")]
81    pub filters: HashMap<T, Vec<T>>,
82}
83
84/// Parameters used in the [Create Container API](Docker::create_container())
85///
86/// ## Examples
87///
88/// ```rust
89/// use bollard_next::container::CreateContainerOptions;
90///
91/// CreateContainerOptions{
92///     name: "my-new-container",
93///     platform: Some("linux/amd64"),
94/// };
95/// ```
96#[derive(Debug, Clone, Default, PartialEq, Serialize)]
97#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
98#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
99pub struct CreateContainerOptions<T>
100where
101    T: Into<String> + Serialize,
102{
103    /// Assign the specified name to the container.
104    pub name: T,
105
106    /// The platform to use for the container.
107    /// Added in API v1.41.
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub platform: Option<T>,
110}
111
112/// This container's networking configuration.
113#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
114#[serde(rename_all = "PascalCase")]
115#[allow(missing_docs)]
116#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
117#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
118pub struct NetworkingConfig<T: Into<String> + Hash + Eq> {
119    pub endpoints_config: HashMap<T, EndpointSettings>,
120}
121
122/// Container to create.
123#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
124#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
125#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
126pub struct Config {
127    /// The hostname to use for the container, as a valid RFC 1123 hostname.
128    #[serde(rename = "Hostname")]
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub hostname: Option<String>,
131
132    /// The domain name to use for the container.
133    #[serde(rename = "Domainname")]
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub domainname: Option<String>,
136
137    /// The user that commands are run as inside the container.
138    #[serde(rename = "User")]
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub user: Option<String>,
141
142    /// Whether to attach to `stdin`.
143    #[serde(rename = "AttachStdin")]
144    #[serde(skip_serializing_if = "Option::is_none")]
145    pub attach_stdin: Option<bool>,
146
147    /// Whether to attach to `stdout`.
148    #[serde(rename = "AttachStdout")]
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub attach_stdout: Option<bool>,
151
152    /// Whether to attach to `stderr`.
153    #[serde(rename = "AttachStderr")]
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub attach_stderr: Option<bool>,
156
157    /// An object mapping ports to an empty object in the form:  `{\"<port>/<tcp|udp|sctp>\": {}}`
158    #[serde(rename = "ExposedPorts")]
159    #[serde(skip_serializing_if = "Option::is_none")]
160    #[cfg_attr(feature = "utoipa", schema(value_type = Option<HashMap<String, HashMap<(), ()>>>))]
161    pub exposed_ports: Option<HashMap<String, EmptyObject>>,
162
163    /// Attach standard streams to a TTY, including `stdin` if it is not closed.
164    #[serde(rename = "Tty")]
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub tty: Option<bool>,
167
168    /// Open `stdin`
169    #[serde(rename = "OpenStdin")]
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub open_stdin: Option<bool>,
172
173    /// Close `stdin` after one attached client disconnects
174    #[serde(rename = "StdinOnce")]
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub stdin_once: Option<bool>,
177
178    /// A list of environment variables to set inside the container in the form `[\"VAR=value\", ...]`. A variable without `=` is removed from the environment, rather than to have an empty value.
179    #[serde(rename = "Env")]
180    #[serde(skip_serializing_if = "Option::is_none")]
181    pub env: Option<Vec<String>>,
182
183    /// Command to run specified as a string or an array of strings.
184    #[serde(rename = "Cmd")]
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub cmd: Option<Vec<String>>,
187
188    /// A TEST to perform TO Check that the container is healthy.
189    #[serde(rename = "Healthcheck")]
190    #[serde(skip_serializing_if = "Option::is_none")]
191    pub healthcheck: Option<HealthConfig>,
192
193    /// Command is already escaped (Windows only)
194    #[serde(rename = "ArgsEscaped")]
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub args_escaped: Option<bool>,
197
198    /// The name of the image to use when creating the container
199    #[serde(rename = "Image")]
200    #[serde(skip_serializing_if = "Option::is_none")]
201    pub image: Option<String>,
202
203    /// An object mapping mount point paths inside the container to empty objects.
204    #[serde(rename = "Volumes")]
205    #[serde(skip_serializing_if = "Option::is_none")]
206    #[cfg_attr(feature = "utoipa", schema(value_type = Option<HashMap<String, HashMap<(), ()>>>))]
207    pub volumes: Option<HashMap<String, EmptyObject>>,
208
209    /// The working directory for commands to run in.
210    #[serde(rename = "WorkingDir")]
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub working_dir: Option<String>,
213
214    /// The entry point for the container as a string or an array of strings.  If the array consists of exactly one empty string (`[\"\"]`) then the entry point is reset to system default (i.e., the entry point used by docker when there is no `ENTRYPOINT` instruction in the `Dockerfile`).
215    #[serde(rename = "Entrypoint")]
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub entrypoint: Option<Vec<String>>,
218
219    /// Disable networking for the container.
220    #[serde(rename = "NetworkDisabled")]
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub network_disabled: Option<bool>,
223
224    /// MAC address of the container.
225    #[serde(rename = "MacAddress")]
226    #[serde(skip_serializing_if = "Option::is_none")]
227    pub mac_address: Option<String>,
228
229    /// `ONBUILD` metadata that were defined in the image's `Dockerfile`.
230    #[serde(rename = "OnBuild")]
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub on_build: Option<Vec<String>>,
233
234    /// User-defined key/value metadata.
235    #[serde(rename = "Labels")]
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub labels: Option<HashMap<String, String>>,
238
239    /// Signal to stop a container as a string or unsigned integer.
240    #[serde(rename = "StopSignal")]
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub stop_signal: Option<String>,
243
244    /// Timeout to stop a container in seconds.
245    #[serde(rename = "StopTimeout")]
246    #[serde(skip_serializing_if = "Option::is_none")]
247    pub stop_timeout: Option<i64>,
248
249    /// Shell for when `RUN`, `CMD`, and `ENTRYPOINT` uses a shell.
250    #[serde(rename = "Shell")]
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub shell: Option<Vec<String>>,
253
254    /// Container configuration that depends on the host we are running on.
255    /// Shell for when `RUN`, `CMD`, and `ENTRYPOINT` uses a shell.
256    #[serde(rename = "HostConfig")]
257    #[serde(skip_serializing_if = "Option::is_none")]
258    pub host_config: Option<HostConfig>,
259
260    /// This container's networking configuration.
261    #[serde(rename = "NetworkingConfig")]
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub networking_config: Option<NetworkingConfig<String>>,
264}
265
266impl From<ContainerConfig> for Config {
267    fn from(container: ContainerConfig) -> Self {
268        Config {
269            hostname: container.hostname,
270            domainname: container.domainname,
271            user: container.user,
272            attach_stdin: container.attach_stdin,
273            attach_stdout: container.attach_stdout,
274            attach_stderr: container.attach_stderr,
275            exposed_ports: container.exposed_ports,
276            tty: container.tty,
277            open_stdin: container.open_stdin,
278            stdin_once: container.stdin_once,
279            env: container.env,
280            cmd: container.cmd,
281            healthcheck: container.healthcheck,
282            args_escaped: container.args_escaped,
283            image: container.image,
284            volumes: container.volumes,
285            working_dir: container.working_dir,
286            entrypoint: container.entrypoint,
287            network_disabled: container.network_disabled,
288            mac_address: container.mac_address,
289            on_build: container.on_build,
290            labels: container.labels,
291            stop_signal: container.stop_signal,
292            stop_timeout: container.stop_timeout,
293            shell: container.shell,
294            host_config: None,
295            networking_config: None,
296        }
297    }
298}
299
300/// Parameters used in the [Stop Container API](Docker::stop_container())
301///
302/// ## Examples
303///
304/// use bollard_next::container::StopContainerOptions;
305///
306/// StopContainerOptions{
307///     t: 30,
308/// };
309#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
310#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
311#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
312pub struct StopContainerOptions {
313    /// Number of seconds to wait before killing the container
314    pub t: i64,
315}
316
317/// Parameters used in the [Start Container API](Docker::start_container())
318///
319/// ## Examples
320///
321/// ```rust
322/// use bollard_next::container::StartContainerOptions;
323///
324/// StartContainerOptions{
325///     detach_keys: "ctrl-^"
326/// };
327/// ```
328#[derive(Debug, Clone, Default, PartialEq, Serialize)]
329#[serde(rename_all = "camelCase")]
330#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
331#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
332pub struct StartContainerOptions<T>
333where
334    T: Into<String> + Serialize,
335{
336    /// Override the key sequence for detaching a container. Format is a single character `[a-Z]` or
337    /// `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`.
338    pub detach_keys: T,
339}
340
341/// Parameters used in the [Remove Container API](Docker::remove_container())
342///
343/// ## Examples
344///
345/// ```rust
346/// use bollard_next::container::RemoveContainerOptions;
347///
348/// use std::default::Default;
349///
350/// RemoveContainerOptions{
351///     force: true,
352///     ..Default::default()
353/// };
354/// ```
355#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
356#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
357#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
358pub struct RemoveContainerOptions {
359    /// Remove the volumes associated with the container.
360    pub v: bool,
361    /// If the container is running, kill it before removing it.
362    pub force: bool,
363    /// Remove the specified link associated with the container.
364    pub link: bool,
365}
366
367/// Parameters used in the [Wait Container API](Docker::wait_container())
368///
369/// ## Examples
370///
371/// ```rust
372/// use bollard_next::container::WaitContainerOptions;
373///
374/// WaitContainerOptions{
375///     condition: "not-running",
376/// };
377/// ```
378#[derive(Debug, Clone, Default, PartialEq, Serialize)]
379#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
380#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
381pub struct WaitContainerOptions<T>
382where
383    T: Into<String> + Serialize,
384{
385    /// Wait until a container state reaches the given condition, either 'not-running' (default),
386    /// 'next-exit', or 'removed'.
387    pub condition: T,
388}
389
390/// Results type for the [Attach Container API](Docker::attach_container())
391pub struct AttachContainerResults {
392    /// [Log Output](LogOutput) enum, wrapped in a Stream.
393    pub output: Pin<Box<dyn Stream<Item = Result<LogOutput, Error>> + Send>>,
394    /// Byte writer to container
395    pub input: Pin<Box<dyn AsyncWrite + Send>>,
396}
397
398impl fmt::Debug for AttachContainerResults {
399    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400        write!(f, "AttachContainerResults")
401    }
402}
403
404/// Parameters used in the [Attach Container API](Docker::attach_container())
405///
406/// ## Examples
407///
408/// ```rust
409/// use bollard_next::container::AttachContainerOptions;
410///
411/// AttachContainerOptions::<String>{
412///     stdin: Some(true),
413///     stdout: Some(true),
414///     stderr: Some(true),
415///     stream: Some(true),
416///     logs: Some(true),
417///     detach_keys: Some("ctrl-c".to_string()),
418/// };
419/// ```
420#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
421#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
422#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
423pub struct AttachContainerOptions<T>
424where
425    T: Into<String> + Serialize + Default,
426{
427    /// Attach to `stdin`
428    pub stdin: Option<bool>,
429    /// Attach to `stdout`
430    pub stdout: Option<bool>,
431    /// Attach to `stderr`
432    pub stderr: Option<bool>,
433    /// Stream attached streams from the time the request was made onwards.
434    pub stream: Option<bool>,
435    /// Replay previous logs from the container.
436    /// This is useful for attaching to a container that has started and you want to output everything since the container started.
437    /// If stream is also enabled, once all the previous output has been returned, it will seamlessly transition into streaming current output.
438    pub logs: Option<bool>,
439    /// Override the key sequence for detaching a container.
440    /// Format is a single character [a-Z] or ctrl-\<value\> where \<value\> is one of: a-z, @, ^, [, , or _.
441    #[serde(rename = "detachKeys")]
442    pub detach_keys: Option<T>,
443}
444
445/// Parameters used in the [Resize Container Tty API](Docker::resize_container_tty())
446///
447/// ## Examples
448///
449/// ```rust
450/// use bollard_next::container::ResizeContainerTtyOptions;
451///
452/// ResizeContainerTtyOptions {
453///     width: 50,
454///     height: 10,
455/// };
456/// ```
457#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
458#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
459#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
460pub struct ResizeContainerTtyOptions {
461    /// Width of the TTY session in characters
462    #[serde(rename = "w")]
463    pub width: u16,
464    /// Height of the TTY session in characters
465    #[serde(rename = "h")]
466    pub height: u16,
467}
468
469/// Parameters used in the [Restart Container API](Docker::restart_container())
470///
471/// ## Example
472///
473/// ```rust
474/// use bollard_next::container::RestartContainerOptions;
475///
476/// RestartContainerOptions{
477///     t: 30,
478/// };
479/// ```
480#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
481#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
482#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
483pub struct RestartContainerOptions {
484    /// Number of seconds to wait before killing the container.
485    pub t: isize,
486}
487
488/// Parameters used in the [Inspect Container API](Docker::inspect_container())
489///
490/// ## Examples
491///
492/// ```rust
493/// use bollard_next::container::InspectContainerOptions;
494///
495/// InspectContainerOptions{
496///     size: false,
497/// };
498/// ```
499#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
500#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
501#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
502pub struct InspectContainerOptions {
503    /// Return the size of container as fields `SizeRw` and `SizeRootFs`
504    pub size: bool,
505}
506
507/// Parameters used in the [Top Processes API](Docker::top_processes())
508///
509/// ## Examples
510///
511/// ```rust
512/// use bollard_next::container::TopOptions;
513///
514/// TopOptions{
515///     ps_args: "aux",
516/// };
517/// ```
518#[derive(Debug, Clone, Default, PartialEq, Serialize)]
519#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
520#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
521pub struct TopOptions<T>
522where
523    T: Into<String> + Serialize,
524{
525    /// The arguments to pass to `ps`. For example, `aux`
526    pub ps_args: T,
527}
528
529fn is_zero(val: &i64) -> bool {
530    val == &0i64
531}
532
533/// Parameters used in the [Logs API](Docker::logs())
534///
535/// ## Examples
536///
537/// ```rust
538/// use bollard_next::container::LogsOptions;
539///
540/// use std::default::Default;
541///
542/// LogsOptions::<String>{
543///     stdout: true,
544///     ..Default::default()
545/// };
546/// ```
547#[derive(Debug, Clone, Default, PartialEq, Serialize)]
548#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
549#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
550pub struct LogsOptions<T>
551where
552    T: Into<String> + Serialize,
553{
554    /// Return the logs as a finite stream.
555    pub follow: bool,
556    /// Return logs from `stdout`.
557    pub stdout: bool,
558    /// Return logs from `stderr`.
559    pub stderr: bool,
560    /// Only return logs since this time, as a UNIX timestamp.
561    pub since: i64,
562    /// Only return logs before this time, as a UNIX timestamp.
563    #[serde(skip_serializing_if = "is_zero")]
564    // workaround for https://github.com/containers/podman/issues/10859
565    pub until: i64,
566    /// Add timestamps to every log line.
567    pub timestamps: bool,
568    /// Only return this number of log lines from the end of the logs. Specify as an integer or all
569    /// to output `all` log lines.
570    pub tail: T,
571}
572
573/// Result type for the [Logs API](Docker::logs())
574#[derive(Debug, Clone, PartialEq)]
575#[allow(missing_docs)]
576pub enum LogOutput {
577    StdErr { message: Bytes },
578    StdOut { message: Bytes },
579    StdIn { message: Bytes },
580    Console { message: Bytes },
581}
582
583impl fmt::Display for LogOutput {
584    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585        let message = match &self {
586            LogOutput::StdErr { message } => message,
587            LogOutput::StdOut { message } => message,
588            LogOutput::StdIn { message } => message,
589            LogOutput::Console { message } => message,
590        };
591        write!(f, "{}", String::from_utf8_lossy(message))
592    }
593}
594
595impl AsRef<[u8]> for LogOutput {
596    fn as_ref(&self) -> &[u8] {
597        match self {
598            LogOutput::StdErr { message } => message.as_ref(),
599            LogOutput::StdOut { message } => message.as_ref(),
600            LogOutput::StdIn { message } => message.as_ref(),
601            LogOutput::Console { message } => message.as_ref(),
602        }
603    }
604}
605
606impl LogOutput {
607    /// Get the raw bytes of the output
608    pub fn into_bytes(self) -> Bytes {
609        match self {
610            LogOutput::StdErr { message } => message,
611            LogOutput::StdOut { message } => message,
612            LogOutput::StdIn { message } => message,
613            LogOutput::Console { message } => message,
614        }
615    }
616}
617
618/// Parameters used in the [Stats API](super::Docker::stats())
619///
620/// ## Examples
621///
622/// ```rust
623/// use bollard_next::container::StatsOptions;
624///
625/// StatsOptions{
626///     stream: false,
627///     one_shot: false,
628/// };
629/// ```
630#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
631#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
632#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
633pub struct StatsOptions {
634    /// Stream the output. If false, the stats will be output once and then it will disconnect.
635    pub stream: bool,
636    /// Only get a single stat instead of waiting for 2 cycles. Must be used with `stream = false`.
637    #[serde(rename = "one-shot")]
638    pub one_shot: bool,
639}
640
641/// Granular memory statistics for the container.
642#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
643#[allow(missing_docs)]
644#[serde(untagged)]
645#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
646#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
647pub enum MemoryStatsStats {
648    V1(MemoryStatsStatsV1),
649    V2(MemoryStatsStatsV2),
650}
651
652/// Granular memory statistics for the container, v1 cgroups.
653///
654/// Exposed in the docker library [here](https://github.com/moby/moby/blob/40d9e2aff130b42ba0f83d5238b9b53184c8ab3b/daemon/daemon_unix.go#L1436).
655#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
656#[allow(missing_docs)]
657#[serde(deny_unknown_fields)]
658#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
659#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
660pub struct MemoryStatsStatsV1 {
661    pub cache: u64,
662    pub dirty: u64,
663    pub mapped_file: u64,
664    pub total_inactive_file: u64,
665    pub pgpgout: u64,
666    pub rss: u64,
667    pub total_mapped_file: u64,
668    pub writeback: u64,
669    pub unevictable: u64,
670    pub pgpgin: u64,
671    pub total_unevictable: u64,
672    pub pgmajfault: u64,
673    pub total_rss: u64,
674    pub total_rss_huge: u64,
675    pub total_writeback: u64,
676    pub total_inactive_anon: u64,
677    pub rss_huge: u64,
678    pub hierarchical_memory_limit: u64,
679    pub total_pgfault: u64,
680    pub total_active_file: u64,
681    pub active_anon: u64,
682    pub total_active_anon: u64,
683    pub total_pgpgout: u64,
684    pub total_cache: u64,
685    pub total_dirty: u64,
686    pub inactive_anon: u64,
687    pub active_file: u64,
688    pub pgfault: u64,
689    pub inactive_file: u64,
690    pub total_pgmajfault: u64,
691    pub total_pgpgin: u64,
692    pub hierarchical_memsw_limit: Option<u64>, // only on OSX
693    pub shmem: Option<u64>,                    // only on linux kernel > 4.15.0-1106
694    pub total_shmem: Option<u64>,              // only on linux kernel > 4.15.0-1106
695}
696
697/// Granular memory statistics for the container, v2 cgroups.
698///
699/// Exposed in the docker library [here](https://github.com/moby/moby/blob/40d9e2aff130b42ba0f83d5238b9b53184c8ab3b/daemon/daemon_unix.go#L1542).
700#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
701#[allow(missing_docs)]
702#[serde(deny_unknown_fields)]
703#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
704#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
705pub struct MemoryStatsStatsV2 {
706    pub anon: u64,
707    pub file: u64,
708    pub kernel_stack: u64,
709    pub slab: u64,
710    pub sock: u64,
711    pub shmem: u64,
712    pub file_mapped: u64,
713    pub file_dirty: u64,
714    pub file_writeback: u64,
715    pub anon_thp: u64,
716    pub inactive_anon: u64,
717    pub active_anon: u64,
718    pub inactive_file: u64,
719    pub active_file: u64,
720    pub unevictable: u64,
721    pub slab_reclaimable: u64,
722    pub slab_unreclaimable: u64,
723    pub pgfault: u64,
724    pub pgmajfault: u64,
725    pub workingset_refault: u64,
726    pub workingset_activate: u64,
727    pub workingset_nodereclaim: u64,
728    pub pgrefill: u64,
729    pub pgscan: u64,
730    pub pgsteal: u64,
731    pub pgactivate: u64,
732    pub pgdeactivate: u64,
733    pub pglazyfree: u64,
734    pub pglazyfreed: u64,
735    pub thp_fault_alloc: u64,
736    pub thp_collapse_alloc: u64,
737}
738
739/// General memory statistics for the container.
740#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
741#[allow(missing_docs)]
742#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
743#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
744pub struct MemoryStats {
745    pub stats: Option<MemoryStatsStats>,
746    pub max_usage: Option<u64>,
747    pub usage: Option<u64>,
748    pub failcnt: Option<u64>,
749    pub limit: Option<u64>,
750    pub commit: Option<u64>,
751    pub commit_peak: Option<u64>,
752    pub commitbytes: Option<u64>,
753    pub commitpeakbytes: Option<u64>,
754    pub privateworkingset: Option<u64>,
755}
756
757/// Process ID statistics for the container.
758#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
759#[allow(missing_docs)]
760#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
761#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
762pub struct PidsStats {
763    pub current: Option<u64>,
764    pub limit: Option<u64>,
765}
766
767/// I/O statistics for the container.
768#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
769#[allow(missing_docs)]
770#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
771#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
772pub struct BlkioStats {
773    pub io_service_bytes_recursive: Option<Vec<BlkioStatsEntry>>,
774    pub io_serviced_recursive: Option<Vec<BlkioStatsEntry>>,
775    pub io_queue_recursive: Option<Vec<BlkioStatsEntry>>,
776    pub io_service_time_recursive: Option<Vec<BlkioStatsEntry>>,
777    pub io_wait_time_recursive: Option<Vec<BlkioStatsEntry>>,
778    pub io_merged_recursive: Option<Vec<BlkioStatsEntry>>,
779    pub io_time_recursive: Option<Vec<BlkioStatsEntry>>,
780    pub sectors_recursive: Option<Vec<BlkioStatsEntry>>,
781}
782
783/// File I/O statistics for the container.
784#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
785#[allow(missing_docs)]
786#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
787#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
788pub struct StorageStats {
789    pub read_count_normalized: Option<u64>,
790    pub read_size_bytes: Option<u64>,
791    pub write_count_normalized: Option<u64>,
792    pub write_size_bytes: Option<u64>,
793}
794
795fn empty_string() -> String {
796    "".to_string()
797}
798
799/// Statistics for the container.
800#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
801#[allow(missing_docs)]
802#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
803#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
804pub struct Stats {
805    #[cfg(feature = "time")]
806    #[serde(
807        deserialize_with = "crate::docker::deserialize_rfc3339",
808        serialize_with = "crate::docker::serialize_rfc3339"
809    )]
810    pub read: time::OffsetDateTime,
811    #[cfg(feature = "time")]
812    #[serde(
813        deserialize_with = "crate::docker::deserialize_rfc3339",
814        serialize_with = "crate::docker::serialize_rfc3339"
815    )]
816    pub preread: time::OffsetDateTime,
817    #[cfg(all(feature = "chrono", not(feature = "time")))]
818    pub read: chrono::DateTime<chrono::Utc>,
819    #[cfg(all(feature = "chrono", not(feature = "time")))]
820    pub preread: chrono::DateTime<chrono::Utc>,
821    #[cfg(not(any(feature = "chrono", feature = "time")))]
822    pub read: String,
823    #[cfg(not(any(feature = "chrono", feature = "time")))]
824    pub preread: String,
825    pub num_procs: u32,
826    pub pids_stats: PidsStats,
827    pub network: Option<NetworkStats>,
828    pub networks: Option<HashMap<String, NetworkStats>>,
829    pub memory_stats: MemoryStats,
830    pub blkio_stats: BlkioStats,
831    pub cpu_stats: CPUStats,
832    pub precpu_stats: CPUStats,
833    pub storage_stats: StorageStats,
834    #[serde(default = "empty_string")]
835    pub name: String,
836
837    // Podman incorrectly capitalises the "id" field. See https://github.com/containers/podman/issues/17869
838    #[serde(alias = "Id", default = "empty_string")]
839    pub id: String,
840}
841
842/// Network statistics for the container.
843#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
844#[allow(missing_docs)]
845#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
846#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
847pub struct NetworkStats {
848    pub rx_dropped: u64,
849    pub rx_bytes: u64,
850    pub rx_errors: u64,
851    pub tx_packets: u64,
852    pub tx_dropped: u64,
853    pub rx_packets: u64,
854    pub tx_errors: u64,
855    pub tx_bytes: u64,
856}
857
858/// CPU usage statistics for the container.
859#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
860#[allow(missing_docs)]
861#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
862#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
863pub struct CPUUsage {
864    pub percpu_usage: Option<Vec<u64>>,
865    pub usage_in_usermode: u64,
866    pub total_usage: u64,
867    pub usage_in_kernelmode: u64,
868}
869
870/// CPU throttling statistics.
871#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
872#[allow(missing_docs)]
873#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
874#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
875pub struct ThrottlingData {
876    pub periods: u64,
877    pub throttled_periods: u64,
878    pub throttled_time: u64,
879}
880
881/// General CPU statistics for the container.
882#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
883#[allow(missing_docs)]
884#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
885#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
886pub struct CPUStats {
887    pub cpu_usage: CPUUsage,
888    pub system_cpu_usage: Option<u64>,
889    pub online_cpus: Option<u64>,
890    pub throttling_data: ThrottlingData,
891}
892
893#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
894#[allow(missing_docs)]
895#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
896#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
897pub struct BlkioStatsEntry {
898    pub major: u64,
899    pub minor: u64,
900    pub op: String,
901    pub value: u64,
902}
903
904/// Parameters used in the [Kill Container API](Docker::kill_container())
905///
906/// ## Examples
907///
908/// ```rust
909/// use bollard_next::container::KillContainerOptions;
910///
911/// KillContainerOptions{
912///     signal: "SIGINT",
913/// };
914/// ```
915#[derive(Debug, Clone, Default, PartialEq, Serialize)]
916#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
917#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
918pub struct KillContainerOptions<T>
919where
920    T: Into<String> + Serialize,
921{
922    /// Signal to send to the container as an integer or string (e.g. `SIGINT`)
923    pub signal: T,
924}
925
926/// Configuration for the [Update Container API](Docker::update_container())
927///
928/// ## Examples
929///
930/// ```rust
931/// use bollard_next::container::UpdateContainerOptions;
932/// use std::default::Default;
933///
934/// UpdateContainerOptions::<String> {
935///     memory: Some(314572800),
936///     memory_swap: Some(314572800),
937///     ..Default::default()
938/// };
939/// ```
940#[derive(Debug, Clone, Default, PartialEq, Serialize)]
941#[serde(rename_all = "PascalCase")]
942#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
943#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
944pub struct UpdateContainerOptions<T>
945where
946    T: Into<String> + Eq + Hash,
947{
948    /// An integer value representing this container's relative CPU weight versus other containers.
949    #[serde(rename = "CpuShares")]
950    #[serde(skip_serializing_if = "Option::is_none")]
951    pub cpu_shares: Option<isize>,
952
953    /// Memory limit in bytes.
954    #[serde(rename = "Memory")]
955    #[serde(skip_serializing_if = "Option::is_none")]
956    pub memory: Option<i64>,
957
958    /// Path to `cgroups` under which the container's `cgroup` is created. If the path is not absolute, the path is considered to be relative to the `cgroups` path of the init process. Cgroups are created if they do not already exist.
959    #[serde(rename = "CgroupParent")]
960    #[serde(skip_serializing_if = "Option::is_none")]
961    pub cgroup_parent: Option<T>,
962
963    /// Block IO weight (relative weight).
964    #[serde(rename = "BlkioWeight")]
965    #[serde(skip_serializing_if = "Option::is_none")]
966    pub blkio_weight: Option<u16>,
967
968    /// Block IO weight (relative device weight) in the form `[{\"Path\": \"device_path\", \"Weight\": weight}]`.
969    #[serde(rename = "BlkioWeightDevice")]
970    #[serde(skip_serializing_if = "Option::is_none")]
971    pub blkio_weight_device: Option<Vec<ResourcesBlkioWeightDevice>>,
972
973    /// Limit read rate (bytes per second) from a device, in the form `[{\"Path\": \"device_path\", \"Rate\": rate}]`.
974    #[serde(rename = "BlkioDeviceReadBps")]
975    #[serde(skip_serializing_if = "Option::is_none")]
976    pub blkio_device_read_bps: Option<Vec<ThrottleDevice>>,
977
978    /// Limit write rate (bytes per second) to a device, in the form `[{\"Path\": \"device_path\", \"Rate\": rate}]`.
979    #[serde(rename = "BlkioDeviceWriteBps")]
980    #[serde(skip_serializing_if = "Option::is_none")]
981    pub blkio_device_write_bps: Option<Vec<ThrottleDevice>>,
982
983    /// Limit read rate (IO per second) from a device, in the form `[{\"Path\": \"device_path\", \"Rate\": rate}]`.
984    #[serde(rename = "BlkioDeviceReadIOps")]
985    #[serde(skip_serializing_if = "Option::is_none")]
986    pub blkio_device_read_i_ops: Option<Vec<ThrottleDevice>>,
987
988    /// Limit write rate (IO per second) to a device, in the form `[{\"Path\": \"device_path\", \"Rate\": rate}]`.
989    #[serde(rename = "BlkioDeviceWriteIOps")]
990    #[serde(skip_serializing_if = "Option::is_none")]
991    pub blkio_device_write_i_ops: Option<Vec<ThrottleDevice>>,
992
993    /// The length of a CPU period in microseconds.
994    #[serde(rename = "CpuPeriod")]
995    #[serde(skip_serializing_if = "Option::is_none")]
996    pub cpu_period: Option<i64>,
997
998    /// Microseconds of CPU time that the container can get in a CPU period.
999    #[serde(rename = "CpuQuota")]
1000    #[serde(skip_serializing_if = "Option::is_none")]
1001    pub cpu_quota: Option<i64>,
1002
1003    /// The length of a CPU real-time period in microseconds. Set to 0 to allocate no time allocated to real-time tasks.
1004    #[serde(rename = "CpuRealtimePeriod")]
1005    #[serde(skip_serializing_if = "Option::is_none")]
1006    pub cpu_realtime_period: Option<i64>,
1007
1008    /// The length of a CPU real-time runtime in microseconds. Set to 0 to allocate no time allocated to real-time tasks.
1009    #[serde(rename = "CpuRealtimeRuntime")]
1010    #[serde(skip_serializing_if = "Option::is_none")]
1011    pub cpu_realtime_runtime: Option<i64>,
1012
1013    /// CPUs in which to allow execution (e.g., `0-3`, `0,1`)
1014    #[serde(rename = "CpusetCpus")]
1015    #[serde(skip_serializing_if = "Option::is_none")]
1016    pub cpuset_cpus: Option<T>,
1017
1018    /// Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
1019    #[serde(rename = "CpusetMems")]
1020    #[serde(skip_serializing_if = "Option::is_none")]
1021    pub cpuset_mems: Option<T>,
1022
1023    /// A list of devices to add to the container.
1024    #[serde(rename = "Devices")]
1025    #[serde(skip_serializing_if = "Option::is_none")]
1026    pub devices: Option<Vec<DeviceMapping>>,
1027
1028    /// a list of cgroup rules to apply to the container
1029    #[serde(rename = "DeviceCgroupRules")]
1030    #[serde(skip_serializing_if = "Option::is_none")]
1031    pub device_cgroup_rules: Option<Vec<T>>,
1032
1033    /// a list of requests for devices to be sent to device drivers
1034    #[serde(rename = "DeviceRequests")]
1035    #[serde(skip_serializing_if = "Option::is_none")]
1036    pub device_requests: Option<Vec<DeviceRequest>>,
1037
1038    /// Hard limit for kernel TCP buffer memory (in bytes).
1039    #[serde(rename = "KernelMemoryTCP")]
1040    #[serde(skip_serializing_if = "Option::is_none")]
1041    pub kernel_memory_tcp: Option<i64>,
1042
1043    /// Memory soft limit in bytes.
1044    #[serde(rename = "MemoryReservation")]
1045    #[serde(skip_serializing_if = "Option::is_none")]
1046    pub memory_reservation: Option<i64>,
1047
1048    /// Total memory limit (memory + swap). Set as `-1` to enable unlimited swap.
1049    #[serde(rename = "MemorySwap")]
1050    #[serde(skip_serializing_if = "Option::is_none")]
1051    pub memory_swap: Option<i64>,
1052
1053    /// Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
1054    #[serde(rename = "MemorySwappiness")]
1055    #[serde(skip_serializing_if = "Option::is_none")]
1056    pub memory_swappiness: Option<i64>,
1057
1058    /// CPU quota in units of 10<sup>-9</sup> CPUs.
1059    #[serde(rename = "NanoCpus")]
1060    #[serde(skip_serializing_if = "Option::is_none")]
1061    pub nano_cpus: Option<i64>,
1062
1063    /// Disable OOM Killer for the container.
1064    #[serde(rename = "OomKillDisable")]
1065    #[serde(skip_serializing_if = "Option::is_none")]
1066    pub oom_kill_disable: Option<bool>,
1067
1068    /// Run an init inside the container that forwards signals and reaps processes. This field is omitted if empty, and the default (as configured on the daemon) is used.
1069    #[serde(rename = "Init")]
1070    #[serde(skip_serializing_if = "Option::is_none")]
1071    pub init: Option<bool>,
1072
1073    /// Tune a container's PIDs limit. Set `0` or `-1` for unlimited, or `null` to not change.
1074    #[serde(rename = "PidsLimit")]
1075    #[serde(skip_serializing_if = "Option::is_none")]
1076    pub pids_limit: Option<i64>,
1077
1078    /// A list of resource limits to set in the container. For example: `{\"Name\": \"nofile\", \"Soft\": 1024, \"Hard\": 2048}`\"
1079    #[serde(rename = "Ulimits")]
1080    #[serde(skip_serializing_if = "Option::is_none")]
1081    pub ulimits: Option<Vec<ResourcesUlimits>>,
1082
1083    /// The number of usable CPUs (Windows only).  On Windows Server containers, the processor resource controls are mutually exclusive. The order of precedence is `CPUCount` first, then `CPUShares`, and `CPUPercent` last.
1084    #[serde(rename = "CpuCount")]
1085    #[serde(skip_serializing_if = "Option::is_none")]
1086    pub cpu_count: Option<i64>,
1087
1088    /// The usable percentage of the available CPUs (Windows only).  On Windows Server containers, the processor resource controls are mutually exclusive. The order of precedence is `CPUCount` first, then `CPUShares`, and `CPUPercent` last.
1089    #[serde(rename = "CpuPercent")]
1090    #[serde(skip_serializing_if = "Option::is_none")]
1091    pub cpu_percent: Option<i64>,
1092
1093    /// Maximum IOps for the container system drive (Windows only)
1094    #[serde(rename = "IOMaximumIOps")]
1095    #[serde(skip_serializing_if = "Option::is_none")]
1096    pub io_maximum_iops: Option<i64>,
1097
1098    /// Maximum IO in bytes per second for the container system drive (Windows only)
1099    #[serde(rename = "IOMaximumBandwidth")]
1100    #[serde(skip_serializing_if = "Option::is_none")]
1101    pub io_maximum_bandwidth: Option<i64>,
1102
1103    /// The behavior to apply when the container exits. The default is not to restart.
1104    ///
1105    /// An ever increasing delay (double the previous delay, starting at 100ms) is added before
1106    /// each restart to prevent flooding the server.
1107    pub restart_policy: Option<RestartPolicy>,
1108}
1109
1110/// Parameters used in the [Rename Container API](Docker::rename_container())
1111///
1112/// ## Examples
1113///
1114/// ```rust
1115/// use bollard_next::container::RenameContainerOptions;
1116///
1117/// RenameContainerOptions {
1118///     name: "my_new_container_name"
1119/// };
1120/// ```
1121#[derive(Debug, Clone, Default, PartialEq, Serialize)]
1122#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1123#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1124pub struct RenameContainerOptions<T>
1125where
1126    T: Into<String> + Serialize,
1127{
1128    /// New name for the container.
1129    pub name: T,
1130}
1131
1132/// Parameters used in the [Prune Containers API](Docker::prune_containers())
1133///
1134/// ## Examples
1135///
1136/// ```rust
1137/// use bollard_next::container::PruneContainersOptions;
1138///
1139/// use std::collections::HashMap;
1140///
1141/// let mut filters = HashMap::new();
1142/// filters.insert("until", vec!["10m"]);
1143///
1144/// PruneContainersOptions{
1145///     filters
1146/// };
1147/// ```
1148#[derive(Debug, Clone, Default, PartialEq, Serialize)]
1149pub struct PruneContainersOptions<T>
1150where
1151    T: Into<String> + Eq + Hash + Serialize,
1152{
1153    /// Filters to process on the prune list, encoded as JSON.
1154    ///
1155    /// Available filters:
1156    ///  - `until=<timestamp>` Prune containers created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine's time.
1157    ///  - label (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune containers with (or without, in case `label!=...` is used) the specified labels.
1158    #[serde(serialize_with = "crate::docker::serialize_as_json")]
1159    pub filters: HashMap<T, Vec<T>>,
1160}
1161
1162/// Parameters used in the [Upload To Container
1163/// API](Docker::upload_to_container)
1164///
1165/// ## Examples
1166///
1167/// ```rust
1168/// use bollard_next::container::UploadToContainerOptions;
1169///
1170/// use std::default::Default;
1171///
1172/// UploadToContainerOptions{
1173///     path: "/opt",
1174///     ..Default::default()
1175/// };
1176/// ```
1177#[derive(Debug, Clone, Default, PartialEq, Serialize)]
1178#[serde(rename_all = "camelCase")]
1179#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1180#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1181pub struct UploadToContainerOptions<T>
1182where
1183    T: Into<String> + Serialize,
1184{
1185    /// Path to a directory in the container to extract the archive’s contents into.
1186    pub path: T,
1187    /// If “1”, “true”, or “True” then it will be an error if unpacking the given content would
1188    /// cause an existing directory to be replaced with a non-directory and vice versa.
1189    pub no_overwrite_dir_non_dir: T,
1190}
1191
1192/// Parameters used in the [Download From Container
1193/// API](Docker::download_from_container())
1194///
1195/// ## Examples
1196///
1197/// ```rust
1198/// use bollard_next::container::DownloadFromContainerOptions;
1199///
1200/// DownloadFromContainerOptions{
1201///     path: "/opt",
1202/// };
1203/// ```
1204#[derive(Debug, Clone, Default, PartialEq, Serialize)]
1205pub struct DownloadFromContainerOptions<T>
1206where
1207    T: Into<String> + Serialize,
1208{
1209    /// Resource in the container’s filesystem to archive.
1210    pub path: T,
1211}
1212
1213impl Docker {
1214    /// ---
1215    ///
1216    /// # List Containers
1217    ///
1218    /// Returns a list of containers.
1219    ///
1220    /// # Arguments
1221    ///
1222    ///  - Optional [ListContainersOptions](ListContainersOptions) struct.
1223    ///
1224    /// # Returns
1225    ///
1226    ///  - Vector of [ContainerSummary](ContainerSummary), wrapped in a Future.
1227    ///
1228    /// # Examples
1229    ///
1230    /// ```rust
1231    /// # use bollard_next::Docker;
1232    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1233    /// use bollard_next::container::ListContainersOptions;
1234    ///
1235    /// use std::collections::HashMap;
1236    /// use std::default::Default;
1237    ///
1238    /// let mut filters = HashMap::new();
1239    /// filters.insert("health", vec!["unhealthy"]);
1240    ///
1241    /// let options = Some(ListContainersOptions{
1242    ///     all: true,
1243    ///     filters,
1244    ///     ..Default::default()
1245    /// });
1246    ///
1247    /// docker.list_containers(options);
1248    /// ```
1249    pub async fn list_containers<'de, T>(
1250        &self,
1251        options: Option<ListContainersOptions<T>>,
1252    ) -> Result<Vec<ContainerSummary>, Error>
1253    where
1254        T: Into<String> + Eq + Hash + Serialize,
1255    {
1256        let url = "/containers/json";
1257
1258        let req = self.build_request(
1259            url,
1260            Builder::new().method(Method::GET),
1261            options,
1262            Ok(BodyType::Left(Full::new(Bytes::new()))),
1263        );
1264
1265        self.process_into_value(req).await
1266    }
1267
1268    /// ---
1269    ///
1270    /// # Create Container
1271    ///
1272    /// Prepares a container for a subsequent start operation.
1273    ///
1274    /// # Arguments
1275    ///
1276    ///  - Optional [Create Container Options](CreateContainerOptions) struct.
1277    ///  - Container [Config](Config) struct.
1278    ///
1279    /// # Returns
1280    ///
1281    ///  - [ContainerCreateResponse](ContainerCreateResponse), wrapped in a Future.
1282    ///
1283    /// # Examples
1284    ///
1285    /// ```rust
1286    /// # use bollard_next::Docker;
1287    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1288    /// use bollard_next::container::{CreateContainerOptions, Config};
1289    ///
1290    /// use std::default::Default;
1291    ///
1292    /// let options = Some(CreateContainerOptions{
1293    ///     name: "my-new-container",
1294    ///     platform: None,
1295    /// });
1296    ///
1297    /// let config = Config {
1298    ///     image: Some("hello-world"),
1299    ///     cmd: Some(vec!["/hello"]),
1300    ///     ..Default::default()
1301    /// };
1302    ///
1303    /// docker.create_container(options, config);
1304    /// ```
1305    pub async fn create_container<T>(
1306        &self,
1307        options: Option<CreateContainerOptions<T>>,
1308        config: Config,
1309    ) -> Result<ContainerCreateResponse, Error>
1310    where
1311        T: Into<String> + Serialize,
1312    {
1313        let url = "/containers/create";
1314        let req = self.build_request(
1315            url,
1316            Builder::new().method(Method::POST),
1317            options,
1318            Docker::serialize_payload(Some(config)),
1319        );
1320
1321        self.process_into_value(req).await
1322    }
1323
1324    /// ---
1325    ///
1326    /// # Start Container
1327    ///
1328    /// Starts a container, after preparing it with the [Create Container
1329    /// API](struct.Docker.html#method.create_container).
1330    ///
1331    /// # Arguments
1332    ///
1333    ///  - Container name as a string slice.
1334    ///  - Optional [Start Container Options](StartContainerOptions) struct.
1335    ///
1336    /// # Returns
1337    ///
1338    ///  - unit type `()`, wrapped in a Future.
1339    ///
1340    /// # Examples
1341    ///
1342    /// ```rust
1343    /// # use bollard_next::Docker;
1344    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1345    /// use bollard_next::container::StartContainerOptions;
1346    ///
1347    /// docker.start_container("hello-world", None::<StartContainerOptions<String>>);
1348    /// ```
1349    pub async fn start_container<T>(
1350        &self,
1351        container_name: &str,
1352        options: Option<StartContainerOptions<T>>,
1353    ) -> Result<(), Error>
1354    where
1355        T: Into<String> + Serialize,
1356    {
1357        let url = format!("/containers/{container_name}/start");
1358
1359        let req = self.build_request(
1360            &url,
1361            Builder::new().method(Method::POST),
1362            options,
1363            Ok(BodyType::Left(Full::new(Bytes::new()))),
1364        );
1365
1366        self.process_into_unit(req).await
1367    }
1368
1369    /// ---
1370    ///
1371    /// # Stop Container
1372    ///
1373    /// Stops a container.
1374    ///
1375    /// # Arguments
1376    ///
1377    /// - Container name as string slice.
1378    /// - Optional [Stop Container Options](StopContainerOptions) struct.
1379    ///
1380    /// # Returns
1381    ///
1382    ///  - unit type `()`, wrapped in a Future.
1383    ///
1384    /// # Examples
1385    ///
1386    /// ```rust
1387    /// # use bollard_next::Docker;
1388    /// use bollard_next::container::StopContainerOptions;
1389    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1390    ///
1391    /// let options = Some(StopContainerOptions{
1392    ///     t: 30,
1393    /// });
1394    ///
1395    /// docker.stop_container("hello-world", options);
1396    /// ```
1397    pub async fn stop_container(
1398        &self,
1399        container_name: &str,
1400        options: Option<StopContainerOptions>,
1401    ) -> Result<(), Error> {
1402        let url = format!("/containers/{container_name}/stop");
1403
1404        let req = self.build_request(
1405            &url,
1406            Builder::new().method(Method::POST),
1407            options,
1408            Ok(BodyType::Left(Full::new(Bytes::new()))),
1409        );
1410
1411        self.process_into_unit(req).await
1412    }
1413
1414    /// ---
1415    ///
1416    /// # Remove Container
1417    ///
1418    /// Remove a container.
1419    ///
1420    /// # Arguments
1421    ///
1422    /// - Container name as a string slice.
1423    /// - Optional [Remove Container Options](RemoveContainerOptions) struct.
1424    ///
1425    /// # Returns
1426    ///
1427    ///  - unit type `()`, wrapped in a Future.
1428    ///
1429    /// # Examples
1430    ///
1431    /// ```rust
1432    /// # use bollard_next::Docker;
1433    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1434    ///
1435    /// use bollard_next::container::RemoveContainerOptions;
1436    ///
1437    /// use std::default::Default;
1438    ///
1439    /// let options = Some(RemoveContainerOptions{
1440    ///     force: true,
1441    ///     ..Default::default()
1442    /// });
1443    ///
1444    /// docker.remove_container("hello-world", options);
1445    /// ```
1446    pub async fn remove_container(
1447        &self,
1448        container_name: &str,
1449        options: Option<RemoveContainerOptions>,
1450    ) -> Result<(), Error> {
1451        let url = format!("/containers/{container_name}");
1452
1453        let req = self.build_request(
1454            &url,
1455            Builder::new().method(Method::DELETE),
1456            options,
1457            Ok(BodyType::Left(Full::new(Bytes::new()))),
1458        );
1459
1460        self.process_into_unit(req).await
1461    }
1462
1463    /// ---
1464    ///
1465    /// # Wait Container
1466    ///
1467    /// Wait for a container to stop. This is a non-blocking operation, the resulting stream will
1468    /// end when the container stops.
1469    ///
1470    /// # Arguments
1471    ///
1472    /// - Container name as string slice.
1473    /// - Optional [Wait Container Options](WaitContainerOptions) struct.
1474    ///
1475    /// # Returns
1476    ///
1477    ///  - [ContainerWaitResponse](ContainerWaitResponse), wrapped in a
1478    ///    Stream.
1479    ///
1480    /// # Examples
1481    ///
1482    /// ```rust
1483    /// # use bollard_next::Docker;
1484    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1485    ///
1486    /// use bollard_next::container::WaitContainerOptions;
1487    ///
1488    /// let options = Some(WaitContainerOptions{
1489    ///     condition: "not-running",
1490    /// });
1491    ///
1492    /// docker.wait_container("hello-world", options);
1493    /// ```
1494    pub fn wait_container<T>(
1495        &self,
1496        container_name: &str,
1497        options: Option<WaitContainerOptions<T>>,
1498    ) -> impl Stream<Item = Result<ContainerWaitResponse, Error>>
1499    where
1500        T: Into<String> + Serialize,
1501    {
1502        let url = format!("/containers/{container_name}/wait");
1503
1504        let req = self.build_request(
1505            &url,
1506            Builder::new().method(Method::POST),
1507            options,
1508            Ok(BodyType::Left(Full::new(Bytes::new()))),
1509        );
1510
1511        self.process_into_stream(req).map(|res| match res {
1512            Ok(ContainerWaitResponse {
1513                status_code: code,
1514                error:
1515                    Some(ContainerWaitExitError {
1516                        message: Some(error),
1517                    }),
1518            }) if code > 0 => Err(Error::DockerContainerWaitError { error, code }),
1519            Ok(ContainerWaitResponse {
1520                status_code: code,
1521                error: None,
1522            }) if code > 0 => Err(Error::DockerContainerWaitError {
1523                error: String::new(),
1524                code,
1525            }),
1526            v => v,
1527        })
1528    }
1529
1530    /// ---
1531    ///
1532    /// # Attach Container
1533    ///
1534    /// Attach to a container to read its output or send it input. You can attach to the
1535    /// same container multiple times and you can reattach to containers that have been detached.
1536    ///
1537    /// # Arguments
1538    ///
1539    /// - Container name as string slice.
1540    /// - Optional [Attach Container Options](AttachContainerOptions) struct.
1541    ///
1542    /// # Returns
1543    ///
1544    ///  - [AttachContainerResults](AttachContainerResults) wrapped in a Future.
1545    ///
1546    /// # Examples
1547    ///
1548    /// ```rust
1549    /// # use bollard_next::Docker;
1550    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1551    ///
1552    /// use bollard_next::container::AttachContainerOptions;
1553    ///
1554    /// let options = Some(AttachContainerOptions::<String>{
1555    ///     stdin: Some(true),
1556    ///     stdout: Some(true),
1557    ///     stderr: Some(true),
1558    ///     stream: Some(true),
1559    ///     logs: Some(true),
1560    ///     detach_keys: Some("ctrl-c".to_string()),
1561    /// });
1562    ///
1563    /// docker.attach_container("hello-world", options);
1564    /// ```
1565    pub async fn attach_container<T>(
1566        &self,
1567        container_name: &str,
1568        options: Option<AttachContainerOptions<T>>,
1569    ) -> Result<AttachContainerResults, Error>
1570    where
1571        T: Into<String> + Serialize + Default,
1572    {
1573        let url = format!("/containers/{container_name}/attach");
1574
1575        let req = self.build_request(
1576            &url,
1577            Builder::new()
1578                .method(Method::POST)
1579                .header(CONNECTION, "Upgrade")
1580                .header(UPGRADE, "tcp"),
1581            options,
1582            Ok(BodyType::Left(Full::new(Bytes::new()))),
1583        );
1584
1585        let (read, write) = self.process_upgraded(req).await?;
1586        let log = FramedRead::new(read, NewlineLogOutputDecoder::new(true)).map_err(|e| e.into());
1587
1588        Ok(AttachContainerResults {
1589            output: Box::pin(log),
1590            input: Box::pin(write),
1591        })
1592    }
1593
1594    /// ---
1595    ///
1596    /// # Resize container tty
1597    ///
1598    /// Resize the container's TTY.
1599    ///
1600    /// # Arguments
1601    ///
1602    /// - Container name as string slice.
1603    /// - [Resize Container Tty Options](ResizeContainerTtyOptions) struct.
1604    ///
1605    /// # Examples
1606    ///
1607    /// ```rust
1608    /// # use bollard_next::Docker;
1609    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1610    ///
1611    /// use bollard_next::container::ResizeContainerTtyOptions;
1612    ///
1613    /// let options = ResizeContainerTtyOptions {
1614    ///     width: 50,
1615    ///     height: 20,
1616    /// };
1617    ///
1618    /// docker.resize_container_tty("hello-world", options);
1619    /// ```
1620    pub async fn resize_container_tty(
1621        &self,
1622        container_name: &str,
1623        options: ResizeContainerTtyOptions,
1624    ) -> Result<(), Error> {
1625        let url = format!("/containers/{container_name}/resize");
1626
1627        let req = self.build_request(
1628            &url,
1629            Builder::new().method(Method::POST),
1630            Some(options),
1631            Ok(BodyType::Left(Full::new(Bytes::new()))),
1632        );
1633
1634        self.process_into_unit(req).await
1635    }
1636
1637    /// ---
1638    ///
1639    /// # Restart Container
1640    ///
1641    /// Restart a container.
1642    ///
1643    /// # Arguments
1644    ///
1645    ///  - Container name as string slice.
1646    ///  - Optional [Restart Container Options](RestartContainerOptions) struct.
1647    ///
1648    /// # Returns
1649    ///
1650    ///  - unit type `()`, wrapped in a Future.
1651    ///
1652    /// # Examples
1653    ///
1654    /// ```rust
1655    /// # use bollard_next::Docker;
1656    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1657    ///
1658    /// use bollard_next::container::RestartContainerOptions;
1659    ///
1660    /// let options = Some(RestartContainerOptions{
1661    ///     t: 30,
1662    /// });
1663    ///
1664    /// docker.restart_container("postgres", options);
1665    /// ```
1666    pub async fn restart_container(
1667        &self,
1668        container_name: &str,
1669        options: Option<RestartContainerOptions>,
1670    ) -> Result<(), Error> {
1671        let url = format!("/containers/{container_name}/restart");
1672
1673        let req = self.build_request(
1674            &url,
1675            Builder::new().method(Method::POST),
1676            options,
1677            Ok(BodyType::Left(Full::new(Bytes::new()))),
1678        );
1679
1680        self.process_into_unit(req).await
1681    }
1682
1683    /// ---
1684    ///
1685    /// # Inspect Container
1686    ///
1687    /// Inspect a container.
1688    ///
1689    /// # Arguments
1690    ///
1691    ///  - Container name as a string slice.
1692    ///  - Optional [Inspect Container Options](InspectContainerOptions) struct.
1693    ///
1694    /// # Returns
1695    ///
1696    ///  - [ContainerInspectResponse](ContainerInspectResponse), wrapped in a Future.
1697    ///
1698    /// # Examples
1699    ///
1700    /// ```rust
1701    /// # use bollard_next::Docker;
1702    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1703    /// use bollard_next::container::InspectContainerOptions;
1704    ///
1705    /// let options = Some(InspectContainerOptions{
1706    ///     size: false,
1707    /// });
1708    ///
1709    /// docker.inspect_container("hello-world", options);
1710    /// ```
1711    pub async fn inspect_container(
1712        &self,
1713        container_name: &str,
1714        options: Option<InspectContainerOptions>,
1715    ) -> Result<ContainerInspectResponse, Error> {
1716        let url = format!("/containers/{container_name}/json");
1717
1718        let req = self.build_request(
1719            &url,
1720            Builder::new().method(Method::GET),
1721            options,
1722            Ok(BodyType::Left(Full::new(Bytes::new()))),
1723        );
1724
1725        self.process_into_value(req).await
1726    }
1727
1728    /// ---
1729    ///
1730    /// # Top Processes
1731    ///
1732    /// List processes running inside a container.
1733    ///
1734    /// # Arguments
1735    ///
1736    ///  - Container name as string slice.
1737    ///  - Optional [Top Options](TopOptions) struct.
1738    ///
1739    /// # Returns
1740    ///
1741    ///  - [ContainerTopResponse](ContainerTopResponse), wrapped in a Future.
1742    ///
1743    /// # Examples
1744    ///
1745    /// ```rust
1746    /// # use bollard_next::Docker;
1747    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1748    /// use bollard_next::container::TopOptions;
1749    ///
1750    /// let options = Some(TopOptions{
1751    ///     ps_args: "aux",
1752    /// });
1753    ///
1754    /// docker.top_processes("fussybeaver/uhttpd", options);
1755    /// ```
1756    pub async fn top_processes<T>(
1757        &self,
1758        container_name: &str,
1759        options: Option<TopOptions<T>>,
1760    ) -> Result<ContainerTopResponse, Error>
1761    where
1762        T: Into<String> + Serialize,
1763    {
1764        let url = format!("/containers/{container_name}/top");
1765
1766        let req = self.build_request(
1767            &url,
1768            Builder::new().method(Method::GET),
1769            options,
1770            Ok(BodyType::Left(Full::new(Bytes::new()))),
1771        );
1772
1773        self.process_into_value(req).await
1774    }
1775
1776    /// ---
1777    ///
1778    /// # Logs
1779    ///
1780    /// Get container logs.
1781    ///
1782    /// # Arguments
1783    ///
1784    ///  - Container name as string slice.
1785    ///  - Optional [Logs Options](LogsOptions) struct.
1786    ///
1787    /// # Returns
1788    ///
1789    ///  - [Log Output](LogOutput) enum, wrapped in a
1790    ///    Stream.
1791    ///
1792    /// # Examples
1793    ///
1794    /// ```rust
1795    /// # use bollard_next::Docker;
1796    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1797    ///
1798    /// use bollard_next::container::LogsOptions;
1799    ///
1800    /// use std::default::Default;
1801    ///
1802    /// let options = Some(LogsOptions::<String>{
1803    ///     stdout: true,
1804    ///     ..Default::default()
1805    /// });
1806    ///
1807    /// docker.logs("hello-world", options);
1808    /// ```
1809    pub fn logs<T>(
1810        &self,
1811        container_name: &str,
1812        options: Option<LogsOptions<T>>,
1813    ) -> impl Stream<Item = Result<LogOutput, Error>>
1814    where
1815        T: Into<String> + Serialize,
1816    {
1817        let url = format!("/containers/{container_name}/logs");
1818
1819        let req = self.build_request(
1820            &url,
1821            Builder::new().method(Method::GET),
1822            options,
1823            Ok(BodyType::Left(Full::new(Bytes::new()))),
1824        );
1825
1826        self.process_into_stream_string(req)
1827    }
1828
1829    /// ---
1830    ///
1831    /// # Container Changes
1832    ///
1833    /// Get changes on a container's filesystem.
1834    ///
1835    /// # Arguments
1836    ///
1837    ///  - Container name as string slice.
1838    ///
1839    /// # Returns
1840    ///
1841    ///  - An Option of Vector of [File System Change](FilesystemChange) structs, wrapped in a
1842    ///    Future.
1843    ///
1844    /// # Examples
1845    ///
1846    /// ```rust
1847    /// # use bollard_next::Docker;
1848    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1849    ///
1850    /// docker.container_changes("hello-world");
1851    /// ```
1852    pub async fn container_changes(
1853        &self,
1854        container_name: &str,
1855    ) -> Result<Option<Vec<FilesystemChange>>, Error> {
1856        let url = format!("/containers/{container_name}/changes");
1857
1858        let req = self.build_request(
1859            &url,
1860            Builder::new().method(Method::GET),
1861            None::<String>,
1862            Ok(BodyType::Left(Full::new(Bytes::new()))),
1863        );
1864
1865        self.process_into_value(req).await
1866    }
1867
1868    /// ---
1869    ///
1870    /// # Stats
1871    ///
1872    /// Get container stats based on resource usage.
1873    ///
1874    /// # Arguments
1875    ///
1876    /// - Container name as string slice.
1877    /// - Optional [Stats Options](StatsOptions) struct.
1878    ///
1879    /// # Returns
1880    ///
1881    ///  - [Stats](Stats) struct, wrapped in a
1882    ///    Stream.
1883    ///
1884    /// # Examples
1885    ///
1886    /// ```rust
1887    /// # use bollard_next::Docker;
1888    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1889    ///
1890    /// use bollard_next::container::StatsOptions;
1891    ///
1892    /// let options = Some(StatsOptions{
1893    ///     stream: false,
1894    ///     one_shot: true,
1895    /// });
1896    ///
1897    /// docker.stats("hello-world", options);
1898    /// ```
1899    pub fn stats(
1900        &self,
1901        container_name: &str,
1902        options: Option<StatsOptions>,
1903    ) -> impl Stream<Item = Result<Stats, Error>> {
1904        let url = format!("/containers/{container_name}/stats");
1905
1906        let req = self.build_request(
1907            &url,
1908            Builder::new().method(Method::GET),
1909            options,
1910            Ok(BodyType::Left(Full::new(Bytes::new()))),
1911        );
1912
1913        self.process_into_stream(req)
1914    }
1915
1916    /// ---
1917    ///
1918    /// # Kill Container
1919    ///
1920    /// Kill a container.
1921    ///
1922    /// # Arguments
1923    ///
1924    /// - Container name as string slice.
1925    /// - Optional [Kill Container Options](KillContainerOptions) struct.
1926    ///
1927    /// # Returns
1928    ///
1929    ///  - unit type `()`, wrapped in a Future.
1930    ///
1931    /// # Examples
1932    ///
1933    /// ```rust
1934    /// # use bollard_next::Docker;
1935    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1936    ///
1937    /// use bollard_next::container::KillContainerOptions;
1938    ///
1939    /// let options = Some(KillContainerOptions{
1940    ///     signal: "SIGINT",
1941    /// });
1942    ///
1943    /// docker.kill_container("postgres", options);
1944    /// ```
1945    pub async fn kill_container<T>(
1946        &self,
1947        container_name: &str,
1948        options: Option<KillContainerOptions<T>>,
1949    ) -> Result<(), Error>
1950    where
1951        T: Into<String> + Serialize,
1952    {
1953        let url = format!("/containers/{container_name}/kill");
1954
1955        let req = self.build_request(
1956            &url,
1957            Builder::new().method(Method::POST),
1958            options,
1959            Ok(BodyType::Left(Full::new(Bytes::new()))),
1960        );
1961
1962        self.process_into_unit(req).await
1963    }
1964
1965    /// ---
1966    ///
1967    /// # Update Container
1968    ///
1969    /// Update a container.
1970    ///
1971    /// # Arguments
1972    ///
1973    ///  - Container name as string slice.
1974    ///  - [Update Container Options](UpdateContainerOptions) struct.
1975    ///
1976    /// # Returns
1977    ///
1978    ///  - unit type `()`, wrapped in a Future.
1979    ///
1980    /// # Examples
1981    ///
1982    /// ```rust
1983    /// # use bollard_next::Docker;
1984    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1985    ///
1986    /// use bollard_next::container::UpdateContainerOptions;
1987    /// use std::default::Default;
1988    ///
1989    /// let config = UpdateContainerOptions::<String> {
1990    ///     memory: Some(314572800),
1991    ///     memory_swap: Some(314572800),
1992    ///     ..Default::default()
1993    /// };
1994    ///
1995    /// docker.update_container("postgres", config);
1996    /// ```
1997    pub async fn update_container<T>(
1998        &self,
1999        container_name: &str,
2000        config: UpdateContainerOptions<T>,
2001    ) -> Result<(), Error>
2002    where
2003        T: Into<String> + Eq + Hash + Serialize,
2004    {
2005        let url = format!("/containers/{container_name}/update");
2006
2007        let req = self.build_request(
2008            &url,
2009            Builder::new().method(Method::POST),
2010            None::<String>,
2011            Docker::serialize_payload(Some(config)),
2012        );
2013
2014        self.process_into_unit(req).await
2015    }
2016
2017    /// ---
2018    ///
2019    /// # Rename Container
2020    ///
2021    /// Rename a container.
2022    ///
2023    /// # Arguments
2024    ///
2025    ///  - Container name as string slice.
2026    ///  - [Rename Container Options](RenameContainerOptions) struct
2027    ///
2028    /// # Returns
2029    ///
2030    ///  - unit type `()`, wrapped in a Future.
2031    ///
2032    /// # Examples
2033    ///
2034    /// ```rust
2035    /// # use bollard_next::Docker;
2036    /// # let docker = Docker::connect_with_http_defaults().unwrap();
2037    ///
2038    /// use bollard_next::container::RenameContainerOptions;
2039    ///
2040    /// let required = RenameContainerOptions {
2041    ///     name: "my_new_container_name"
2042    /// };
2043    ///
2044    /// docker.rename_container("hello-world", required);
2045    /// ```
2046    pub async fn rename_container<T>(
2047        &self,
2048        container_name: &str,
2049        options: RenameContainerOptions<T>,
2050    ) -> Result<(), Error>
2051    where
2052        T: Into<String> + Serialize,
2053    {
2054        let url = format!("/containers/{container_name}/rename");
2055
2056        let req = self.build_request(
2057            &url,
2058            Builder::new().method(Method::POST),
2059            Some(options),
2060            Ok(BodyType::Left(Full::new(Bytes::new()))),
2061        );
2062
2063        self.process_into_unit(req).await
2064    }
2065
2066    /// ---
2067    ///
2068    /// # Pause Container
2069    ///
2070    /// Use the cgroups freezer to suspend all processes in a container.
2071    ///
2072    /// # Arguments
2073    ///
2074    ///  - Container name as a string slice.
2075    ///
2076    /// # Returns
2077    ///
2078    ///  - unit type `()`, wrapped in a Future.
2079    ///
2080    /// # Examples
2081    ///
2082    /// ```rust
2083    /// # use bollard_next::Docker;
2084    /// # let docker = Docker::connect_with_http_defaults().unwrap();
2085    ///
2086    /// docker.pause_container("postgres");
2087    /// ```
2088    pub async fn pause_container(&self, container_name: &str) -> Result<(), Error> {
2089        let url = format!("/containers/{container_name}/pause");
2090
2091        let req = self.build_request(
2092            &url,
2093            Builder::new().method(Method::POST),
2094            None::<String>,
2095            Ok(BodyType::Left(Full::new(Bytes::new()))),
2096        );
2097
2098        self.process_into_unit(req).await
2099    }
2100
2101    /// ---
2102    ///
2103    /// # Unpause Container
2104    ///
2105    /// Resume a container which has been paused.
2106    ///
2107    /// # Arguments
2108    ///
2109    ///  - Container name as a string slice.
2110    ///
2111    /// # Returns
2112    ///
2113    ///  - unit type `()`, wrapped in a Future.
2114    ///
2115    /// # Examples
2116    ///
2117    /// ```rust
2118    /// # use bollard_next::Docker;
2119    /// # let docker = Docker::connect_with_http_defaults().unwrap();
2120    ///
2121    /// docker.unpause_container("postgres");
2122    /// ```
2123    pub async fn unpause_container(&self, container_name: &str) -> Result<(), Error> {
2124        let url = format!("/containers/{container_name}/unpause");
2125
2126        let req = self.build_request(
2127            &url,
2128            Builder::new().method(Method::POST),
2129            None::<String>,
2130            Ok(BodyType::Left(Full::new(Bytes::new()))),
2131        );
2132
2133        self.process_into_unit(req).await
2134    }
2135
2136    /// ---
2137    ///
2138    /// # Prune Containers
2139    ///
2140    /// Delete stopped containers.
2141    ///
2142    /// # Arguments
2143    ///
2144    ///  - Optional [Prune Containers Options](PruneContainersOptions) struct.
2145    ///
2146    /// # Returns
2147    ///
2148    ///  - [Container Prune Response](ContainerPruneResponse) struct, wrapped in a Future.
2149    ///
2150    /// # Examples
2151    ///
2152    /// ```rust
2153    /// # use bollard_next::Docker;
2154    /// # let docker = Docker::connect_with_http_defaults().unwrap();
2155    /// use bollard_next::container::PruneContainersOptions;
2156    ///
2157    /// use std::collections::HashMap;
2158    ///
2159    /// let mut filters = HashMap::new();
2160    /// filters.insert("until", vec!["10m"]);
2161    ///
2162    /// let options = Some(PruneContainersOptions{
2163    ///     filters
2164    /// });
2165    ///
2166    /// docker.prune_containers(options);
2167    /// ```
2168    pub async fn prune_containers<T>(
2169        &self,
2170        options: Option<PruneContainersOptions<T>>,
2171    ) -> Result<ContainerPruneResponse, Error>
2172    where
2173        T: Into<String> + Eq + Hash + Serialize,
2174    {
2175        let url = "/containers/prune";
2176
2177        let req = self.build_request(
2178            url,
2179            Builder::new().method(Method::POST),
2180            options,
2181            Ok(BodyType::Left(Full::new(Bytes::new()))),
2182        );
2183
2184        self.process_into_value(req).await
2185    }
2186
2187    /// ---
2188    ///
2189    /// # Stream Upload To Container
2190    ///
2191    /// Stream an upload of a tar archive to be extracted to a path in the filesystem of container
2192    /// id.
2193    ///
2194    /// # Arguments
2195    ///
2196    ///  - Optional [Upload To Container Options](UploadToContainerOptions) struct.
2197    ///
2198    /// # Returns
2199    ///
2200    ///  - unit type `()`, wrapped in a Future.
2201    ///
2202    /// # Examples
2203    ///
2204    /// ```rust,no_run
2205    /// # use bollard::Docker;
2206    /// use bollard::container::UploadToContainerOptions;
2207    /// use futures_util::{StreamExt, TryFutureExt};
2208    /// use tokio::fs::File;
2209    /// use tokio_util::io::ReaderStream;
2210    ///
2211    /// # #[tokio::main]
2212    /// # async fn main() {
2213    /// # let docker = Docker::connect_with_http_defaults().unwrap();
2214    /// let options = Some(UploadToContainerOptions{
2215    ///     path: "/opt",
2216    ///     ..Default::default()
2217    /// });
2218    ///
2219    /// let file = File::open("tarball.tar.gz")
2220    ///     .map_ok(ReaderStream::new)
2221    ///     .try_flatten_stream()
2222    ///     .map(|x|x.expect("failed to stream file"));
2223    ///
2224    /// docker
2225    ///     .upload_to_container_streaming("my-container", options, file)
2226    ///     .await
2227    ///     .expect("upload failed");
2228    /// # }
2229    /// ```
2230    pub async fn upload_to_container_streaming<T>(
2231        &self,
2232        container_name: &str,
2233        options: Option<UploadToContainerOptions<T>>,
2234        tar: impl Stream<Item = Bytes> + Send + 'static,
2235    ) -> Result<(), Error>
2236    where
2237        T: Into<String> + Serialize,
2238    {
2239        let url = format!("/containers/{container_name}/archive");
2240
2241        let req = self.build_request(
2242            &url,
2243            Builder::new()
2244                .method(Method::PUT)
2245                .header(CONTENT_TYPE, "application/x-tar"),
2246            options,
2247            Ok(body_stream(tar)),
2248        );
2249
2250        self.process_into_unit(req).await
2251    }
2252
2253    /// ---
2254    ///
2255    /// # Upload To Container
2256    ///
2257    /// Upload a tar archive to be extracted to a path in the filesystem of container id.
2258    ///
2259    /// # Arguments
2260    ///
2261    ///  - Optional [Upload To Container Options](UploadToContainerOptions) struct.
2262    ///
2263    /// # Returns
2264    ///
2265    ///  - unit type `()`, wrapped in a Future.
2266    ///
2267    /// # Examples
2268    ///
2269    /// ```rust,no_run
2270    /// # use bollard::Docker;
2271    /// use bollard::container::UploadToContainerOptions;
2272    /// use std::fs::File;
2273    /// use std::io::Read;
2274    ///
2275    /// # #[tokio::main]
2276    /// # async fn main() {
2277    /// # let docker = Docker::connect_with_http_defaults().unwrap();
2278    /// let options = Some(UploadToContainerOptions{
2279    ///     path: "/opt",
2280    ///     ..Default::default()
2281    /// });
2282    ///
2283    /// let mut file = File::open("tarball.tar.gz").unwrap();
2284    /// let mut contents = Vec::new();
2285    /// file.read_to_end(&mut contents).unwrap();
2286    ///
2287    /// docker
2288    ///     .upload_to_container("my-container", options, contents.into())
2289    ///     .await
2290    ///     .expect("upload failed");
2291    /// # }
2292    /// ```
2293    pub async fn upload_to_container<T>(
2294        &self,
2295        container_name: &str,
2296        options: Option<UploadToContainerOptions<T>>,
2297        tar: Bytes,
2298    ) -> Result<(), Error>
2299    where
2300        T: Into<String> + Serialize,
2301    {
2302        let url = format!("/containers/{container_name}/archive");
2303
2304        let req = self.build_request(
2305            &url,
2306            Builder::new()
2307                .method(Method::PUT)
2308                .header(CONTENT_TYPE, "application/x-tar"),
2309            options,
2310            Ok(BodyType::Left(Full::new(tar))),
2311        );
2312
2313        self.process_into_unit(req).await
2314    }
2315
2316    /// ---
2317    ///
2318    /// # Download From Container
2319    ///
2320    /// Get a tar archive of a resource in the filesystem of container id.
2321    ///
2322    /// # Arguments
2323    ///
2324    ///  - [Download From Container Options](DownloadFromContainerOptions) struct.
2325    ///
2326    /// # Returns
2327    ///
2328    ///  - Tar archive compressed with one of the following algorithms: identity (no compression),
2329    ///    gzip, bzip2, xz. [Hyper Body](hyper::body::Body).
2330    ///
2331    /// # Examples
2332    ///
2333    /// ```rust
2334    /// # use bollard_next::Docker;
2335    /// # let docker = Docker::connect_with_http_defaults().unwrap();
2336    /// use bollard_next::container::DownloadFromContainerOptions;
2337    ///
2338    /// let options = Some(DownloadFromContainerOptions{
2339    ///     path: "/opt",
2340    /// });
2341    ///
2342    /// docker.download_from_container("my-container", options);
2343    /// ```
2344    pub fn download_from_container<T>(
2345        &self,
2346        container_name: &str,
2347        options: Option<DownloadFromContainerOptions<T>>,
2348    ) -> impl Stream<Item = Result<Bytes, Error>>
2349    where
2350        T: Into<String> + Serialize,
2351    {
2352        let url = format!("/containers/{container_name}/archive");
2353
2354        let req = self.build_request(
2355            &url,
2356            Builder::new().method(Method::GET),
2357            options,
2358            Ok(BodyType::Left(Full::new(Bytes::new()))),
2359        );
2360
2361        self.process_into_body(req)
2362    }
2363
2364    /// ---
2365    ///
2366    /// # Export Container
2367    ///
2368    /// Get a tarball containing the filesystem contents of a container.
2369    ///
2370    /// See the [Docker API documentation](https://docs.docker.com/engine/api/v1.40/#operation/ContainerExport)
2371    /// for more information.
2372    /// # Arguments
2373    /// - The `container_name` string referring to an individual container
2374    ///
2375    /// # Returns
2376    ///  - An uncompressed TAR archive
2377    pub fn export_container(
2378        &self,
2379        container_name: &str,
2380    ) -> impl Stream<Item = Result<Bytes, Error>> {
2381        let url = format!("/containers/{container_name}/export");
2382        let req = self.build_request(
2383            &url,
2384            Builder::new()
2385                .method(Method::GET)
2386                .header(CONTENT_TYPE, "application/json"),
2387            None::<String>,
2388            Ok(BodyType::Left(Full::new(Bytes::new()))),
2389        );
2390        self.process_into_body(req)
2391    }
2392}
2393
2394#[cfg(not(windows))]
2395#[cfg(test)]
2396mod tests {
2397
2398    use futures_util::TryStreamExt;
2399    use yup_hyper_mock::HostToReplyConnector;
2400
2401    use crate::{Docker, API_DEFAULT_VERSION};
2402
2403    use super::WaitContainerOptions;
2404
2405    #[tokio::test]
2406    async fn test_container_wait_with_error() {
2407        let mut connector = HostToReplyConnector::default();
2408        connector.m.insert(
2409            String::from("http://127.0.0.1"),
2410            "HTTP/1.1 200 OK\r\nServer:mock1\r\nContent-Type:application/json\r\n\r\n{\"Error\":null,\"StatusCode\":1}".to_string(),
2411        );
2412
2413        let docker =
2414            Docker::connect_with_mock(connector, "127.0.0.1".to_string(), 5, API_DEFAULT_VERSION)
2415                .unwrap();
2416
2417        let result = &docker
2418            .wait_container("wait_container_test", None::<WaitContainerOptions<String>>)
2419            .try_collect::<Vec<_>>()
2420            .await;
2421
2422        assert!(matches!(
2423            result,
2424            Err(crate::errors::Error::DockerContainerWaitError { code: _, error: _ })
2425        ));
2426    }
2427}