object lifecycles (fix #309) #620
3 changed files with 39 additions and 8 deletions
|
@ -10,7 +10,7 @@ use crate::s3::xml::{to_xml_with_header, xmlns_tag, IntValue, Value};
|
||||||
use crate::signature::verify_signed_content;
|
use crate::signature::verify_signed_content;
|
||||||
|
|
||||||
use garage_model::bucket_table::{
|
use garage_model::bucket_table::{
|
||||||
Bucket, LifecycleExpiration as GarageLifecycleExpiration,
|
parse_lifecycle_date, Bucket, LifecycleExpiration as GarageLifecycleExpiration,
|
||||||
LifecycleFilter as GarageLifecycleFilter, LifecycleRule as GarageLifecycleRule,
|
LifecycleFilter as GarageLifecycleFilter, LifecycleRule as GarageLifecycleRule,
|
||||||
};
|
};
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
|
@ -21,6 +21,8 @@ pub async fn handle_get_lifecycle(bucket: &Bucket) -> Result<Response<Body>, Err
|
||||||
.params()
|
.params()
|
||||||
.ok_or_internal_error("Bucket should not be deleted at this point")?;
|
.ok_or_internal_error("Bucket should not be deleted at this point")?;
|
||||||
|
|
||||||
|
trace!("bucket: {:#?}", bucket);
|
||||||
|
|
||||||
if let Some(lifecycle) = param.lifecycle_config.get() {
|
if let Some(lifecycle) = param.lifecycle_config.get() {
|
||||||
let wc = LifecycleConfiguration::from_garage_lifecycle_config(lifecycle);
|
let wc = LifecycleConfiguration::from_garage_lifecycle_config(lifecycle);
|
||||||
let xml = to_xml_with_header(&wc)?;
|
let xml = to_xml_with_header(&wc)?;
|
||||||
|
@ -79,7 +81,15 @@ pub async fn handle_put_lifecycle(
|
||||||
.validate_into_garage_lifecycle_config()
|
.validate_into_garage_lifecycle_config()
|
||||||
.ok_or_bad_request("Invalid lifecycle configuration")?;
|
.ok_or_bad_request("Invalid lifecycle configuration")?;
|
||||||
param.lifecycle_config.update(Some(config));
|
param.lifecycle_config.update(Some(config));
|
||||||
|
|
||||||
garage.bucket_table.insert(&bucket).await?;
|
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()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::OK)
|
.status(StatusCode::OK)
|
||||||
|
@ -270,11 +280,11 @@ impl Expiration {
|
||||||
(Some(_), Some(_)) => Err("cannot have both <Days> and <Date> in <Expiration>"),
|
(Some(_), Some(_)) => Err("cannot have both <Days> and <Date> in <Expiration>"),
|
||||||
(None, None) => Err("<Expiration> must contain either <Days> or <Date>"),
|
(None, None) => Err("<Expiration> must contain either <Days> or <Date>"),
|
||||||
(Some(days), None) => Ok(GarageLifecycleExpiration::AfterDays(days.0 as usize)),
|
(Some(days), None) => Ok(GarageLifecycleExpiration::AfterDays(days.0 as usize)),
|
||||||
(None, Some(date)) => date
|
(None, Some(date)) => {
|
||||||
.0
|
trace!("date: {}", date.0);
|
||||||
.parse::<chrono::NaiveDate>()
|
parse_lifecycle_date(&date.0)?;
|
||||||
.map(GarageLifecycleExpiration::AtDate)
|
Ok(GarageLifecycleExpiration::AtDate(date.0))
|
||||||
.map_err(|_| "Invalid expiration <Date>"),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ mod v08 {
|
||||||
/// Objects expire x days after they were created
|
/// Objects expire x days after they were created
|
||||||
AfterDays(usize),
|
AfterDays(usize),
|
||||||
/// Objects expire at date x (must be in yyyy-mm-dd format)
|
/// 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)]
|
#[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 {
|
impl Default for Bucket {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
|
|
|
@ -268,7 +268,14 @@ async fn process_object(
|
||||||
LifecycleExpiration::AfterDays(n_days) => {
|
LifecycleExpiration::AfterDays(n_days) => {
|
||||||
(now_date - version_date) >= chrono::Duration::days(*n_days as i64)
|
(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 {
|
if size_match && date_match {
|
||||||
|
|
Loading…
Reference in a new issue