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}