diff --git a/src/api/data_types/snapshots.rs b/src/api/data_types/snapshots.rs index 40d73354c6..676b5084ff 100644 --- a/src/api/data_types/snapshots.rs +++ b/src/api/data_types/snapshots.rs @@ -12,6 +12,13 @@ pub struct CreateSnapshotResponse { pub image_count: u64, } +/// Response from the preprod retention endpoint. +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PreprodRetentionResponse { + pub snapshots: u64, +} + // Keep in sync with https://github.com/getsentry/sentry/blob/master/src/sentry/preprod/snapshots/manifest.py /// Manifest describing a set of snapshot images for an app. #[derive(Debug, Serialize)] diff --git a/src/api/mod.rs b/src/api/mod.rs index df57300b16..07c1db1c7b 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1006,6 +1006,12 @@ impl AuthenticatedApi<'_> { ); self.get(&path)?.convert() } + + /// Fetches the preprod retention policy for an organization. + pub fn fetch_preprod_retention(&self, org: &str) -> ApiResult { + let path = format!("/organizations/{}/preprod/retention/", PathArg(org),); + self.get(&path)?.convert() + } } /// Available datasets for fetching organization events @@ -2035,5 +2041,4 @@ pub struct SnapshotsUploadOptions { pub struct ObjectstoreUploadOptions { pub url: String, pub scopes: Vec<(String, String)>, - pub expiration_policy: String, } diff --git a/src/commands/build/snapshots.rs b/src/commands/build/snapshots.rs index 2ded836073..84c738ee16 100644 --- a/src/commands/build/snapshots.rs +++ b/src/commands/build/snapshots.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::fs; use std::path::{Path, PathBuf}; -use std::str::FromStr as _; +use std::time::Duration; use anyhow::{Context as _, Result}; use clap::{Arg, ArgMatches, Command}; @@ -88,6 +88,12 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { if images.len() == 1 { "file" } else { "files" } ); + // Fetch retention policy for snapshot uploads + let api = Api::current(); + let authenticated_api = api.authenticated()?; + let retention = authenticated_api.fetch_preprod_retention(&org)?; + debug!("Snapshot retention: {} days", retention.snapshots); + // Upload image files to objectstore println!( "{} Uploading {} image {}", @@ -95,7 +101,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { style(images.len()).yellow(), if images.len() == 1 { "file" } else { "files" } ); - let manifest_entries = upload_images(images, &org, &project)?; + let manifest_entries = upload_images(images, &org, &project, retention.snapshots)?; // Build manifest from discovered images let manifest = SnapshotsManifest { @@ -192,13 +198,14 @@ fn upload_images( images: Vec, org: &str, project: &str, + retention_days: u64, ) -> Result> { let api = Api::current(); let authenticated_api = api.authenticated()?; let options = authenticated_api.fetch_snapshots_upload_options(org, project)?; - let expiration = ExpirationPolicy::from_str(&options.objectstore.expiration_policy) - .context("Failed to parse expiration policy from upload options")?; + let expiration = + ExpirationPolicy::TimeToLive(Duration::from_secs(retention_days * 24 * 60 * 60)); let client = ClientBuilder::new(options.objectstore.url) .token({