intermodal_rs/image/types/mod.rs
1//! Definitions of traits required for handling container Images.
2//!
3//! # Reference:
4//! [Types Implemented in Go](https://github.com/containers/image/blob/master/types/types.go)
5//!
6//! We are not going to define the types matching one to one above, but instead, the idea is to
7//! have Interface definitions that would broadly achieve everything that the interfaces above
8//! achieve.
9
10use std::boxed::Box;
11use std::collections::HashMap;
12
13use async_trait::async_trait;
14use serde::Serialize;
15use tokio::io::AsyncRead;
16
17use crate::image::{
18 docker::reference::types::DockerImageReference, oci::digest::Digest,
19 oci::spec_v1::Image as OCIv1Image,
20};
21
22/// A Result of operations related to handling Images
23pub type ImageResult<T> = Result<T, errors::ImageError>;
24
25/// A trait that is to be implemented by All supported Image Transports
26pub trait ImageTransport: std::fmt::Debug {
27 /// Name of the Transport
28 fn name(&self) -> String;
29
30 /// Parse an input reference, that returns an ImageResult
31 fn parse_reference<'s>(&self, reference: &'s str) -> ImageResult<Box<dyn ImageReference + 's>>;
32
33 #[doc(hidden)]
34 // We need to implement this for Transports because we are keeping a set of Transports in a
35 // Hashmap, and then we'll have to return clone of the value in the HashMap. The additional
36 // `Sync` and `Send` requirements are because the HashMap is protected by a Mutex (being a
37 // global variable).
38
39 fn cloned(&self) -> Box<dyn ImageTransport + Send + Sync>;
40}
41
42// Required for handling the Boxed Trait Objects of ImageTransport type
43impl Clone for Box<dyn ImageTransport + Send + Sync> {
44 fn clone(&self) -> Self {
45 self.cloned()
46 }
47}
48
49/// A trait that should be implemented by All Image References
50pub trait ImageReference: std::fmt::Debug {
51 /// Returns the `ImageTransport` providing this Image Reference.
52 fn transport(&self) -> Box<dyn ImageTransport + Send + Sync>;
53
54 /// Returns the String within the transport that can be used to obtain the equivalent reference
55 /// as the current reference.
56 ///
57 /// Thus `self.transport().parse_reference(self.string_within_reference())` will return a
58 /// reference equivalent to the current reference.
59 fn string_within_transport(&self) -> String;
60
61 /// Returns an Image Source from the Reference provided or an Error.
62 fn new_image_source(&self) -> ImageResult<Box<dyn ImageSource + Send + Sync>>;
63
64 /// Returns the Image
65 fn new_image(&self) -> ImageResult<Box<dyn Image + Send + Sync>>;
66
67 /// Returns the DockerReference corresponding to this ImageReference
68 fn docker_reference(&self) -> Option<Box<dyn DockerImageReference>> {
69 None
70 }
71
72 // FIXME: implement following methods
73 // fn policy_configuration_identity(&self) -> String;
74
75 // fn policy_configuration_namespaces(&self) -> Vec<String>;
76
77 // fn new_image_destination(&self) -> Result
78}
79
80/// A trait that should be implemented by All Image Sources.
81///
82/// An ImageSource is an ImageReference and a client. The 'client' for the image source handles
83/// 'transport' specific details. Thus we'll have an ImageSource for every soupported transport.
84/// Right now we are supporting only 'docker' (Repo V2) and 'oci' (local FS - TODO).
85///
86#[async_trait]
87pub trait ImageSource: std::fmt::Debug {
88 /// Returns a Reference corresponding to this particular ImageSource.
89 fn reference(&self) -> Box<dyn ImageReference>;
90
91 /// Get the manifest using this `ImageSource`.
92 ///
93 /// If the passed `Digest` is None, it means - Get the manifest for the reference, this source
94 /// points to. Usually it means getting the manifest for the 'digest' if present in the
95 /// reference or the 'tag' (default if not present) for the reference. When we explicitly pass
96 /// the Digest, we are interested in manifest corresponding to this specific digest (Which
97 /// usually is the manifest for the 'Image' if the previous manifest was a 'list' or 'index'
98 /// type.)
99 async fn get_manifest(&mut self, digest: Option<&Digest>) -> ImageResult<ImageManifest>;
100
101 /// Get a blob for the image
102 ///
103 /// It is up to the caller to decide whether the requested blob is a 'config' or a 'layer'
104 /// blob.
105 async fn get_blob(
106 &self,
107 digest: &Digest,
108 ) -> ImageResult<Box<dyn AsyncRead + Unpin + Send + Sync>>;
109
110 /// Get all tags for this Image source
111 ///
112 /// Get's all tags corresponding to this Image Source. Note: Right now this makes sense only
113 /// for the 'docker' Image sources, for other image sources, simply return an Empty List.
114 async fn get_repo_tags(&self) -> ImageResult<Vec<String>>;
115}
116
117/// A trait that should be implemented by all Images.
118///
119/// This trait is an API for inspecting images. An image is basically represented by ImageSource
120/// and instance Digest. This can be a manifest list or a single instance.
121#[async_trait]
122pub trait Image: std::fmt::Debug {
123 /// Underlying 'image source'
124 fn source_ref(&self) -> &(dyn ImageSource + Send + Sync);
125
126 /// Reference of the 'image source'.
127 fn reference(&self) -> Box<dyn ImageReference>;
128
129 /// Returns the manifest for the image.
130 ///
131 /// This manifest returns the 'manifest' for the source corresponding to `reference()`.
132 /// The manifest may be of 'list' or 'index' type (if the reference is a tag) or appropriate
133 /// media type (if the reference is a digest).
134 ///
135 /// Usually, if the reference is a user requested, it's likely that the manifest corresponds to
136 /// a user requested tag or default tag 'latest'.
137 ///
138 async fn manifest(&mut self) -> ImageResult<ImageManifest>;
139
140 /// Returns the 'Resolved' manifest for the image.
141 ///
142 /// Manifest for the `reference()` is resolved to current OS and Architecture and is returned.
143 /// This manifest will be used to get other image details like config and layer blobs.
144 ///
145 async fn resolved_manifest(&mut self) -> ImageResult<ImageManifest>;
146
147 /// Returns the raw config blob for the Image
148 async fn config_blob(&mut self) -> ImageResult<Vec<u8>>;
149
150 /// Returns the Image in OCI Format.
151 async fn oci_config(&mut self) -> ImageResult<OCIv1Image>;
152
153 /// Returns inspect output friendly structure.
154 async fn inspect(&mut self) -> ImageResult<ImageInspect>;
155}
156
157/// A struct representing Image Manfest
158#[derive(Debug, Clone)]
159pub struct ImageManifest {
160 pub manifest: Vec<u8>,
161 pub mime_type: String,
162}
163
164/// A struct representing Inspect output (Something like 'docker inspect', 'skopeo inspect')
165#[derive(Debug, Serialize)]
166pub struct ImageInspect {
167 #[serde(rename = "Created")]
168 pub created: String,
169
170 #[serde(rename = "DockerVersion")]
171 pub docker_version: String,
172
173 #[serde(rename = "Labels")]
174 pub labels: HashMap<String, String>,
175
176 #[serde(rename = "Architecture")]
177 pub architecture: String,
178
179 #[serde(rename = "Os")]
180 pub os: String,
181
182 #[serde(rename = "Layers")]
183 pub layers: Vec<String>,
184
185 #[serde(rename = "Env")]
186 pub env: Vec<String>,
187}
188
189pub mod errors;