aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2023-08-30 20:02:07 +0200
committerAlex Auvolat <alex@adnab.me>2023-08-30 20:02:07 +0200
commit75ccc5a95c76f31235fcaab8a2c1795693733a4b (patch)
tree2309b19d04875d991bffdad93cdb050c7477123e
parent7200954318a1b248b4194ee9273bcd2502b50d58 (diff)
downloadgarage-75ccc5a95c76f31235fcaab8a2c1795693733a4b.tar.gz
garage-75ccc5a95c76f31235fcaab8a2c1795693733a4b.zip
lifecycle config: store date as given, try to debug
-rw-r--r--src/api/s3/lifecycle.rs22
-rw-r--r--src/model/bucket_table.rs16
-rw-r--r--src/model/s3/lifecycle_worker.rs9
3 files changed, 39 insertions, 8 deletions
diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs
index 2d621eac..f0fde083 100644
--- a/src/api/s3/lifecycle.rs
+++ b/src/api/s3/lifecycle.rs
@@ -10,7 +10,7 @@ use crate::s3::xml::{to_xml_with_header, xmlns_tag, IntValue, Value};
use crate::signature::verify_signed_content;
use garage_model::bucket_table::{
- Bucket, LifecycleExpiration as GarageLifecycleExpiration,
+ parse_lifecycle_date, Bucket, LifecycleExpiration as GarageLifecycleExpiration,
LifecycleFilter as GarageLifecycleFilter, LifecycleRule as GarageLifecycleRule,
};
use garage_model::garage::Garage;
@@ -21,6 +21,8 @@ pub async fn handle_get_lifecycle(bucket: &Bucket) -> Result<Response<Body>, Err
.params()
.ok_or_internal_error("Bucket should not be deleted at this point")?;
+ trace!("bucket: {:#?}", bucket);
+
if let Some(lifecycle) = param.lifecycle_config.get() {
let wc = LifecycleConfiguration::from_garage_lifecycle_config(lifecycle);
let xml = to_xml_with_header(&wc)?;
@@ -79,7 +81,15 @@ pub async fn handle_put_lifecycle(
.validate_into_garage_lifecycle_config()
.ok_or_bad_request("Invalid lifecycle configuration")?;
param.lifecycle_config.update(Some(config));
+
garage.bucket_table.insert(&bucket).await?;
+ trace!("new bucket: {:#?}", bucket);
+
+ let bucket = garage
+ .bucket_helper()
+ .get_existing_bucket(bucket_id)
+ .await?;
+ trace!("new bucket again: {:#?}", bucket);
Ok(Response::builder()
.status(StatusCode::OK)
@@ -270,11 +280,11 @@ impl Expiration {
(Some(_), Some(_)) => Err("cannot have both <Days> and <Date> in <Expiration>"),
(None, None) => Err("<Expiration> must contain either <Days> or <Date>"),
(Some(days), None) => Ok(GarageLifecycleExpiration::AfterDays(days.0 as usize)),
- (None, Some(date)) => date
- .0
- .parse::<chrono::NaiveDate>()
- .map(GarageLifecycleExpiration::AtDate)
- .map_err(|_| "Invalid expiration <Date>"),
+ (None, Some(date)) => {
+ trace!("date: {}", date.0);
+ parse_lifecycle_date(&date.0)?;
+ Ok(GarageLifecycleExpiration::AtDate(date.0))
+ }
}
}
diff --git a/src/model/bucket_table.rs b/src/model/bucket_table.rs
index e9d574c5..df2e9b4a 100644
--- a/src/model/bucket_table.rs
+++ b/src/model/bucket_table.rs
@@ -105,7 +105,7 @@ mod v08 {
/// Objects expire x days after they were created
AfterDays(usize),
/// Objects expire at date x (must be in yyyy-mm-dd format)
- AtDate(chrono::naive::NaiveDate),
+ AtDate(String),
}
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize)]
@@ -155,6 +155,20 @@ impl Crdt for BucketParams {
}
}
+pub fn parse_lifecycle_date(date: &str) -> Result<chrono::NaiveDate, &'static str> {
+ use chrono::prelude::*;
+
+ if let Ok(datetime) = NaiveDateTime::parse_from_str(date, "%Y-%m-%dT%H:%M:%SZ") {
+ if datetime.time() == NaiveTime::MIN {
+ Ok(datetime.date())
+ } else {
+ Err("date must be at midnight")
+ }
+ } else {
+ NaiveDate::parse_from_str(date, "%Y-%m-%d").map_err(|_| "date has invalid format")
+ }
+}
+
impl Default for Bucket {
fn default() -> Self {
Self::new()
diff --git a/src/model/s3/lifecycle_worker.rs b/src/model/s3/lifecycle_worker.rs
index 02e296e7..5641b093 100644
--- a/src/model/s3/lifecycle_worker.rs
+++ b/src/model/s3/lifecycle_worker.rs
@@ -268,7 +268,14 @@ async fn process_object(
LifecycleExpiration::AfterDays(n_days) => {
(now_date - version_date) >= chrono::Duration::days(*n_days as i64)
}
- LifecycleExpiration::AtDate(exp_date) => now_date >= *exp_date,
+ LifecycleExpiration::AtDate(exp_date) => {
+ if let Ok(exp_date) = parse_lifecycle_date(&exp_date) {
+ now_date >= exp_date
+ } else {
+ warn!("Invalid expiraiton date stored in bucket {:?} lifecycle config: {}", bucket.id, exp_date);
+ false
+ }
+ }
};
if size_match && date_match {