Skip to content

Commit b534f18

Browse files
authored
Merge pull request #28 from ameijboom/feat/add-monolithic-push-in-config
feat: add optional use_monolithic_push entry to steiger config
2 parents e37d99c + 01b62b3 commit b534f18

3 files changed

Lines changed: 70 additions & 17 deletions

File tree

src/cmd/build.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::{collections::HashMap, mem, path::Path};
33
use docker_credential::CredentialRetrievalError;
44
use miette::Diagnostic;
55
use oci_client::Reference;
6-
use tokio::{fs, task::JoinSet, time::Instant};
76
use steiger::git;
7+
use tokio::{fs, task::JoinSet, time::Instant};
88

99
use crate::{
1010
build::{
@@ -89,6 +89,7 @@ pub async fn run(
8989
let root = progress::tree();
9090
let handle = progress::setup_line_renderer(&root);
9191
let insecure_registries = mem::take(&mut config.insecure_registries);
92+
let use_monolithic_push = config.use_monolithic_push;
9293

9394
let (tag, default_repo) = (config.tag_format.clone(), config.default_repo.take());
9495
let events = EventsClient::from_env();
@@ -119,7 +120,7 @@ pub async fn run(
119120
progress.init(Some(output.artifacts.len()), None);
120121

121122
let auth = registry::load_credentials(&repo)?;
122-
let registry = Registry::with_config(auth, &insecure_registries);
123+
let registry = Registry::with_config(auth, &insecure_registries, use_monolithic_push);
123124
let mut artifacts = HashMap::new();
124125
let mut set = JoinSet::<Result<_, PushError>>::new();
125126

src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub struct Config {
2424
pub default_repo: Option<String>,
2525
#[serde(default)]
2626
pub tag_format: String,
27+
#[serde(default)]
28+
pub use_monolithic_push: bool,
2729
}
2830

2931
#[derive(Clone, Debug, Serialize, Deserialize)]

src/registry.rs

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,27 @@ pub fn load_credentials(repo: &str) -> Result<RegistryAuth, CredentialRetrievalE
3939
#[derive(Clone)]
4040
pub struct Registry {
4141
client: Client,
42+
use_monolithic_push: bool,
4243
auth: RegistryAuth,
4344
}
4445

4546
impl Registry {
46-
pub fn with_config(auth: RegistryAuth, insecure_registies: &[String]) -> Self {
47+
pub fn with_config(
48+
auth: RegistryAuth,
49+
insecure_registies: &[String],
50+
use_monolithic_push: bool,
51+
) -> Self {
4752
let config = ClientConfig {
4853
protocol: ClientProtocol::HttpsExcept(
4954
[insecure_registies, &["localhost".to_string()]].concat(),
5055
),
56+
use_monolithic_push,
5157
..ClientConfig::default()
5258
};
5359

5460
Self {
5561
client: Client::new(config),
62+
use_monolithic_push,
5663
auth,
5764
}
5865
}
@@ -74,23 +81,40 @@ impl Registry {
7481
}
7582
}
7683

77-
pub async fn push(
84+
async fn monolithic_push(
7885
&mut self,
7986
mut progress: Item,
8087
image_ref: &Reference,
8188
image: Image,
8289
) -> Result<Option<PushResponse>, PushError> {
83-
let registry = image_ref.resolve_registry();
84-
self.client.store_auth_if_needed(registry, &self.auth).await;
90+
progress.init(None, None);
91+
progress.info("pushing image");
8592

86-
if let Some(digest) = self.try_resolve_digest(&self.auth, image_ref).await? {
87-
// If the digest matches the image's digest, we can skip pushing
88-
if digest == image.digest {
89-
progress.info("image already exists, skipping push");
90-
return Ok(None);
91-
}
92-
}
93+
let image_urls = self
94+
.client
95+
.push(
96+
image_ref,
97+
&image.layers,
98+
image.config,
99+
&self.auth,
100+
image.manifest.into(),
101+
)
102+
.await?;
103+
104+
progress.done("image pushed");
93105

106+
Ok(Some(PushResponse {
107+
config_url: image_urls.config_url,
108+
manifest_url: image_urls.manifest_url,
109+
}))
110+
}
111+
112+
async fn layered_push(
113+
&mut self,
114+
mut progress: Item,
115+
image_ref: &Reference,
116+
image: Image,
117+
) -> Result<Option<PushResponse>, PushError> {
94118
progress.init(Some(image.layers.len()), None);
95119
progress.info("pushing image");
96120

@@ -118,10 +142,12 @@ impl Registry {
118142
// Retry on digest mismatch (400) and invalid range (416) errors.
119143
// Root cause unknown; we should probably look into this but retry is safe for now.
120144
// Retrying on 5xx server errors is also acceptable.
121-
Err(e @ OciDistributionError::ServerError {
122-
code: 400 | 416 | 500..599,
123-
..
124-
}) => {
145+
Err(
146+
e @ OciDistributionError::ServerError {
147+
code: 400 | 416 | 500..599,
148+
..
149+
},
150+
) => {
125151
last_err = Some(e);
126152
tokio::time::sleep(Duration::from_secs(i * 2)).await;
127153
}
@@ -160,4 +186,28 @@ impl Registry {
160186
manifest_url,
161187
}))
162188
}
189+
190+
pub async fn push(
191+
&mut self,
192+
mut progress: Item,
193+
image_ref: &Reference,
194+
image: Image,
195+
) -> Result<Option<PushResponse>, PushError> {
196+
let registry = image_ref.resolve_registry();
197+
self.client.store_auth_if_needed(registry, &self.auth).await;
198+
199+
if let Some(digest) = self.try_resolve_digest(&self.auth, image_ref).await? {
200+
// If the digest matches the image's digest, we can skip pushing
201+
if digest == image.digest {
202+
progress.info("image already exists, skipping push");
203+
return Ok(None);
204+
}
205+
}
206+
207+
if self.use_monolithic_push {
208+
return self.monolithic_push(progress, image_ref, image).await;
209+
}
210+
211+
self.layered_push(progress, image_ref, image).await
212+
}
163213
}

0 commit comments

Comments
 (0)