Skip to main content

podman_api/opts/
images.rs

1use containers_api::opts::{Filter, FilterItem};
2use containers_api::{
3    impl_filter_func, impl_map_field, impl_opts_builder, impl_opts_required_builder,
4    impl_url_bool_field, impl_url_enum_field, impl_url_field, impl_url_str_field,
5    impl_url_vec_field,
6};
7use serde::Serialize;
8use base64::engine::Engine;
9use std::collections::HashMap;
10use std::fmt;
11
12impl_opts_required_builder!(url =>
13    /// Adjust how an image is built.
14    ImageBuild,
15    ///
16    /// Parameters:
17    /// * path - Path to a build context directory
18    path => "path"
19);
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22/// The networking mode for the run commands during image build.
23#[derive(Default)]
24pub enum NetworkMode {
25    /// Limited to containers within a single host, port mapping required for external access.
26    #[default]
27    Bridge,
28    /// No isolation between host and containers on this network.
29    Host,
30    /// Disable all networking for this container.
31    None,
32    /// Share networking with given container.
33    Container,
34    /// Custom network's name.
35    Custom(String),
36}
37
38impl AsRef<str> for NetworkMode {
39    fn as_ref(&self) -> &str {
40        match self {
41            NetworkMode::Bridge => "bridge",
42            NetworkMode::Host => "host",
43            NetworkMode::None => "none",
44            NetworkMode::Container => "container",
45            NetworkMode::Custom(custom) => custom,
46        }
47    }
48}
49
50impl fmt::Display for NetworkMode {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "{}", self.as_ref())
53    }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
57/// Used to set the image platform with [`platform`](ImageBuildOptsBuilder::platform).
58pub struct Platform {
59    os: String,
60    arch: Option<String>,
61    version: Option<String>,
62}
63
64impl Platform {
65    pub fn new(os: impl Into<String>) -> Self {
66        Self {
67            os: os.into(),
68            arch: None,
69            version: None,
70        }
71    }
72
73    pub fn arch(mut self, arch: impl Into<String>) -> Self {
74        self.arch = Some(arch.into());
75        self
76    }
77
78    pub fn version(mut self, version: impl Into<String>) -> Self {
79        self.version = Some(version.into());
80        self
81    }
82}
83
84impl fmt::Display for Platform {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        if let Some(arch) = &self.arch {
87            if let Some(vers) = &self.version {
88                write!(f, "{}/{}/{}", self.os, arch, vers)
89            } else {
90                write!(f, "{}/{}", self.os, arch)
91            }
92        } else {
93            write!(f, "{}", self.os)
94        }
95    }
96}
97
98impl ImageBuildOptsBuilder {
99    impl_url_bool_field!(
100        /// Instead of building for a set of platforms specified using the platform option,
101        /// inspect the build's base images, and build for all of the platforms that are available.
102        /// Stages that use scratch as a starting point can not be inspected, so at least one
103        /// non-scratch stage must be present for detection to work usefully.
104        all_platforms => "allplatforms"
105    );
106
107    impl_map_field!(url
108        /// Key-value build time variables.
109        build_args => "buildargs"
110    );
111
112    /// List of images used to build cache resolution
113    pub fn cache_from<S>(mut self, images: impl IntoIterator<Item = S>) -> Self
114    where
115        S: Into<String>,
116    {
117        self.params.insert(
118            "cachefrom",
119            serde_json::to_string(&images.into_iter().map(|i| i.into()).collect::<Vec<_>>())
120                .unwrap_or_default(),
121        );
122        self
123    }
124
125    impl_url_field!(
126        /// Limits the CPU CFS (Completely Fair Scheduler) period.
127        cpu_period: isize => "cpuperiod"
128    );
129
130    impl_url_field!(
131        /// Limits the CPU CFS (Completely Fair Scheduler) quota.
132        cpu_quota: isize => "cpuquota"
133    );
134
135    impl_url_field!(
136        /// Set CPUs in which to allow execution. Example: `0-1`, `1-3`
137        cpu_set_cpus: isize => "cpusetcpus"
138    );
139
140    impl_url_field!(
141        /// CPU shares - relative weights
142        cpu_shares: isize => "cpushares"
143    );
144
145    impl_url_str_field!(
146        /// Path within the build context to the Dockerfile. This is ignored
147        /// if remote is specified and points to an external Dockerfile.
148        dockerfile => "dockerfile"
149    );
150
151    impl_url_str_field!(
152        /// Extra hosts to add to /etc/hosts.
153        extra_hosts => "extrahosts"
154    );
155
156    impl_url_bool_field!(
157        /// Always remove intermediate containers, even upon failure.
158        force_rm => "forcerm"
159    );
160
161    impl_url_bool_field!(
162        /// Inject http proxy environment variables into container.
163        http_proxy => "httpproxy"
164    );
165
166    impl_map_field!(url
167        /// Key-value pairs to set as labels on the new image.
168        labels => "labels"
169    );
170
171    impl_url_bool_field!(
172        /// Cache intermediate layers during build.
173        layers => "layers"
174    );
175
176    impl_url_field!(
177        /// The upper limit (in bytes) on how much memory running
178        /// containers can use.
179        memory: usize => "memory"
180    );
181
182    impl_url_field!(
183        /// Limits the amount of memory and swap together.
184        memswap: usize => "memswap"
185    );
186
187    impl_url_enum_field!(
188        /// Set the networking mode for the run commands during build.
189        network_mode: NetworkMode => "networkmode"
190    );
191
192    impl_url_bool_field!(
193        /// Do not use the cache when building the image.
194        no_cache => "nocache"
195    );
196
197    impl_url_str_field!(
198        /// Output configuration.
199        outputs => "outputs"
200    );
201
202    pub fn platform(mut self, platform: Platform) -> Self {
203        self.params.insert("platform", platform.to_string());
204        self
205    }
206
207    impl_url_bool_field!(
208        /// Attempt to pull the image even if an older image exists locally.
209        pull => "pull"
210    );
211
212    impl_url_bool_field!(
213        /// Suppress verbose build output.
214        quiet => "q"
215    );
216
217    impl_url_str_field!(
218        /// A Git repository URI or HTTP/HTTPS context URI. If the URI points
219        /// to a single text file, the file’s contents are placed into a file
220        /// called Dockerfile and the image is built from that file. If the URI
221        /// points to a tarball, the file is downloaded by the daemon and
222        /// the contents therein used as the context for the build. If the URI
223        /// points to a tarball and the dockerfile parameter is also specified,
224        /// there must be a file with the corresponding path inside the tarball.
225        remote => "remote"
226    );
227
228    impl_url_bool_field!(
229        /// Remove intermediate containers after a successful build.
230        remove => "rm"
231    );
232
233    impl_url_field!(
234        /// Value to use when mounting an shmfs on the container's /dev/shm directory.
235        /// Default is 64MB
236        shared_mem_size: usize => "shmsize"
237    );
238
239    impl_url_bool_field!(
240        /// Silently ignored. Squash the resulting images layers into a single layer.
241        squash => "squash"
242    );
243
244    impl_url_str_field!(
245        /// A name and optional tag to apply to the image in the `name:tag` format.
246        tag => "t"
247    );
248
249    impl_url_str_field!(
250        /// Target build stage
251        target => "target"
252    );
253
254    impl_url_vec_field!(
255        /// Unset environment variables from the final image.
256        unset_env => "unsetenv"
257    );
258}
259
260impl_opts_builder!(url =>
261    /// Adjust how images are listed.
262    ImageList
263);
264
265#[derive(Debug, Clone)]
266/// Used to filter listed images with [`ImagesListFilter`](ImagesListFilter).
267pub enum ImageOpt {
268    Name(crate::Id),
269    Tag(crate::Id, String),
270    Digest(crate::Id, String),
271}
272
273impl fmt::Display for ImageOpt {
274    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275        use ImageOpt::*;
276        match self {
277            Name(id) => write!(f, "{id}"),
278            Tag(id, tag) => write!(f, "{id}:{tag}"),
279            Digest(id, digest) => write!(f, "{id}@{digest}"),
280        }
281    }
282}
283
284#[derive(Debug)]
285/// Used to filter listed images by one of the variants.
286pub enum ImageListFilter {
287    Before(ImageOpt),
288    Dangling(bool),
289    /// Image with key label.
290    LabelKey(String),
291    /// Image with key-value label.
292    LabelKeyVal(String, String),
293    /// Image without key label.
294    NoLabelKey(String),
295    /// Image without key=value label.
296    NoLabelKeyVal(String, String),
297    /// Image name with optional tag.
298    Reference(crate::Id, Option<String>),
299    Id(crate::Id),
300    Since(ImageOpt),
301}
302
303impl Filter for ImageListFilter {
304    fn query_item(&self) -> FilterItem {
305        use ImageListFilter::*;
306        match &self {
307            Before(image) => FilterItem::new("before", image.to_string()),
308            Dangling(dangling) => FilterItem::new("dangling", dangling.to_string()),
309            LabelKey(key) => FilterItem::new("label", key.clone()),
310            LabelKeyVal(key, val) => FilterItem::new("label", format!("{key}={val}")),
311            NoLabelKey(key) => FilterItem::new("label!", key.clone()),
312            NoLabelKeyVal(key, val) => FilterItem::new("label!", format!("{key}={val}")),
313            Reference(image, tag) => FilterItem::new(
314                "reference",
315                if let Some(tag) = tag {
316                    format!("{image}:{tag}")
317                } else {
318                    image.to_string()
319                },
320            ),
321            Id(id) => FilterItem::new("id", id.to_string()),
322            Since(image) => FilterItem::new("since", image.to_string()),
323        }
324    }
325}
326
327impl ImageListOptsBuilder {
328    impl_filter_func!(ImageListFilter);
329
330    impl_url_bool_field!(
331        /// Show all images. Only images from a final layer (no children) are shown by default.
332        all => "all"
333    );
334}
335
336impl_opts_builder!(url =>
337    /// Adjust the way an image is tagged/untagged.
338    ImageTag
339);
340
341impl ImageTagOptsBuilder {
342    impl_url_str_field!(
343        /// Set the image repository.
344        repo => "repo"
345    );
346
347    impl_url_str_field!(
348        /// Set the image tag.
349        tag => "tag"
350    );
351}
352
353#[derive(Clone, Serialize, Debug)]
354#[serde(untagged)]
355pub enum RegistryAuth {
356    Password {
357        username: String,
358        password: String,
359
360        #[serde(skip_serializing_if = "Option::is_none")]
361        email: Option<String>,
362
363        #[serde(rename = "serveraddress")]
364        #[serde(skip_serializing_if = "Option::is_none")]
365        server_address: Option<String>,
366    },
367    Token {
368        #[serde(rename = "identitytoken")]
369        identity_token: String,
370    },
371}
372
373impl RegistryAuth {
374    /// return a new instance with token authentication
375    pub fn token(token: impl Into<String>) -> RegistryAuth {
376        RegistryAuth::Token {
377            identity_token: token.into(),
378        }
379    }
380
381    /// return a new instance of a builder for authentication
382    pub fn builder() -> RegistryAuthBuilder {
383        RegistryAuthBuilder::default()
384    }
385
386    /// serialize authentication as JSON in base64
387    pub fn serialize(&self) -> String {
388        serde_json::to_string(self)
389            .map(|c| base64::engine::general_purpose::URL_SAFE.encode(c))
390            .unwrap_or_default()
391    }
392}
393
394#[derive(Default)]
395pub struct RegistryAuthBuilder {
396    username: Option<String>,
397    password: Option<String>,
398    email: Option<String>,
399    server_address: Option<String>,
400}
401
402impl RegistryAuthBuilder {
403    /// The username used for authentication.
404    pub fn username(&mut self, username: impl Into<String>) -> &mut Self {
405        self.username = Some(username.into());
406        self
407    }
408
409    /// The password used for authentication.
410    pub fn password(&mut self, password: impl Into<String>) -> &mut Self {
411        self.password = Some(password.into());
412        self
413    }
414
415    /// The email addres used for authentication.
416    pub fn email(&mut self, email: impl Into<String>) -> &mut Self {
417        self.email = Some(email.into());
418        self
419    }
420
421    /// The server address of registry, should be a domain/IP without a protocol.
422    /// Example: `10.92.0.1`, `docker.corp.local`
423    pub fn server_address(&mut self, server_address: impl Into<String>) -> &mut Self {
424        self.server_address = Some(server_address.into());
425        self
426    }
427
428    /// Create the final authentication object.
429    pub fn build(&self) -> RegistryAuth {
430        RegistryAuth::Password {
431            username: self.username.clone().unwrap_or_default(),
432            password: self.password.clone().unwrap_or_default(),
433            email: self.email.clone(),
434            server_address: self.server_address.clone(),
435        }
436    }
437}
438
439#[derive(Default, Debug)]
440pub struct PullOpts {
441    auth: Option<RegistryAuth>,
442    params: HashMap<&'static str, String>,
443}
444
445impl PullOpts {
446    /// return a new instance of a builder for Opts
447    pub fn builder() -> PullOptsBuilder {
448        PullOptsBuilder::default()
449    }
450
451    /// serialize Opts as a string. returns None if no Opts are defined
452    pub fn serialize(&self) -> Option<String> {
453        if self.params.is_empty() {
454            None
455        } else {
456            Some(containers_api::url::encoded_pairs(
457                self.params.iter().map(|(k, v)| (k, v)),
458            ))
459        }
460    }
461
462    pub(crate) fn auth_header(&self) -> Option<String> {
463        self.auth.clone().map(|a| a.serialize())
464    }
465}
466
467#[derive(Debug, Clone, PartialEq, Eq)]
468/// The networking mode for the run commands during image build.
469#[derive(Default)]
470pub enum PullPolicy {
471    #[default]
472    Always,
473    Missing,
474    Newer,
475    Never,
476}
477
478impl AsRef<str> for PullPolicy {
479    fn as_ref(&self) -> &str {
480        match self {
481            PullPolicy::Always => "always",
482            PullPolicy::Missing => "missing",
483            PullPolicy::Newer => "newer",
484            PullPolicy::Never => "never",
485        }
486    }
487}
488
489impl fmt::Display for PullPolicy {
490    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
491        write!(f, "{}", self.as_ref())
492    }
493}
494
495#[derive(Debug, Default)]
496pub struct PullOptsBuilder {
497    auth: Option<RegistryAuth>,
498    params: HashMap<&'static str, String>,
499}
500
501impl PullOptsBuilder {
502    impl_url_bool_field!(
503        /// Pull all tagged images in the repository.
504        all_tags => "allTags"
505    );
506
507    impl_url_str_field!(
508        /// Pull image for the specified architecture.
509        arch => "Arch"
510    );
511
512    impl_url_str_field!(
513        /// username:password for the registry.
514        credentials => "credentials"
515    );
516
517    impl_url_str_field!(
518        /// Pull image for the specified operating system.
519        os => "OS"
520    );
521
522    impl_url_enum_field!(
523        /// Image pull policy.
524        policy: PullPolicy => "policy"
525    );
526
527    impl_url_bool_field!(
528        /// Silences extra stream data on pull.
529        quiet => "quiet"
530    );
531
532    impl_url_str_field!(
533        /// Mandatory reference to the image.
534        reference => "reference"
535    );
536
537    impl_url_bool_field!(
538        /// Require TLS verification.
539        tls_verify => "tlsVerify"
540    );
541
542    impl_url_str_field!(
543        /// Pull image for the specified variant.
544        variant => "Variant"
545    );
546
547    pub fn auth(&mut self, auth: RegistryAuth) -> &mut Self {
548        self.auth = Some(auth);
549        self
550    }
551
552    pub fn build(&mut self) -> PullOpts {
553        PullOpts {
554            auth: self.auth.take(),
555            params: self.params.clone(),
556        }
557    }
558}
559
560impl_opts_builder!(url =>
561    /// Adjust how an image is exported.
562    ImageExport
563);
564
565impl ImageExportOptsBuilder {
566    impl_url_bool_field!(
567        /// Use compression on image.
568        compress => "compress"
569    );
570
571    impl_url_str_field!(
572        /// Format for exported image.
573        format => "format"
574    );
575}
576
577impl_opts_builder!(url =>
578    /// Adjust how an image is imported.
579    ImageImport
580);
581
582impl ImageImportOptsBuilder {
583    impl_url_vec_field!(
584        /// Apply the following possible instructions to the created image: CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR.
585        changes => "changes"
586    );
587
588    impl_url_str_field!(
589        /// Set commit message for imported image.
590        message => "message"
591    );
592
593    impl_url_str_field!(
594        /// Optional Name[:TAG] for the image.
595        reference => "reference"
596    );
597
598    impl_url_str_field!(
599        /// Load image from the specified URL.
600        url => "url"
601    );
602}
603
604impl_opts_builder!(url =>
605    /// Adjust how the image tree is retrieved.
606    ImageTree
607);
608
609impl ImageTreeOptsBuilder {
610    impl_url_bool_field!(
611        /// Show all child images and layers of the specified image.
612        what_requires => "whatrequires"
613    );
614}
615
616impl_opts_builder!(url =>
617    /// Adjust how multiple images will be removed.
618    ImagesRemove
619);
620
621impl ImagesRemoveOptsBuilder {
622    impl_url_bool_field!(
623        /// Remove all images.
624        all => "all"
625    );
626
627    impl_url_bool_field!(
628        /// Force image removal (including containers using the images).
629        force => "force"
630    );
631
632    impl_url_bool_field!(
633        /// Ignore if a specified image does not exist and do not throw an error.
634        ignore => "ignore"
635    );
636
637    impl_url_vec_field!(
638        /// Images IDs or names to remove.
639        images => "images"
640    );
641
642    impl_url_bool_field!(
643        /// Resolves to manifest list instead of image.
644        lookup_manifest => "lookupManifest"
645    );
646}
647
648#[derive(Default, Debug)]
649/// Adjust how an image is pushed to a registry.
650pub struct ImagePushOpts {
651    auth: Option<RegistryAuth>,
652    params: HashMap<&'static str, String>,
653}
654
655impl ImagePushOpts {
656    /// Return a new instance of a builder for ImagePushOpts.
657    pub fn builder() -> ImagePushOptsBuilder {
658        ImagePushOptsBuilder::default()
659    }
660
661    /// Serialize ImagePushOpts as a string. Returns None if no Opts are defined.
662    pub fn serialize(&self) -> Option<String> {
663        if self.params.is_empty() {
664            None
665        } else {
666            Some(containers_api::url::encoded_pairs(
667                self.params.iter().map(|(k, v)| (k, v)),
668            ))
669        }
670    }
671
672    pub(crate) fn auth_header(&self) -> Option<String> {
673        self.auth.clone().map(|a| a.serialize())
674    }
675}
676
677#[derive(Debug, Default)]
678pub struct ImagePushOptsBuilder {
679    auth: Option<RegistryAuth>,
680    params: HashMap<&'static str, String>,
681}
682
683impl ImagePushOptsBuilder {
684    impl_url_str_field!(
685        /// Allows for pushing the image to a different destination than the image refers to.
686        destination => "destination"
687    );
688
689    impl_url_bool_field!(
690        /// Silences extra stream data on push.
691        quiet => "quiet"
692    );
693
694    impl_url_bool_field!(
695        /// Require TLS verification.
696        tls_verify => "tlsVerify"
697    );
698
699    pub fn auth(mut self, auth: RegistryAuth) -> Self {
700        self.auth = Some(auth);
701        self
702    }
703
704    pub fn build(self) -> ImagePushOpts {
705        ImagePushOpts {
706            auth: self.auth,
707            params: self.params,
708        }
709    }
710}
711
712#[derive(Debug)]
713/// Used to filter removed images.
714pub enum ImagePruneFilter {
715    /// When set to true, prune only unused and untagged images. When set to false, all unused
716    /// images are pruned.
717    Dangling(bool),
718    /// Prune images created before this timestamp. The <timestamp> can be Unix timestamps, date
719    /// formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the
720    /// daemon machine’s time.
721    // #TODO: DateTime
722    Until(String),
723    /// Image with key label.
724    LabelKey(String),
725    /// Image with key-value label.
726    LabelKeyVal(String, String),
727    /// Image without key label.
728    NoLabelKey(String),
729    /// Image without key-value label.
730    NoLabelKeyVal(String, String),
731}
732
733impl Filter for ImagePruneFilter {
734    fn query_item(&self) -> FilterItem {
735        use ImagePruneFilter::*;
736        match &self {
737            Dangling(dangling) => FilterItem::new("dangling", dangling.to_string()),
738            Until(until) => FilterItem::new("until", until.to_string()),
739            LabelKey(key) => FilterItem::new("label", key.clone()),
740            LabelKeyVal(key, val) => FilterItem::new("label", format!("{key}={val}")),
741            NoLabelKey(key) => FilterItem::new("label!", key.clone()),
742            NoLabelKeyVal(key, val) => FilterItem::new("label!", format!("{key}={val}")),
743        }
744    }
745}
746
747impl_opts_builder!(url =>
748    /// Adjust how unused images are removed.
749    ImagePrune
750);
751
752impl ImagePruneOptsBuilder {
753    impl_filter_func!(
754        /// Filters to apply to image pruning.
755        ImagePruneFilter
756    );
757
758    impl_url_bool_field!(
759        /// Remove all images not in use by containers, not just dangling ones.
760        all => "all"
761    );
762
763    impl_url_bool_field!(
764        /// Remove images even when they are used by external containers (e.g, by build
765        /// containers).
766        external => "external"
767    );
768}
769
770#[derive(Debug)]
771/// Used to filter searched images.
772pub enum ImageSearchFilter {
773    IsAutomated(bool),
774    IsOfficial(bool),
775    /// Matches images that has at least 'number' stars.
776    Stars(usize),
777}
778
779impl Filter for ImageSearchFilter {
780    fn query_item(&self) -> FilterItem {
781        use ImageSearchFilter::*;
782        match &self {
783            IsAutomated(is_automated) => FilterItem::new("is-automated", is_automated.to_string()),
784            IsOfficial(is_official) => FilterItem::new("is-official", is_official.to_string()),
785            Stars(stars) => FilterItem::new("stars", stars.to_string()),
786        }
787    }
788}
789
790impl_opts_builder!(url =>
791    /// Adjust how to search for images in registries.
792    ImageSearch
793);
794
795impl ImageSearchOptsBuilder {
796    impl_filter_func!(
797        /// Filters to process on the images list.
798        ImageSearchFilter
799    );
800
801    impl_url_field!(
802        /// Maximum number of results.
803        limit: usize => "limit"
804    );
805
806    impl_url_bool_field!(
807        /// List the available tags in the repository.
808        list_tags => "listTags"
809    );
810
811    impl_url_str_field!(
812        /// Term to search for.
813        term => "term"
814    );
815
816    impl_url_bool_field!(
817        /// Skip TLS verification for registries.
818        tls_verify => "tlsVerify"
819    );
820}
821
822impl_opts_builder!(url =>
823    /// Adjust how multiple images are exported.
824    ImagesExport
825);
826
827impl ImagesExportOptsBuilder {
828    impl_url_bool_field!(
829        /// Use compression on image.
830        compress => "compress"
831    );
832
833    impl_url_str_field!(
834        /// Format for exported image (only docker-archive is supported).
835        format => "format"
836    );
837
838    impl_url_bool_field!(
839        /// Accept uncompressed layers when copying OCI images.
840        oci_accept_uncompressed_layers => "ociAcceptUncompressedLayers"
841    );
842
843    impl_url_vec_field!(
844        /// References to images to export.
845        references => "references"
846    );
847}