bollard/
image.rs

1//! Image API: creating, manipulating and pushing docker images
2#![allow(deprecated)]
3#[cfg(feature = "buildkit_providerless")]
4use bollard_buildkit_proto::moby::filesync::packet::file_send_server::FileSendServer as FileSendPacketServer;
5use bytes::Bytes;
6use futures_core::Stream;
7#[cfg(feature = "buildkit_providerless")]
8use futures_util::future::{Either, FutureExt};
9#[cfg(feature = "buildkit_providerless")]
10use futures_util::stream;
11use futures_util::stream::StreamExt;
12use http::header::CONTENT_TYPE;
13use http::request::Builder;
14use http_body_util::Full;
15use hyper::Method;
16use serde::Serialize;
17use serde_repr::*;
18
19use super::Docker;
20use crate::auth::{DockerCredentials, DockerCredentialsHeader};
21use crate::docker::{body_stream, BodyType};
22use crate::errors::Error;
23use crate::models::*;
24
25use std::cmp::Eq;
26use std::collections::HashMap;
27use std::hash::Hash;
28
29/// Parameters available for pulling an image, used in the [Create Image
30/// API](Docker::create_image)
31///
32/// ## Examples
33///
34/// ```rust
35/// use bollard::image::CreateImageOptions;
36///
37/// use std::default::Default;
38///
39/// CreateImageOptions{
40///   from_image: "hello-world",
41///   ..Default::default()
42/// };
43/// ```
44///
45/// ```rust
46/// # use bollard::image::CreateImageOptions;
47/// # use std::default::Default;
48/// CreateImageOptions::<String>{
49///   ..Default::default()
50/// };
51/// ```
52#[derive(Debug, Clone, Default, PartialEq, Serialize)]
53#[deprecated(
54    since = "0.19.0",
55    note = "use the OpenAPI generated bollard::query_parameters::CreateImageOptions and associated CreateImageOptionsBuilder"
56)]
57#[serde(rename_all = "camelCase")]
58pub struct CreateImageOptions<'a, T>
59where
60    T: Into<String> + Serialize,
61{
62    /// Name of the image to pull. The name may include a tag or digest. This parameter may only be
63    /// used when pulling an image. The pull is cancelled if the HTTP connection is closed.
64    pub from_image: T,
65    /// Source to import. The value may be a URL from which the image can be retrieved or `-` to
66    /// read the image from the request body. This parameter may only be used when importing an
67    /// image.
68    pub from_src: T,
69    /// Repository name given to an image when it is imported. The repo may include a tag. This
70    /// parameter may only be used when importing an image.
71    pub repo: T,
72    /// Tag or digest. If empty when pulling an image, this causes all tags for the given image to
73    /// be pulled.
74    pub tag: T,
75    /// Platform in the format `os[/arch[/variant]]`
76    pub platform: T,
77    /// A list of Dockerfile instructions to be applied to the image being created. Changes must be
78    /// URL-encoded! This parameter may only be used when importing an image.
79    #[serde(
80        serialize_with = "crate::docker::serialize_join_newlines",
81        skip_serializing_if = "Vec::is_empty" // if an empty changes parameter is sent, Docker returns a 400 "file with no instructions" error
82    )]
83    pub changes: Vec<&'a str>,
84}
85
86impl<T> From<CreateImageOptions<'_, T>> for crate::query_parameters::CreateImageOptions
87where
88    T: Into<String> + Serialize,
89{
90    fn from(opts: CreateImageOptions<'_, T>) -> Self {
91        crate::query_parameters::CreateImageOptionsBuilder::default()
92            .from_image(&opts.from_image.into())
93            .from_src(&opts.from_src.into())
94            .repo(&opts.repo.into())
95            .tag(&opts.tag.into())
96            .platform(&opts.platform.into())
97            .changes(opts.changes.into_iter().map(ToString::to_string).collect())
98            .build()
99    }
100}
101
102/// Parameters to the [List Images
103/// API](Docker::list_images())
104///
105/// ## Examples
106///
107/// ```rust
108/// use bollard::image::ListImagesOptions;
109///
110/// use std::collections::HashMap;
111/// use std::default::Default;
112///
113/// let mut filters = HashMap::new();
114/// filters.insert("dangling", vec!["true"]);
115///
116/// ListImagesOptions{
117///   all: true,
118///   filters,
119///   ..Default::default()
120/// };
121/// ```
122///
123/// ```rust
124/// # use bollard::image::ListImagesOptions;
125/// # use std::default::Default;
126/// ListImagesOptions::<String>{
127///   ..Default::default()
128/// };
129/// ```
130///
131#[derive(Debug, Clone, Default, PartialEq, Serialize)]
132#[deprecated(
133    since = "0.19.0",
134    note = "use the OpenAPI generated bollard::query_parameters::ListImageOptions and associated ListImageOptionsBuilder"
135)]
136pub struct ListImagesOptions<T>
137where
138    T: Into<String> + Eq + Hash + Serialize,
139{
140    /// Show all images. Only images from a final layer (no children) are shown by default.
141    pub all: bool,
142    /// A JSON encoded value of the filters to process on the images list. Available filters:
143    ///  - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
144    ///  - `dangling`=`true`
145    ///  - `label`=`key` or `label`=`"key=value"` of an image label
146    ///  - `reference`=(`<image-name>[:<tag>]`)
147    ///  - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
148    #[serde(serialize_with = "crate::docker::serialize_as_json")]
149    pub filters: HashMap<T, Vec<T>>,
150    /// Show digest information as a RepoDigests field on each image.
151    pub digests: bool,
152}
153
154impl<T> From<ListImagesOptions<T>> for crate::query_parameters::ListImagesOptions
155where
156    T: Into<String> + Eq + Hash + Serialize,
157{
158    fn from(opts: ListImagesOptions<T>) -> Self {
159        crate::query_parameters::ListImagesOptionsBuilder::default()
160            .all(opts.all)
161            .filters(
162                &opts
163                    .filters
164                    .into_iter()
165                    .map(|(k, v)| (k.into(), v.into_iter().map(T::into).collect()))
166                    .collect(),
167            )
168            .digests(opts.digests)
169            .build()
170    }
171}
172
173/// Parameters to the [Prune Images API](Docker::prune_images())
174///
175/// ## Examples
176///
177/// ```rust
178/// use bollard::image::PruneImagesOptions;
179///
180/// use std::collections::HashMap;
181///
182/// let mut filters = HashMap::new();
183/// filters.insert("until", vec!["10m"]);
184///
185/// PruneImagesOptions{
186///   filters,
187/// };
188/// ```
189///
190/// ```rust
191/// # use bollard::image::PruneImagesOptions;
192/// # use std::default::Default;
193/// PruneImagesOptions::<String>{
194///   ..Default::default()
195/// };
196/// ```
197///
198#[derive(Debug, Clone, Default, PartialEq, Serialize)]
199#[deprecated(
200    since = "0.19.0",
201    note = "use the OpenAPI generated bollard::query_parameters::PruneImagesOptions and associated PruneImagesOptionsBuilder"
202)]
203pub struct PruneImagesOptions<T>
204where
205    T: Into<String> + Eq + Hash + Serialize,
206{
207    /// Filters to process on the prune list, encoded as JSON. Available filters:
208    ///  - `dangling=<boolean>` When set to `true` (or `1`), prune only unused *and* untagged
209    ///    images. When set to `false` (or `0`), all unused images are pruned.
210    ///  - `until=<string>` Prune images created before this timestamp. The `<timestamp>` can be
211    ///    Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`)
212    ///    computed relative to the daemon machine’s time.
213    ///  - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or
214    ///    `label!=<key>=<value>`) Prune images with (or without, in case `label!=...` is used) the
215    ///    specified labels.
216    #[serde(serialize_with = "crate::docker::serialize_as_json")]
217    pub filters: HashMap<T, Vec<T>>,
218}
219
220impl<T> From<PruneImagesOptions<T>> for crate::query_parameters::PruneImagesOptions
221where
222    T: Into<String> + Eq + Hash + Serialize,
223{
224    fn from(opts: PruneImagesOptions<T>) -> Self {
225        crate::query_parameters::PruneImagesOptionsBuilder::default()
226            .filters(
227                &opts
228                    .filters
229                    .into_iter()
230                    .map(|(k, v)| (k.into(), v.into_iter().map(T::into).collect()))
231                    .collect(),
232            )
233            .build()
234    }
235}
236
237/// Parameters to the [Search Images API](Docker::search_images())
238///
239/// ## Example
240///
241/// ```rust
242/// use bollard::image::SearchImagesOptions;
243/// use std::default::Default;
244/// use std::collections::HashMap;
245///
246/// let mut filters = HashMap::new();
247/// filters.insert("until", vec!["10m"]);
248///
249/// SearchImagesOptions {
250///     term: "hello-world",
251///     filters,
252///     ..Default::default()
253/// };
254/// ```
255///
256/// ```rust
257/// # use bollard::image::SearchImagesOptions;
258/// # use std::default::Default;
259/// SearchImagesOptions::<String> {
260///     ..Default::default()
261/// };
262/// ```
263#[derive(Debug, Clone, Default, PartialEq, Serialize)]
264#[deprecated(
265    since = "0.19.0",
266    note = "use the OpenAPI generated bollard::query_parameters::SearchImagesOptions and associated SearchImagesOptionsBuilder"
267)]
268pub struct SearchImagesOptions<T>
269where
270    T: Into<String> + Eq + Hash + Serialize,
271{
272    /// Term to search (required)
273    pub term: T,
274    /// Maximum number of results to return
275    pub limit: Option<u64>,
276    /// A JSON encoded value of the filters to process on the images list. Available filters:
277    ///  - `is-automated=(true|false)`
278    ///  - `is-official=(true|false)`
279    ///  - `stars=<number>` Matches images that has at least 'number' stars.
280    #[serde(serialize_with = "crate::docker::serialize_as_json")]
281    pub filters: HashMap<T, Vec<T>>,
282}
283
284impl<T> From<SearchImagesOptions<T>> for crate::query_parameters::SearchImagesOptions
285where
286    T: Into<String> + Eq + Hash + Serialize,
287{
288    fn from(opts: SearchImagesOptions<T>) -> Self {
289        let mut builder = crate::query_parameters::SearchImagesOptionsBuilder::default()
290            .term(&opts.term.into())
291            .filters(
292                &opts
293                    .filters
294                    .into_iter()
295                    .map(|(k, v)| (k.into(), v.into_iter().map(T::into).collect()))
296                    .collect(),
297            );
298        if let Some(limit) = opts.limit {
299            builder = builder.limit(
300                i32::try_from(limit)
301                    .inspect_err(|e| {
302                        log::error!("Truncation of u64 into i32 in SearchImagesOptions: {e:?}")
303                    })
304                    .unwrap_or(limit as i32),
305            )
306        }
307
308        builder.build()
309    }
310}
311
312/// Parameters to the [Remove Image API](Docker::remove_image())
313///
314/// ## Examples
315///
316/// ```rust
317/// use bollard::image::RemoveImageOptions;
318/// use std::default::Default;
319///
320/// RemoveImageOptions {
321///     force: true,
322///     ..Default::default()
323/// };
324/// ```
325#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
326#[deprecated(
327    since = "0.19.0",
328    note = "use the OpenAPI generated bollard::query_parameters::RemoveImageOptions and associated RemoveImageOptionsBuilder"
329)]
330pub struct RemoveImageOptions {
331    /// Remove the image even if it is being used by stopped containers or has other tags.
332    pub force: bool,
333    /// Do not delete untagged parent images.
334    pub noprune: bool,
335}
336
337impl From<RemoveImageOptions> for crate::query_parameters::RemoveImageOptions {
338    fn from(opts: RemoveImageOptions) -> Self {
339        crate::query_parameters::RemoveImageOptionsBuilder::default()
340            .force(opts.force)
341            .noprune(opts.noprune)
342            .build()
343    }
344}
345
346/// Parameters to the [Tag Image API](Docker::tag_image())
347///
348/// ## Examples
349///
350/// ```rust
351/// use bollard::image::TagImageOptions;
352/// use std::default::Default;
353///
354/// let tag_options = TagImageOptions {
355///     tag: "v1.0.1",
356///     ..Default::default()
357/// };
358/// ```
359///
360/// ```rust
361/// # use bollard::image::TagImageOptions;
362/// # use std::default::Default;
363/// let tag_options = TagImageOptions::<String> {
364///     ..Default::default()
365/// };
366/// ```
367#[derive(Debug, Clone, Default, PartialEq, Serialize)]
368#[deprecated(
369    since = "0.19.0",
370    note = "use the OpenAPI generated bollard::query_parameters::TagImageOptions and associated TagImageOptionsBuilder"
371)]
372pub struct TagImageOptions<T>
373where
374    T: Into<String> + Serialize,
375{
376    /// The repository to tag in. For example, `someuser/someimage`.
377    pub repo: T,
378    /// The name of the new tag.
379    pub tag: T,
380}
381
382impl<T> From<TagImageOptions<T>> for crate::query_parameters::TagImageOptions
383where
384    T: Into<String> + Serialize,
385{
386    fn from(opts: TagImageOptions<T>) -> Self {
387        crate::query_parameters::TagImageOptionsBuilder::default()
388            .repo(&opts.repo.into())
389            .tag(&opts.tag.into())
390            .build()
391    }
392}
393
394/// Parameters to the [Push Image API](Docker::push_image())
395///
396/// ## Examples
397///
398/// ```rust
399/// use bollard::image::PushImageOptions;
400///
401/// PushImageOptions {
402///     tag: "v1.0.1",
403/// };
404/// ```
405///
406/// ```
407/// # use bollard::image::PushImageOptions;
408/// # use std::default::Default;
409/// PushImageOptions::<String> {
410///     ..Default::default()
411/// };
412/// ```
413#[derive(Debug, Clone, Default, PartialEq, Serialize)]
414#[deprecated(
415    since = "0.19.0",
416    note = "use the OpenAPI generated bollard::query_parameters::PushImageOptions and associated PushImageOptionsBuilder"
417)]
418pub struct PushImageOptions<T>
419where
420    T: Into<String> + Serialize,
421{
422    /// The tag to associate with the image on the registry.
423    pub tag: T,
424}
425
426impl<T> From<PushImageOptions<T>> for crate::query_parameters::PushImageOptions
427where
428    T: Into<String> + Serialize,
429{
430    fn from(opts: PushImageOptions<T>) -> Self {
431        crate::query_parameters::PushImageOptionsBuilder::default()
432            .tag(&opts.tag.into())
433            .build()
434    }
435}
436
437/// Parameters to the [Commit Container API](Docker::commit_container())
438///
439/// ## Examples
440///
441/// ```rust
442/// use bollard::image::CommitContainerOptions;
443///
444/// CommitContainerOptions {
445///     container: "my-running-container",
446///     pause: true,
447///     ..Default::default()
448/// };
449/// ```
450///
451/// ```
452/// # use bollard::image::CommitContainerOptions;
453/// # use std::default::Default;
454/// CommitContainerOptions::<String> {
455///     ..Default::default()
456/// };
457/// ```
458#[derive(Debug, Clone, Default, PartialEq, Serialize)]
459#[deprecated(
460    since = "0.19.0",
461    note = "use the OpenAPI generated bollard::query_parameters::CommitContainerOptions and associated CommitContainerOptionsBuilder"
462)]
463pub struct CommitContainerOptions<T>
464where
465    T: Into<String> + Serialize,
466{
467    /// The ID or name of the container to commit.
468    pub container: T,
469    /// Repository name for the created image.
470    pub repo: T,
471    /// Tag name for the create image.
472    pub tag: T,
473    /// Commit message.
474    pub comment: T,
475    /// Author of the image.
476    pub author: T,
477    /// Whether to pause the container before committing.
478    pub pause: bool,
479    /// `Dockerfile` instructions to apply while committing
480    pub changes: Option<T>,
481}
482
483impl<T> From<CommitContainerOptions<T>> for crate::query_parameters::CommitContainerOptions
484where
485    T: Into<String> + Serialize,
486{
487    fn from(opts: CommitContainerOptions<T>) -> Self {
488        let mut builder = crate::query_parameters::CommitContainerOptionsBuilder::default()
489            .container(&opts.container.into())
490            .repo(&opts.repo.into())
491            .tag(&opts.tag.into())
492            .comment(&opts.comment.into())
493            .author(&opts.author.into())
494            .pause(opts.pause);
495
496        if let Some(changes) = opts.changes {
497            builder = builder.changes(&changes.into())
498        }
499
500        builder.build()
501    }
502}
503
504/// Parameters to the [Build Image API](Docker::build_image())
505///
506/// ## Examples
507///
508/// ```rust
509/// use bollard::image::BuildImageOptions;
510///
511/// BuildImageOptions {
512///     dockerfile: "Dockerfile",
513///     t: "my-image",
514///     ..Default::default()
515/// };
516/// ```
517///
518/// ```
519/// # use bollard::image::BuildImageOptions;
520/// # use std::default::Default;
521/// BuildImageOptions::<String> {
522///     ..Default::default()
523/// };
524/// ```
525#[derive(Debug, Clone, Default, PartialEq, Serialize)]
526#[deprecated(
527    since = "0.19.0",
528    note = "use the OpenAPI generated bollard::query_parameters::BuildImageOptions and associated BuildImageOptionsBuilder"
529)]
530pub struct BuildImageOptions<T>
531where
532    T: Into<String> + Eq + Hash + Serialize,
533{
534    /// Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and
535    /// points to an external `Dockerfile`.
536    pub dockerfile: T,
537    /// A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag
538    /// the default `latest` value is assumed. You can provide several `t` parameters.
539    pub t: T,
540    /// Extra hosts to add to `/etc/hosts`.
541    pub extrahosts: Option<T>,
542    /// A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file,
543    /// the file’s contents are placed into a file called `Dockerfile` and the image is built from
544    /// that file. If the URI points to a tarball, the file is downloaded by the daemon and the
545    /// contents therein used as the context for the build. If the URI points to a tarball and the
546    /// `dockerfile` parameter is also specified, there must be a file with the corresponding path
547    /// inside the tarball.
548    pub remote: T,
549    /// Suppress verbose build output.
550    pub q: bool,
551    /// Do not use the cache when building the image.
552    pub nocache: bool,
553    /// JSON array of images used for build cache resolution.
554    #[serde(serialize_with = "crate::docker::serialize_as_json")]
555    pub cachefrom: Vec<T>,
556    /// Attempt to pull the image even if an older image exists locally.
557    pub pull: bool,
558    /// Remove intermediate containers after a successful build.
559    pub rm: bool,
560    /// Always remove intermediate containers, even upon failure.
561    pub forcerm: bool,
562    /// Set memory limit for build.
563    pub memory: Option<u64>,
564    /// Total memory (memory + swap). Set as `-1` to disable swap.
565    pub memswap: Option<i64>,
566    /// CPU shares (relative weight).
567    pub cpushares: Option<u64>,
568    /// CPUs in which to allow execution (e.g., `0-3`, `0,1`).
569    pub cpusetcpus: T,
570    /// The length of a CPU period in microseconds.
571    pub cpuperiod: Option<u64>,
572    /// Microseconds of CPU time that the container can get in a CPU period.
573    pub cpuquota: Option<u64>,
574    /// JSON map of string pairs for build-time variables. Users pass these values at build-time.
575    /// Docker uses the buildargs as the environment context for commands run via the `Dockerfile`
576    /// RUN instruction, or for variable expansion in other `Dockerfile` instructions.
577    #[serde(serialize_with = "crate::docker::serialize_as_json")]
578    pub buildargs: HashMap<T, T>,
579    #[cfg(feature = "buildkit_providerless")]
580    /// Session ID
581    pub session: Option<String>,
582    /// Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB.
583    pub shmsize: Option<u64>,
584    /// Squash the resulting images layers into a single layer.
585    pub squash: bool,
586    /// Arbitrary key/value labels to set on the image, as a JSON map of string pairs.
587    #[serde(serialize_with = "crate::docker::serialize_as_json")]
588    pub labels: HashMap<T, T>,
589    /// Sets the networking mode for the run commands during build. Supported standard values are:
590    /// `bridge`, `host`, `none`, and `container:<name|id>`. Any other value is taken as a custom network's
591    /// name to which this container should connect to.
592    pub networkmode: T,
593    /// Platform in the format `os[/arch[/variant]]`
594    pub platform: T,
595    /// Target build stage
596    pub target: T,
597    #[cfg(feature = "buildkit_providerless")]
598    /// Specify a custom exporter.
599    pub outputs: Option<ImageBuildOutput<T>>,
600    /// Builder version to use
601    pub version: BuilderVersion,
602}
603
604impl<T> From<BuildImageOptions<T>> for crate::query_parameters::BuildImageOptions
605where
606    T: Into<String> + Eq + Hash + Serialize,
607{
608    fn from(opts: BuildImageOptions<T>) -> Self {
609        let mut builder = crate::query_parameters::BuildImageOptionsBuilder::default()
610            .dockerfile(&opts.dockerfile.into())
611            .t(&opts.t.into())
612            .remote(&opts.remote.into())
613            .q(opts.q)
614            .nocache(opts.nocache)
615            .cachefrom(&opts.cachefrom.into_iter().map(T::into).collect())
616            .pull(&opts.pull.to_string())
617            .rm(opts.rm)
618            .forcerm(opts.forcerm)
619            .cpusetcpus(&opts.cpusetcpus.into())
620            .buildargs(
621                &opts
622                    .buildargs
623                    .into_iter()
624                    .map(|(k, v)| (k.into(), v.into()))
625                    .collect(),
626            )
627            .squash(opts.squash)
628            .labels(
629                &opts
630                    .labels
631                    .into_iter()
632                    .map(|(k, v)| (k.into(), v.into()))
633                    .collect(),
634            )
635            .networkmode(&opts.networkmode.into())
636            .platform(&opts.platform.into())
637            .target(&opts.target.into())
638            .version(opts.version.into());
639
640        if let Some(extrahosts) = opts.extrahosts {
641            builder = builder.extrahosts(&extrahosts.into());
642        }
643
644        if let Some(memory) = opts.memory {
645            builder = builder.memory(
646                i32::try_from(memory)
647                    .inspect_err(|e| {
648                        log::error!("Truncation of u64 into i32 in BuildImageOptions: {e:?}")
649                    })
650                    .unwrap_or(memory as i32),
651            );
652        }
653
654        if let Some(memswap) = opts.memswap {
655            builder = builder.memswap(
656                i32::try_from(memswap)
657                    .inspect_err(|e| {
658                        log::error!("Truncation of u64 into i32 in BuildImageOptions: {e:?}")
659                    })
660                    .unwrap_or(memswap as i32),
661            );
662        }
663
664        if let Some(cpushares) = opts.cpushares {
665            builder = builder.cpushares(
666                i32::try_from(cpushares)
667                    .inspect_err(|e| {
668                        log::error!("Truncation of u64 into i32 in BuildImageOptions: {e:?}")
669                    })
670                    .unwrap_or(cpushares as i32),
671            );
672        }
673
674        if let Some(cpuperiod) = opts.cpuperiod {
675            builder = builder.cpuperiod(
676                i32::try_from(cpuperiod)
677                    .inspect_err(|e| {
678                        log::error!("Truncation of u64 into i32 in BuildImageOptions: {e:?}")
679                    })
680                    .unwrap_or(cpuperiod as i32),
681            );
682        }
683
684        if let Some(cpuquota) = opts.cpuquota {
685            builder = builder.cpuquota(
686                i32::try_from(cpuquota)
687                    .inspect_err(|e| {
688                        log::error!("Truncation of u64 into i32 in BuildImageOptions: {e:?}")
689                    })
690                    .unwrap_or(cpuquota as i32),
691            );
692        }
693
694        if let Some(shmsize) = opts.shmsize {
695            builder = builder.shmsize(
696                i32::try_from(shmsize)
697                    .inspect_err(|e| {
698                        log::error!("Truncation of u64 into i32 in BuildImageOptions: {e:?}")
699                    })
700                    .unwrap_or(shmsize as i32),
701            );
702        }
703
704        #[cfg(feature = "buildkit_providerless")]
705        let builder = if let Some(outputs) = opts.outputs {
706            builder.outputs(outputs.into())
707        } else {
708            builder
709        };
710
711        #[cfg(feature = "buildkit_providerless")]
712        let builder = if let Some(session) = opts.session {
713            builder.session(&session)
714        } else {
715            builder
716        };
717
718        builder.build()
719    }
720}
721
722#[cfg(feature = "buildkit_providerless")]
723/// The exporter to use (see [Docker Docs](https://docs.docker.com/reference/cli/docker/buildx/build/#output))
724#[derive(Debug, Clone, PartialEq)]
725#[deprecated(
726    since = "0.19.0",
727    note = "use the bollard_stubs::query_parameters::ImageBuildOutput"
728)]
729pub enum ImageBuildOutput<T>
730where
731    T: Into<String>,
732{
733    /// The tar export type writes all result files as a single tarball on the client.
734    /// On multi-platform builds all results will be put in subdirectories by their platform.
735    /// It takes the destination directory as a first argument.
736    Tar(T),
737    /// The local export type writes all result files to a directory on the client.
738    /// The new files will be owned by the current user.
739    /// On multi-platform builds, all results will be put in subdirectories by their platform.
740    /// It takes the destination directory as a first argument.
741    ///
742    /// **Notice**: The implementation of the underlying `fsutil` protocol is not complete.
743    /// Therefore, special files, permissions, etc. are ignored or not handled correctly.
744    Local(T),
745}
746
747#[cfg(feature = "buildkit_providerless")]
748impl<T> From<ImageBuildOutput<T>> for crate::query_parameters::ImageBuildOutput
749where
750    T: Into<String>,
751{
752    fn from(output: ImageBuildOutput<T>) -> Self {
753        match output {
754            ImageBuildOutput::Tar(path) => {
755                crate::query_parameters::ImageBuildOutput::Tar(path.into())
756            }
757            ImageBuildOutput::Local(path) => {
758                crate::query_parameters::ImageBuildOutput::Local(path.into())
759            }
760        }
761    }
762}
763
764#[cfg(feature = "buildkit_providerless")]
765impl<T> Serialize for ImageBuildOutput<T>
766where
767    T: Into<String>,
768{
769    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
770    where
771        S: serde::Serializer,
772    {
773        match self {
774            ImageBuildOutput::Tar(_) => serializer.serialize_str(r#"[{"type": "tar"}]"#),
775            ImageBuildOutput::Local(_) => serializer.serialize_str(r#"[{"type": "local"}]"#),
776        }
777    }
778}
779
780/// Parameters to the [Prune Build API](Docker::prune_build())
781///
782/// ## Examples
783///
784/// ```rust
785/// use bollard::image::PruneBuildOptions;
786///
787/// use std::collections::HashMap;
788///
789/// let mut filters = HashMap::new();
790/// filters.insert("until", vec!["10m"]);
791///
792/// PruneBuildOptions{
793///   filters,
794///   ..Default::default()
795/// };
796/// ```
797///
798/// ```rust
799/// # use bollard::image::PruneBuildOptions;
800/// # use std::default::Default;
801/// PruneBuildOptions::<String>{
802///   ..Default::default()
803/// };
804/// ```
805///
806#[derive(Debug, Clone, Default, PartialEq, Serialize)]
807#[deprecated(
808    since = "0.19.0",
809    note = "use the OpenAPI generated bollard::query_parameters::PruneBuildOptions and associated PruneBuildOptionsBuilder"
810)]
811pub struct PruneBuildOptions<T>
812where
813    T: Into<String> + Eq + Hash + Serialize,
814{
815    /// Amount of disk space in bytes to keep for cache
816    pub reserved_space: Option<i64>,
817    /// Maximum amount of disk space allowed to keep for cache
818    pub max_used_space: Option<i64>,
819    /// Target amount of free disk space after pruning
820    pub min_free_space: Option<i64>,
821    /// Remove all types of build cache
822    pub all: bool,
823    /// Filters to process on the prune list, encoded as JSON. Available filters:
824    ///  - `until=<string>` remove cache older than this timestamp. The `<timestamp>` can be
825    ///    Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`)
826    ///    computed relative to the daemon machine’s time.
827    ///  - id=<id>
828    ///  - parent=<id>
829    ///  - type=<string>
830    ///  - description=<string>
831    ///  - inuse
832    ///  - shared
833    ///  - private
834    #[serde(serialize_with = "crate::docker::serialize_as_json")]
835    pub filters: HashMap<T, Vec<T>>,
836}
837
838impl<T> From<PruneBuildOptions<T>> for crate::query_parameters::PruneBuildOptions
839where
840    T: Into<String> + Eq + Hash + Serialize,
841{
842    fn from(opts: PruneBuildOptions<T>) -> Self {
843        crate::query_parameters::PruneBuildOptionsBuilder::default()
844            .all(opts.all)
845            .filters(
846                &opts
847                    .filters
848                    .into_iter()
849                    .map(|(k, v)| (k.into(), v.into_iter().map(T::into).collect()))
850                    .collect(),
851            )
852            .build()
853    }
854}
855
856/// Builder Version to use
857#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize_repr)]
858#[repr(u8)]
859#[deprecated(
860    since = "0.19.0",
861    note = "use the bollard_stubs::query_parameters::BuilderVersion"
862)]
863pub enum BuilderVersion {
864    /// BuilderV1 is the first generation builder in docker daemon
865    #[default]
866    BuilderV1 = 1,
867    /// BuilderBuildKit is builder based on moby/buildkit project
868    BuilderBuildKit = 2,
869}
870
871impl From<BuilderVersion> for crate::query_parameters::BuilderVersion {
872    fn from(opts: BuilderVersion) -> Self {
873        match opts {
874            BuilderVersion::BuilderV1 => crate::query_parameters::BuilderVersion::BuilderV1,
875            BuilderVersion::BuilderBuildKit => {
876                crate::query_parameters::BuilderVersion::BuilderBuildKit
877            }
878        }
879    }
880}
881
882enum ImageBuildBuildkitEither {
883    #[allow(dead_code)]
884    Left(Option<HashMap<String, DockerCredentials>>),
885    Right(Option<HashMap<String, DockerCredentials>>),
886}
887
888/// Parameters to the [Import Image API](Docker::import_image())
889///
890/// ## Examples
891///
892/// ```rust
893/// use bollard::image::ImportImageOptions;
894/// use std::default::Default;
895///
896/// ImportImageOptions {
897///     quiet: true,
898///     ..Default::default()
899/// };
900/// ```
901#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize)]
902#[deprecated(
903    since = "0.19.0",
904    note = "use the OpenAPI generated bollard::query_parameters::ImportImageOptions and associated ImportImageOptionsBuilder"
905)]
906pub struct ImportImageOptions {
907    /// Suppress progress details during load.
908    pub quiet: bool,
909}
910
911impl From<ImportImageOptions> for crate::query_parameters::ImportImageOptions {
912    fn from(opts: ImportImageOptions) -> Self {
913        crate::query_parameters::ImportImageOptionsBuilder::default()
914            .quiet(opts.quiet)
915            .build()
916    }
917}
918
919impl Docker {
920    /// ---
921    ///
922    /// # List Images
923    ///
924    /// Returns a list of images on the server. Note that it uses a different, smaller
925    /// representation of an image than inspecting a single image
926    ///
927    /// # Arguments
928    ///
929    ///  - An optional [List Images Options](ListImagesOptions) struct.
930    ///
931    /// # Returns
932    ///
933    ///  - Vector of [API Images](ImageSummary), wrapped in a Future.
934    ///
935    /// # Examples
936    ///
937    /// ```rust,no_run
938    /// # use bollard::Docker;
939    /// # let docker = Docker::connect_with_http_defaults().unwrap();
940    /// use bollard::image::ListImagesOptions;
941    ///
942    /// use std::collections::HashMap;
943    /// use std::default::Default;
944    ///
945    /// let mut filters = HashMap::new();
946    /// filters.insert("dangling", vec!["true"]);
947    ///
948    /// let options = Some(ListImagesOptions{
949    ///   all: true,
950    ///   filters,
951    ///   ..Default::default()
952    /// });
953    ///
954    /// docker.list_images(options);
955    /// ```
956    pub async fn list_images(
957        &self,
958        options: Option<impl Into<crate::query_parameters::ListImagesOptions>>,
959    ) -> Result<Vec<ImageSummary>, Error> {
960        let url = "/images/json";
961
962        let req = self.build_request(
963            url,
964            Builder::new().method(Method::GET),
965            options.map(Into::into),
966            Ok(BodyType::Left(Full::new(Bytes::new()))),
967        );
968
969        self.process_into_value(req).await
970    }
971
972    /// ---
973    ///
974    /// # Create Image
975    ///
976    /// Create an image by either pulling it from a registry or importing it.
977    ///
978    /// # Arguments
979    ///
980    ///  - An optional [Create Image Options](CreateImageOptions) struct.
981    ///  - An optional request body consisting of a tar or tar.gz archive, or a stream
982    ///    containing the root file system for the image. If this argument is used,
983    ///    the value of the `from_src` option must be "-".
984    ///
985    /// # Returns
986    ///
987    ///  - [Create Image Info](CreateImageInfo), wrapped in an asynchronous
988    ///    Stream.
989    ///
990    /// # Examples
991    ///
992    /// ```rust
993    /// # use bollard::Docker;
994    /// # let docker = Docker::connect_with_http_defaults().unwrap();
995    /// use bollard::image::CreateImageOptions;
996    ///
997    /// use std::default::Default;
998    ///
999    /// let options = Some(CreateImageOptions{
1000    ///   from_image: "hello-world",
1001    ///   ..Default::default()
1002    /// });
1003    ///
1004    /// docker.create_image(options, None, None);
1005    ///
1006    /// // do some other work while the image is pulled from the docker hub...
1007    /// ```
1008    ///
1009    /// # Unsupported
1010    ///
1011    ///  - Import from tarball
1012    ///
1013    pub fn create_image(
1014        &self,
1015        options: Option<impl Into<crate::query_parameters::CreateImageOptions>>,
1016        root_fs: Option<BodyType>,
1017        credentials: Option<DockerCredentials>,
1018    ) -> impl Stream<Item = Result<CreateImageInfo, Error>> {
1019        let url = "/images/create";
1020
1021        let req = self.build_request_with_registry_auth(
1022            url,
1023            Builder::new().method(Method::POST),
1024            options.map(Into::into),
1025            Ok(root_fs.unwrap_or(BodyType::Left(Full::new(Bytes::new())))),
1026            DockerCredentialsHeader::Auth(credentials),
1027        );
1028
1029        self.process_into_stream(req).boxed().map(|res| {
1030            if let Ok(CreateImageInfo {
1031                error: Some(error), ..
1032            }) = res
1033            {
1034                Err(Error::DockerStreamError { error })
1035            } else {
1036                res
1037            }
1038        })
1039    }
1040
1041    /// ---
1042    ///
1043    /// # Inspect Image
1044    ///
1045    /// Return low-level information about an image.
1046    ///
1047    /// # Arguments
1048    ///
1049    /// - Image name as a string slice.
1050    ///
1051    /// # Returns
1052    ///
1053    ///  - [ImageInspect](ImageInspect), wrapped in a Future.
1054    ///
1055    /// # Examples
1056    ///
1057    /// ```rust
1058    /// # use bollard::Docker;
1059    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1060    ///
1061    /// use std::default::Default;
1062    ///
1063    /// docker.inspect_image("hello-world");
1064    /// ```
1065    pub async fn inspect_image(&self, image_name: &str) -> Result<ImageInspect, Error> {
1066        let url = format!("/images/{image_name}/json");
1067
1068        let req = self.build_request(
1069            &url,
1070            Builder::new().method(Method::GET),
1071            None::<String>,
1072            Ok(BodyType::Left(Full::new(Bytes::new()))),
1073        );
1074
1075        self.process_into_value(req).await
1076    }
1077
1078    /// ---
1079    ///
1080    /// # Inspect an Image by contacting the registry
1081    ///
1082    /// Return image digest and platform information by contacting the registry
1083    ///
1084    /// # Arguments
1085    ///
1086    /// - Image name as a string slice.
1087    ///
1088    /// # Returns
1089    ///
1090    /// - [DistributionInspect](DistributionInspect), wrapped in a Future
1091    ///
1092    /// # Examples
1093    /// ```rust
1094    /// use bollard::Docker;
1095    /// let docker = Docker::connect_with_http_defaults().unwrap();
1096    /// docker.inspect_registry_image("ubuntu:jammy", None);
1097    /// ```
1098    pub async fn inspect_registry_image(
1099        &self,
1100        image_name: &str,
1101        credentials: Option<DockerCredentials>,
1102    ) -> Result<DistributionInspect, Error> {
1103        let url = format!("/distribution/{image_name}/json");
1104
1105        let req = self.build_request_with_registry_auth(
1106            &url,
1107            Builder::new().method(Method::GET),
1108            None::<String>,
1109            Ok(BodyType::Left(Full::new(Bytes::new()))),
1110            DockerCredentialsHeader::Auth(credentials),
1111        );
1112
1113        self.process_into_value(req).await
1114    }
1115
1116    /// ---
1117    ///
1118    /// # Prune Images
1119    ///
1120    /// Delete unused images.
1121    ///
1122    /// # Arguments
1123    ///
1124    /// - An optional [Prune Images Options](PruneImagesOptions) struct.
1125    ///
1126    /// # Returns
1127    ///
1128    ///  - a [Prune Image Response](ImagePruneResponse), wrapped in a Future.
1129    ///
1130    /// # Examples
1131    ///
1132    /// ```rust
1133    /// # use bollard::Docker;
1134    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1135    /// use bollard::image::PruneImagesOptions;
1136    ///
1137    /// use std::collections::HashMap;
1138    ///
1139    /// let mut filters = HashMap::new();
1140    /// filters.insert("until", vec!["10m"]);
1141    ///
1142    /// let options = Some(PruneImagesOptions {
1143    ///   filters
1144    /// });
1145    ///
1146    /// docker.prune_images(options);
1147    /// ```
1148    pub async fn prune_images(
1149        &self,
1150        options: Option<impl Into<crate::query_parameters::PruneImagesOptions>>,
1151    ) -> Result<ImagePruneResponse, Error> {
1152        let url = "/images/prune";
1153
1154        let req = self.build_request(
1155            url,
1156            Builder::new().method(Method::POST),
1157            options.map(Into::into),
1158            Ok(BodyType::Left(Full::new(Bytes::new()))),
1159        );
1160
1161        self.process_into_value(req).await
1162    }
1163
1164    /// ---
1165    ///
1166    /// # Image History
1167    ///
1168    /// Return parent layers of an image.
1169    ///
1170    /// # Arguments
1171    ///
1172    ///  - Image name as a string slice.
1173    ///
1174    /// # Returns
1175    ///
1176    ///  - Vector of [History Response Item](HistoryResponseItem), wrapped in a
1177    ///    Future.
1178    ///
1179    /// # Examples
1180    ///
1181    /// ```rust
1182    /// # use bollard::Docker;
1183    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1184    ///
1185    /// docker.image_history("hello-world");
1186    /// ```
1187    pub async fn image_history(&self, image_name: &str) -> Result<Vec<HistoryResponseItem>, Error> {
1188        let url = format!("/images/{image_name}/history");
1189
1190        let req = self.build_request(
1191            &url,
1192            Builder::new().method(Method::GET),
1193            None::<String>,
1194            Ok(BodyType::Left(Full::new(Bytes::new()))),
1195        );
1196
1197        self.process_into_value(req).await
1198    }
1199
1200    /// ---
1201    ///
1202    /// # Search Images
1203    ///
1204    /// Search for an image on Docker Hub.
1205    ///
1206    /// # Arguments
1207    ///
1208    ///  - [Search Image Options](SearchImagesOptions) struct.
1209    ///
1210    /// # Returns
1211    ///
1212    ///  - Vector of [Image Search Response Item](ImageSearchResponseItem) results, wrapped in a
1213    ///    Future.
1214    ///
1215    /// # Examples
1216    ///
1217    /// ```rust
1218    /// # use bollard::Docker;
1219    ///
1220    /// use bollard::image::SearchImagesOptions;
1221    /// use std::default::Default;
1222    /// use std::collections::HashMap;
1223    ///
1224    /// let mut filters = HashMap::new();
1225    /// filters.insert("until", vec!["10m"]);
1226    ///
1227    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1228    /// let search_options = SearchImagesOptions {
1229    ///     term: "hello-world",
1230    ///     filters,
1231    ///     ..Default::default()
1232    /// };
1233    ///
1234    /// docker.search_images(search_options);
1235    /// ```
1236    pub async fn search_images(
1237        &self,
1238        options: impl Into<crate::query_parameters::SearchImagesOptions>,
1239    ) -> Result<Vec<ImageSearchResponseItem>, Error> {
1240        let url = "/images/search";
1241
1242        let req = self.build_request(
1243            url,
1244            Builder::new().method(Method::GET),
1245            Some(options.into()),
1246            Ok(BodyType::Left(Full::new(Bytes::new()))),
1247        );
1248
1249        self.process_into_value(req).await
1250    }
1251
1252    /// ---
1253    ///
1254    /// # Remove Image
1255    ///
1256    /// Remove an image, along with any untagged parent images that were referenced by that image.
1257    ///
1258    /// # Arguments
1259    ///
1260    ///  - Image name as a string slice.
1261    ///  - An optional [Remove Image Options](RemoveImageOptions) struct.
1262    ///
1263    /// # Returns
1264    ///
1265    ///  - Vector of [Image Delete Response Item](ImageDeleteResponseItem), wrapped in a
1266    ///    Future.
1267    ///
1268    /// # Examples
1269    ///
1270    /// ```rust
1271    /// # use bollard::Docker;
1272    ///
1273    /// use bollard::image::RemoveImageOptions;
1274    /// use std::default::Default;
1275    ///
1276    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1277    /// let remove_options = Some(RemoveImageOptions {
1278    ///     force: true,
1279    ///     ..Default::default()
1280    /// });
1281    ///
1282    /// docker.remove_image("hello-world", remove_options, None);
1283    /// ```
1284    pub async fn remove_image(
1285        &self,
1286        image_name: &str,
1287        options: Option<impl Into<crate::query_parameters::RemoveImageOptions>>,
1288        credentials: Option<DockerCredentials>,
1289    ) -> Result<Vec<ImageDeleteResponseItem>, Error> {
1290        let url = format!("/images/{image_name}");
1291
1292        let req = self.build_request_with_registry_auth(
1293            &url,
1294            Builder::new().method(Method::DELETE),
1295            options.map(Into::into),
1296            Ok(BodyType::Left(Full::new(Bytes::new()))),
1297            DockerCredentialsHeader::Auth(credentials),
1298        );
1299        self.process_into_value(req).await
1300    }
1301
1302    /// ---
1303    ///
1304    /// # Tag Image
1305    ///
1306    /// Tag an image so that it becomes part of a repository.
1307    ///
1308    /// # Arguments
1309    ///
1310    ///  - Image name as a string slice.
1311    ///  - Optional [Tag Image Options](TagImageOptions) struct.
1312    ///
1313    /// # Returns
1314    ///
1315    ///  - unit type `()`, wrapped in a Future.
1316    ///
1317    /// # Examples
1318    ///
1319    /// ```rust
1320    /// # use bollard::Docker;
1321    ///
1322    /// use bollard::image::TagImageOptions;
1323    /// use std::default::Default;
1324    ///
1325    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1326    /// let tag_options = Some(TagImageOptions {
1327    ///     tag: "v1.0.1",
1328    ///     ..Default::default()
1329    /// });
1330    ///
1331    /// docker.tag_image("hello-world", tag_options);
1332    /// ```
1333    pub async fn tag_image(
1334        &self,
1335        image_name: &str,
1336        options: Option<impl Into<crate::query_parameters::TagImageOptions>>,
1337    ) -> Result<(), Error> {
1338        let url = format!("/images/{image_name}/tag");
1339
1340        let req = self.build_request(
1341            &url,
1342            Builder::new().method(Method::POST),
1343            options.map(Into::into),
1344            Ok(BodyType::Left(Full::new(Bytes::new()))),
1345        );
1346
1347        self.process_into_unit(req).await
1348    }
1349
1350    /// ---
1351    ///
1352    /// # Push Image
1353    ///
1354    /// Push an image to a registry.
1355    ///
1356    /// # Arguments
1357    ///
1358    ///  - Image name as a string slice.
1359    ///  - Optional [Push Image Options](PushImageOptions) struct.
1360    ///  - Optional [Docker Credentials](DockerCredentials) struct.
1361    ///
1362    /// # Returns
1363    ///
1364    ///  - unit type `()`, wrapped in a Future.
1365    ///
1366    /// # Examples
1367    ///
1368    /// ```rust
1369    /// # use bollard::Docker;
1370    ///
1371    /// use bollard::auth::DockerCredentials;
1372    /// use bollard::image::PushImageOptions;
1373    ///
1374    /// use std::default::Default;
1375    ///
1376    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1377    /// let push_options = Some(PushImageOptions {
1378    ///     tag: "v1.0.1",
1379    /// });
1380    ///
1381    /// let credentials = Some(DockerCredentials {
1382    ///     username: Some("Jack".to_string()),
1383    ///     password: Some("myverysecretpassword".to_string()),
1384    ///     ..Default::default()
1385    /// });
1386    ///
1387    /// docker.push_image("hello-world", push_options, credentials);
1388    /// ```
1389    pub fn push_image(
1390        &self,
1391        image_name: &str,
1392        options: Option<impl Into<crate::query_parameters::PushImageOptions>>,
1393        credentials: Option<DockerCredentials>,
1394    ) -> impl Stream<Item = Result<PushImageInfo, Error>> {
1395        let url = format!("/images/{image_name}/push");
1396
1397        let req = self.build_request_with_registry_auth(
1398            &url,
1399            Builder::new()
1400                .method(Method::POST)
1401                .header(CONTENT_TYPE, "application/json"),
1402            options.map(Into::into),
1403            Ok(BodyType::Left(Full::new(Bytes::new()))),
1404            DockerCredentialsHeader::Auth(Some(credentials.unwrap_or_default())),
1405        );
1406
1407        self.process_into_stream(req).boxed().map(|res| {
1408            if let Ok(PushImageInfo {
1409                error: Some(error), ..
1410            }) = res
1411            {
1412                Err(Error::DockerStreamError { error })
1413            } else {
1414                res
1415            }
1416        })
1417    }
1418
1419    /// ---
1420    ///
1421    /// # Commit Container
1422    ///
1423    /// Create a new image from a container.
1424    ///
1425    /// # Arguments
1426    ///
1427    ///  - [Commit Container Options](CommitContainerOptions) struct.
1428    ///  - Container [Config](Config) struct.
1429    ///
1430    /// # Returns
1431    ///
1432    ///  - [Commit](Commit), wrapped in a Future.
1433    ///
1434    /// # Examples
1435    ///
1436    /// ```rust
1437    /// # use bollard::Docker;
1438    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1439    /// use bollard::image::CommitContainerOptions;
1440    /// use bollard::container::Config;
1441    ///
1442    /// use std::default::Default;
1443    ///
1444    /// let options = CommitContainerOptions{
1445    ///     container: "my-running-container",
1446    ///     pause: true,
1447    ///     ..Default::default()
1448    /// };
1449    ///
1450    /// let config = Config::<String> {
1451    ///     ..Default::default()
1452    /// };
1453    ///
1454    /// docker.commit_container(options, config);
1455    /// ```
1456    pub async fn commit_container(
1457        &self,
1458        options: impl Into<crate::query_parameters::CommitContainerOptions>,
1459        config: impl Into<crate::models::ContainerConfig>,
1460    ) -> Result<IdResponse, Error> {
1461        let url = "/commit";
1462
1463        let req = self.build_request(
1464            url,
1465            Builder::new().method(Method::POST),
1466            Some(options.into()),
1467            Docker::serialize_payload(Some(config.into())),
1468        );
1469
1470        self.process_into_value(req).await
1471    }
1472
1473    /// ---
1474    ///
1475    /// # Build Image
1476    ///
1477    /// Build an image from a tar archive with a `Dockerfile` in it.
1478    ///
1479    /// The `Dockerfile` specifies how the image is built from the tar archive. It is typically in
1480    /// the archive's root, but can be at a different path or have a different name by specifying
1481    /// the `dockerfile` parameter.
1482    ///
1483    /// By default, the call to build specifies using BuilderV1, the first generation builder in docker daemon.
1484    ///
1485    /// # Arguments
1486    ///
1487    ///  - [Build Image Options](BuildImageOptions) struct.
1488    ///  - Optional [Docker Credentials](DockerCredentials) struct.
1489    ///  - Tar archive compressed with one of the following algorithms: identity (no compression),
1490    ///    gzip, bzip2, xz. Optional [Hyper Body](hyper::body::Body).
1491    ///
1492    /// # Returns
1493    ///
1494    ///  - [Create Image Info](CreateImageInfo), wrapped in an asynchronous
1495    ///    Stream.
1496    ///
1497    /// # Examples
1498    ///
1499    /// Sending a tarball:
1500    ///
1501    /// ```rust,no_run
1502    /// # use bollard::Docker;
1503    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1504    /// use bollard::image::BuildImageOptions;
1505    /// use bollard::container::Config;
1506    /// use bollard::body_full;
1507    ///
1508    /// use std::default::Default;
1509    /// use std::fs::File;
1510    /// use std::io::Read;
1511    ///
1512    /// let options = BuildImageOptions{
1513    ///     dockerfile: "Dockerfile",
1514    ///     t: "my-image",
1515    ///     rm: true,
1516    ///     ..Default::default()
1517    /// };
1518    ///
1519    /// let mut file = File::open("tarball.tar.gz").unwrap();
1520    /// let mut contents = Vec::new();
1521    /// file.read_to_end(&mut contents).unwrap();
1522    ///
1523    /// docker.build_image(options, None, Some(body_full(contents.into())));
1524    /// ```
1525    ///
1526    /// Sending a stream:
1527    ///
1528    /// ```rust,no_run
1529    /// # use bollard::Docker;
1530    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1531    /// use bollard::image::BuildImageOptions;
1532    /// use bollard::container::Config;
1533    /// use bollard::body_stream;
1534    ///
1535    /// use std::default::Default;
1536    /// use std::fs::File;
1537    /// use std::io::Read;
1538    ///
1539    /// let options = BuildImageOptions{
1540    ///     dockerfile: "Dockerfile",
1541    ///     t: "my-image",
1542    ///     rm: true,
1543    ///     ..Default::default()
1544    /// };
1545    ///
1546    /// # let mut file = File::open("tarball.tar.gz").unwrap();
1547    /// # let mut contents = Vec::new();
1548    /// # file.read_to_end(&mut contents).unwrap();
1549    /// # let payload = Box::new(contents).leak();
1550    /// # let payload = payload.chunks(32);
1551    /// # let stream = futures_util::stream::iter(payload.map(bytes::Bytes::from));
1552    ///
1553    /// docker.build_image(options, None, Some(body_stream(stream)));
1554    /// ```
1555    pub fn build_image(
1556        &self,
1557        options: impl Into<crate::query_parameters::BuildImageOptions>,
1558        credentials: Option<HashMap<String, DockerCredentials>>,
1559        tar: Option<BodyType>,
1560    ) -> impl Stream<Item = Result<BuildInfo, Error>> + '_ {
1561        let url = "/build";
1562        let options = options.into();
1563
1564        match (
1565            if cfg!(feature = "buildkit_providerless")
1566                && options.version == crate::query_parameters::BuilderVersion::BuilderBuildKit
1567            {
1568                ImageBuildBuildkitEither::Left(credentials)
1569            } else {
1570                ImageBuildBuildkitEither::Right(credentials)
1571            },
1572            &options,
1573        ) {
1574            #[cfg(feature = "buildkit_providerless")]
1575            (
1576                ImageBuildBuildkitEither::Left(creds),
1577                crate::query_parameters::BuildImageOptions {
1578                    session: Some(sess),
1579                    ..
1580                },
1581            ) => {
1582                let session_id = String::clone(sess);
1583                let outputs = options.outputs.clone();
1584
1585                let req = self.build_request(
1586                    url,
1587                    Builder::new()
1588                        .method(Method::POST)
1589                        .header(CONTENT_TYPE, "application/x-tar"),
1590                    Some(options),
1591                    Ok(tar.unwrap()),
1592                );
1593
1594                let session = stream::once(
1595                    self.start_session(session_id, creds, outputs)
1596                        .map(|_| Either::Right(()))
1597                        .fuse(),
1598                );
1599
1600                let stream = self.process_into_stream::<BuildInfo>(req).map(Either::Left);
1601
1602                stream::select(stream, session)
1603                    .filter_map(|either| async move {
1604                        match either {
1605                            Either::Left(data) => Some(data),
1606                            _ => None,
1607                        }
1608                    })
1609                    .boxed()
1610            }
1611            #[cfg(feature = "buildkit_providerless")]
1612            (
1613                ImageBuildBuildkitEither::Left(_),
1614                crate::query_parameters::BuildImageOptions { session: None, .. },
1615            ) => stream::once(futures_util::future::err(
1616                Error::MissingSessionBuildkitError {},
1617            ))
1618            .boxed(),
1619            #[cfg(not(feature = "buildkit_providerless"))]
1620            (ImageBuildBuildkitEither::Left(_), _) => unimplemented!(
1621                "a buildkit enabled build without the 'buildkit_providerless' feature should not be possible"
1622            ),
1623            (ImageBuildBuildkitEither::Right(creds), _) => {
1624                let req = self.build_request_with_registry_auth(
1625                    url,
1626                    Builder::new()
1627                        .method(Method::POST)
1628                        .header(CONTENT_TYPE, "application/x-tar"),
1629                    Some(options),
1630                    Ok(tar.unwrap()),
1631                    DockerCredentialsHeader::Config(creds),
1632                );
1633
1634                self.process_into_stream(req).boxed()
1635            }
1636        }
1637        .map(|res| {
1638            if let Ok(BuildInfo {
1639                error: Some(error), ..
1640            }) = res
1641            {
1642                Err(Error::DockerStreamError { error })
1643            } else {
1644                res
1645            }
1646        })
1647    }
1648
1649    #[cfg(feature = "buildkit_providerless")]
1650    async fn start_session(
1651        &self,
1652        id: String,
1653        credentials: Option<HashMap<String, DockerCredentials>>,
1654        outputs: Option<crate::query_parameters::ImageBuildOutput>,
1655    ) -> Result<(), crate::grpc::error::GrpcError> {
1656        let driver = crate::grpc::driver::moby::Moby::new(self);
1657
1658        let mut auth_provider = crate::grpc::AuthProvider::new();
1659        if let Some(creds) = credentials {
1660            for (host, docker_credentials) in creds {
1661                auth_provider.set_docker_credentials(&host, docker_credentials);
1662            }
1663        }
1664
1665        let auth =
1666            bollard_buildkit_proto::moby::filesync::v1::auth_server::AuthServer::new(auth_provider);
1667
1668        let mut services = match outputs {
1669            Some(crate::query_parameters::ImageBuildOutput::Tar(path)) => {
1670                let filesend_impl =
1671                    crate::grpc::FileSendImpl::new(std::path::PathBuf::from(path).as_path());
1672                let filesend =
1673                    bollard_buildkit_proto::moby::filesync::v1::file_send_server::FileSendServer::new(
1674                        filesend_impl,
1675                    );
1676                vec![crate::grpc::GrpcServer::FileSend(filesend)]
1677            }
1678            Some(crate::query_parameters::ImageBuildOutput::Local(path)) => {
1679                let filesendpacket_impl =
1680                    crate::grpc::FileSendPacketImpl::new(std::path::PathBuf::from(path).as_path());
1681                let filesendpacket = FileSendPacketServer::new(filesendpacket_impl);
1682                vec![crate::grpc::GrpcServer::FileSendPacket(filesendpacket)]
1683            }
1684            None => vec![],
1685        };
1686
1687        services.push(crate::grpc::GrpcServer::Auth(auth));
1688
1689        crate::grpc::driver::Driver::grpc_handle(driver, &id, services).await?;
1690
1691        Ok(())
1692    }
1693
1694    /// ---
1695    ///
1696    /// # Prune Build
1697    ///
1698    /// Delete contents of the build cache
1699    ///
1700    /// # Arguments
1701    ///
1702    /// - An optional [Prune Build Options](PruneBuildOptions) struct.
1703    ///
1704    /// # Returns
1705    ///
1706    ///  - a [Prune Build Response](BuildPruneResponse), wrapped in a Future.
1707    ///
1708    /// # Examples
1709    ///
1710    /// ```rust
1711    /// # use bollard::Docker;
1712    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1713    /// use bollard::image::PruneBuildOptions;
1714    ///
1715    /// use std::collections::HashMap;
1716    ///
1717    /// let mut filters = HashMap::new();
1718    /// filters.insert("until", vec!["10m"]);
1719    ///
1720    /// let options = Some(PruneBuildOptions {
1721    ///   filters,
1722    ///   ..Default::default()
1723    /// });
1724    ///
1725    /// docker.prune_build(options);
1726    /// ```
1727    pub async fn prune_build(
1728        &self,
1729        options: Option<impl Into<crate::query_parameters::PruneBuildOptions>>,
1730    ) -> Result<BuildPruneResponse, Error> {
1731        let url = "/build/prune";
1732
1733        let req = self.build_request(
1734            url,
1735            Builder::new().method(Method::POST),
1736            options.map(Into::into),
1737            Ok(BodyType::Left(Full::new(Bytes::new()))),
1738        );
1739
1740        self.process_into_value(req).await
1741    }
1742
1743    /// ---
1744    ///
1745    /// # Export Image
1746    ///
1747    /// Get a tarball containing all images and metadata for a repository.
1748    ///
1749    /// The root of the resulting tar file will contain the file "manifest.json". If the export is
1750    /// of an image repository, rather than a single image, there will also be a `repositories` file
1751    /// with a JSON description of the exported image repositories.
1752    /// Additionally, each layer of all exported images will have a sub directory in the archive
1753    /// containing the filesystem of the layer.
1754    ///
1755    /// See the [Docker API documentation](https://docs.docker.com/engine/api/v1.40/#operation/ImageGet)
1756    /// for more information.
1757    /// # Arguments
1758    /// - The `image_name` string referring to an individual image and tag (e.g. alpine:latest)
1759    ///
1760    /// # Returns
1761    ///  - An uncompressed TAR archive
1762    pub fn export_image(&self, image_name: &str) -> impl Stream<Item = Result<Bytes, Error>> {
1763        let url = format!("/images/{image_name}/get");
1764        let req = self.build_request(
1765            &url,
1766            Builder::new()
1767                .method(Method::GET)
1768                .header(CONTENT_TYPE, "application/json"),
1769            None::<String>,
1770            Ok(BodyType::Left(Full::new(Bytes::new()))),
1771        );
1772        self.process_into_body(req)
1773    }
1774
1775    /// ---
1776    ///
1777    /// # Export Images
1778    ///
1779    /// Get a tarball containing all images and metadata for several image repositories. Shared
1780    /// layers will be deduplicated.
1781    ///
1782    /// See the [Docker API documentation](https://docs.docker.com/engine/api/v1.40/#tag/Image/operation/ImageGetAll)
1783    /// for more information.
1784    /// # Arguments
1785    /// - The `image_names` Vec of image names.
1786    ///
1787    /// # Returns
1788    ///  - An uncompressed TAR archive
1789    pub fn export_images(&self, image_names: &[&str]) -> impl Stream<Item = Result<Bytes, Error>> {
1790        let options: Vec<_> = image_names.iter().map(|name| ("names", name)).collect();
1791        let req = self.build_request(
1792            "/images/get",
1793            Builder::new()
1794                .method(Method::GET)
1795                .header(CONTENT_TYPE, "application/json"),
1796            Some(options),
1797            Ok(BodyType::Left(Full::new(Bytes::new()))),
1798        );
1799        self.process_into_body(req)
1800    }
1801
1802    /// ---
1803    ///
1804    /// # Import Image
1805    ///
1806    /// Load a set of images and tags into a repository.
1807    ///
1808    /// For details on the format, see the [export image
1809    /// endpoint](struct.Docker.html#method.export_image).
1810    ///
1811    /// # Arguments
1812    ///  - [Image Import Options](ImportImageOptions) struct.
1813    ///
1814    /// # Returns
1815    ///
1816    ///  - [Build Info](BuildInfo), wrapped in an asynchronous
1817    ///    Stream.
1818    ///
1819    /// # Examples
1820    ///
1821    /// ```rust
1822    /// # use bollard::Docker;
1823    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1824    /// use bollard::image::ImportImageOptions;
1825    /// use bollard::errors::Error;
1826    /// use bollard::body_full;
1827    ///
1828    /// use std::default::Default;
1829    /// use futures_util::stream::{StreamExt, TryStreamExt};
1830    /// use tokio::fs::File;
1831    /// use tokio::io::AsyncWriteExt;
1832    /// use tokio_util::codec;
1833    ///
1834    /// let options = ImportImageOptions{
1835    ///     ..Default::default()
1836    /// };
1837    ///
1838    /// async move {
1839    ///     let mut file = File::open("tarball.tar.gz").await.unwrap();
1840    ///
1841    ///     let mut byte_stream = codec::FramedRead::new(file, codec::BytesCodec::new()).map(|r| {
1842    ///         let bytes = r.unwrap().freeze();
1843    ///         Ok::<_, Error>(bytes)
1844    ///     });
1845    ///
1846    ///     let bytes = byte_stream.next().await.unwrap().unwrap();
1847    ///
1848    ///     let mut stream = docker
1849    ///         .import_image(
1850    ///             ImportImageOptions {
1851    ///                 ..Default::default()
1852    ///             },
1853    ///             body_full(bytes),
1854    ///             None,
1855    ///         );
1856    ///
1857    ///     while let Some(response) = stream.next().await {
1858    ///         // ...
1859    ///     }
1860    /// };
1861    /// ```
1862    pub fn import_image(
1863        &self,
1864        options: impl Into<crate::query_parameters::ImportImageOptions>,
1865        root_fs: BodyType,
1866        credentials: Option<HashMap<String, DockerCredentials>>,
1867    ) -> impl Stream<Item = Result<BuildInfo, Error>> {
1868        let req = self.build_request_with_registry_auth(
1869            "/images/load",
1870            Builder::new()
1871                .method(Method::POST)
1872                .header(CONTENT_TYPE, "application/x-tar"),
1873            Some(options.into()),
1874            Ok(root_fs),
1875            DockerCredentialsHeader::Config(credentials),
1876        );
1877
1878        self.process_into_stream(req).boxed().map(|res| {
1879            if let Ok(BuildInfo {
1880                error: Some(error), ..
1881            }) = res
1882            {
1883                Err(Error::DockerStreamError { error })
1884            } else {
1885                res
1886            }
1887        })
1888    }
1889
1890    /// ---
1891    ///
1892    /// # Import Image (stream)
1893    ///
1894    /// Load a set of images and tags into a repository, without holding it all in memory at a given point in time
1895    ///
1896    /// For details on the format, see the [export image
1897    /// endpoint](struct.Docker.html#method.export_image).
1898    ///
1899    /// # Arguments
1900    ///  - [Image Import Options](ImportImageOptions) struct.
1901    ///  - Stream producing `Bytes` of the image
1902    ///
1903    /// # Returns
1904    ///
1905    ///  - [Build Info](BuildInfo), wrapped in an asynchronous
1906    ///    Stream.
1907    ///
1908    /// # Examples
1909    ///
1910    /// ```rust
1911    /// # use bollard::Docker;
1912    /// # let docker = Docker::connect_with_http_defaults().unwrap();
1913    /// use bollard::image::ImportImageOptions;
1914    /// use bollard::errors::Error;
1915    ///
1916    /// use std::default::Default;
1917    /// use futures_util::stream::{StreamExt, TryStreamExt};
1918    /// use tokio::fs::File;
1919    /// use tokio::io::AsyncWriteExt;
1920    /// use tokio_util::codec;
1921    ///
1922    /// let options = ImportImageOptions{
1923    ///     ..Default::default()
1924    /// };
1925    ///
1926    /// async move {
1927    ///     let mut file = File::open("tarball.tar.gz").await.unwrap();
1928    ///
1929    ///     let mut byte_stream = codec::FramedRead::new(file, codec::BytesCodec::new()).map(|r| {
1930    ///         r.unwrap().freeze()
1931    ///     });
1932    ///
1933    ///     let mut stream = docker
1934    ///         .import_image_stream(
1935    ///             ImportImageOptions {
1936    ///                 ..Default::default()
1937    ///             },
1938    ///             byte_stream,
1939    ///             None,
1940    ///         );
1941    ///
1942    ///     while let Some(response) = stream.next().await {
1943    ///         // ...
1944    ///     }
1945    /// };
1946    /// ```
1947    pub fn import_image_stream(
1948        &self,
1949        options: impl Into<crate::query_parameters::ImportImageOptions>,
1950        root_fs: impl Stream<Item = Bytes> + Send + 'static,
1951        credentials: Option<HashMap<String, DockerCredentials>>,
1952    ) -> impl Stream<Item = Result<BuildInfo, Error>> {
1953        let req = self.build_request_with_registry_auth(
1954            "/images/load",
1955            Builder::new()
1956                .method(Method::POST)
1957                .header(CONTENT_TYPE, "application/json"),
1958            Some(options.into()),
1959            Ok(body_stream(root_fs)),
1960            DockerCredentialsHeader::Config(credentials),
1961        );
1962
1963        self.process_into_stream(req).boxed().map(|res| {
1964            if let Ok(BuildInfo {
1965                error: Some(error), ..
1966            }) = res
1967            {
1968                Err(Error::DockerStreamError { error })
1969            } else {
1970                res
1971            }
1972        })
1973    }
1974}
1975
1976#[cfg(not(windows))]
1977#[cfg(test)]
1978mod tests {
1979
1980    use std::io::Write;
1981
1982    use futures_util::TryStreamExt;
1983    use yup_hyper_mock::HostToReplyConnector;
1984
1985    use crate::{
1986        image::{BuildImageOptions, PushImageOptions},
1987        Docker, API_DEFAULT_VERSION,
1988    };
1989
1990    use super::CreateImageOptions;
1991
1992    #[tokio::test]
1993    async fn test_create_image_with_error() {
1994        let mut connector = HostToReplyConnector::default();
1995        connector.m.insert(
1996            String::from("http://127.0.0.1"),
1997            "HTTP/1.1 200 OK\r\nServer:mock1\r\nContent-Type:application/json\r\n\r\n{\"status\":\"Pulling from localstack/localstack\",\"id\":\"0.14.2\"}\n{\"errorDetail\":{\"message\":\"Get \\\"[https://registry-1.docker.io/v2/localstack/localstack/manifests/sha256:d7aefdaae6712891f13795f538fd855fe4e5a8722249e9ca965e94b69b83b819](https://registry-1.docker.io/v2/localstack/localstack/manifests/sha256:d7aefdaae6712891f13795f538fd855fe4e5a8722249e9ca965e94b69b83b819/)\\\": EOF\"},\"error\":\"Get \\\"[https://registry-1.docker.io/v2/localstack/localstack/manifests/sha256:d7aefdaae6712891f13795f538fd855fe4e5a8722249e9ca965e94b69b83b819](https://registry-1.docker.io/v2/localstack/localstack/manifests/sha256:d7aefdaae6712891f13795f538fd855fe4e5a8722249e9ca965e94b69b83b819/)\\\": EOF\"}".to_string());
1998
1999        let docker =
2000            Docker::connect_with_mock(connector, "127.0.0.1".to_string(), 5, API_DEFAULT_VERSION)
2001                .unwrap();
2002
2003        let image = String::from("localstack");
2004
2005        let result = &docker
2006            .create_image(
2007                Some(CreateImageOptions {
2008                    from_image: &image[..],
2009                    ..Default::default()
2010                }),
2011                None,
2012                None,
2013            )
2014            .try_collect::<Vec<_>>()
2015            .await;
2016
2017        assert!(matches!(
2018            result,
2019            Err(crate::errors::Error::DockerStreamError { error: _ })
2020        ));
2021    }
2022
2023    #[tokio::test]
2024    async fn test_push_image_with_error() {
2025        let mut connector = HostToReplyConnector::default();
2026        connector.m.insert(
2027            String::from("http://127.0.0.1"),
2028            "HTTP/1.1 200 OK\r\nServer:mock1\r\nContent-Type:application/json\r\n\r\n{\"status\":\"The push refers to repository [localhost:5000/centos]\"}\n{\"status\":\"Preparing\",\"progressDetail\":{},\"id\":\"74ddd0ec08fa\"}\n{\"errorDetail\":{\"message\":\"EOF\"},\"error\":\"EOF\"}".to_string());
2029
2030        let docker =
2031            Docker::connect_with_mock(connector, "127.0.0.1".to_string(), 5, API_DEFAULT_VERSION)
2032                .unwrap();
2033
2034        let image = String::from("centos");
2035
2036        let result = docker
2037            .push_image(&image[..], None::<PushImageOptions<String>>, None)
2038            .try_collect::<Vec<_>>()
2039            .await;
2040
2041        assert!(matches!(
2042            result,
2043            Err(crate::errors::Error::DockerStreamError { error: _ })
2044        ));
2045    }
2046
2047    #[tokio::test]
2048    async fn test_build_image_with_error() {
2049        let mut connector = HostToReplyConnector::default();
2050        connector.m.insert(
2051            String::from("http://127.0.0.1"),
2052            "HTTP/1.1 200 OK\r\nServer:mock1\r\nContent-Type:application/json\r\n\r\n{\"stream\":\"Step 1/2 : FROM alpine\"}\n{\"stream\":\"\n\"}\n{\"status\":\"Pulling from library/alpine\",\"id\":\"latest\"}\n{\"status\":\"Digest: sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad\"}\n{\"status\":\"Status: Image is up to date for alpine:latest\"}\n{\"stream\":\" --- 9c6f07244728\\n\"}\n{\"stream\":\"Step 2/2 : RUN cmd.exe /C copy nul bollard.txt\"}\n{\"stream\":\"\\n\"}\n{\"stream\":\" --- Running in d615794caf91\\n\"}\n{\"stream\":\"/bin/sh: cmd.exe: not found\\n\"}\n{\"errorDetail\":{\"code\":127,\"message\":\"The command '/bin/sh -c cmd.exe /C copy nul bollard.txt' returned a non-zero code: 127\"},\"error\":\"The command '/bin/sh -c cmd.exe /C copy nul bollard.txt' returned a non-zero code: 127\"}".to_string());
2053        let docker =
2054            Docker::connect_with_mock(connector, "127.0.0.1".to_string(), 5, API_DEFAULT_VERSION)
2055                .unwrap();
2056
2057        let dockerfile = String::from(
2058            r#"FROM alpine
2059            RUN cmd.exe /C copy nul bollard.txt"#,
2060        );
2061
2062        let mut header = tar::Header::new_gnu();
2063        header.set_path("Dockerfile").unwrap();
2064        header.set_size(dockerfile.len() as u64);
2065        header.set_mode(0o755);
2066        header.set_cksum();
2067        let mut tar = tar::Builder::new(Vec::new());
2068        tar.append(&header, dockerfile.as_bytes()).unwrap();
2069
2070        let uncompressed = tar.into_inner().unwrap();
2071        let mut c = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default());
2072        c.write_all(&uncompressed).unwrap();
2073        let compressed = c.finish().unwrap();
2074
2075        let result = &docker
2076            .build_image(
2077                BuildImageOptions {
2078                    dockerfile: "Dockerfile".to_string(),
2079                    t: "integration_test_build_image".to_string(),
2080                    pull: true,
2081                    rm: true,
2082                    ..Default::default()
2083                },
2084                None,
2085                Some(http_body_util::Either::Left(compressed.into())),
2086            )
2087            .try_collect::<Vec<_>>()
2088            .await;
2089
2090        println!("{result:#?}");
2091
2092        assert!(matches!(
2093            result,
2094            Err(crate::errors::Error::DockerStreamError { error: _ })
2095        ));
2096    }
2097}