From 8041d9a8274619b9a7cb66735ed560bcfba16078 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Tue, 29 Aug 2023 17:44:17 +0200 Subject: s3: add xml structures to serialize/deserialize lifecycle configs --- src/api/s3/api_server.rs | 6 ++ src/api/s3/lifecycle.rs | 256 +++++++++++++++++++++++++++++++++++++++++++++++ src/api/s3/mod.rs | 1 + 3 files changed, 263 insertions(+) create mode 100644 src/api/s3/lifecycle.rs (limited to 'src/api') diff --git a/src/api/s3/api_server.rs b/src/api/s3/api_server.rs index 5e793082..06fef6d5 100644 --- a/src/api/s3/api_server.rs +++ b/src/api/s3/api_server.rs @@ -26,6 +26,7 @@ use crate::s3::copy::*; use crate::s3::cors::*; use crate::s3::delete::*; use crate::s3::get::*; +use crate::s3::lifecycle::*; use crate::s3::list::*; use crate::s3::multipart::*; use crate::s3::post_object::handle_post_object; @@ -362,6 +363,11 @@ impl ApiHandler for S3ApiServer { handle_put_cors(garage, bucket_id, req, content_sha256).await } Endpoint::DeleteBucketCors {} => handle_delete_cors(garage, bucket_id).await, + Endpoint::GetBucketLifecycleConfiguration {} => handle_get_lifecycle(&bucket).await, + Endpoint::PutBucketLifecycleConfiguration {} => { + handle_put_lifecycle(garage, bucket_id, req, content_sha256).await + } + Endpoint::DeleteBucketLifecycle {} => handle_delete_lifecycle(garage, bucket_id).await, endpoint => Err(Error::NotImplemented(endpoint.name().to_owned())), }; diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs new file mode 100644 index 00000000..cb0cc83a --- /dev/null +++ b/src/api/s3/lifecycle.rs @@ -0,0 +1,256 @@ +use quick_xml::de::from_reader; +use std::sync::Arc; + +use hyper::{Body, Request, Response, StatusCode}; + +use serde::{Deserialize, Serialize}; + +use crate::s3::error::*; +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, + LifecycleFilter as GarageLifecycleFilter, LifecycleRule as GarageLifecycleRule, +}; +use garage_model::garage::Garage; +use garage_util::data::*; + +pub async fn handle_get_lifecycle(bucket: &Bucket) -> Result, Error> { + let param = bucket + .params() + .ok_or_internal_error("Bucket should not be deleted at this point")?; + + if let Some(lifecycle) = param.lifecycle_config.get() { + let wc = LifecycleConfiguration { + xmlns: (), + lifecycle_rules: lifecycle + .iter() + .map(LifecycleRule::from_garage_lifecycle_rule) + .collect::>(), + }; + let xml = to_xml_with_header(&wc)?; + Ok(Response::builder() + .status(StatusCode::OK) + .header(http::header::CONTENT_TYPE, "application/xml") + .body(Body::from(xml))?) + } else { + Ok(Response::builder() + .status(StatusCode::NO_CONTENT) + .body(Body::empty())?) + } +} + +pub async fn handle_delete_lifecycle( + garage: Arc, + bucket_id: Uuid, +) -> Result, Error> { + let mut bucket = garage + .bucket_helper() + .get_existing_bucket(bucket_id) + .await?; + + let param = bucket.params_mut().unwrap(); + + param.lifecycle_config.update(None); + garage.bucket_table.insert(&bucket).await?; + + Ok(Response::builder() + .status(StatusCode::NO_CONTENT) + .body(Body::empty())?) +} + +pub async fn handle_put_lifecycle( + garage: Arc, + bucket_id: Uuid, + req: Request, + content_sha256: Option, +) -> Result, Error> { + let body = hyper::body::to_bytes(req.into_body()).await?; + + if let Some(content_sha256) = content_sha256 { + verify_signed_content(content_sha256, &body[..])?; + } + + let mut bucket = garage + .bucket_helper() + .get_existing_bucket(bucket_id) + .await?; + + let param = bucket.params_mut().unwrap(); + + let conf: LifecycleConfiguration = from_reader(&body as &[u8])?; + + param + .lifecycle_config + .update(Some(conf.validate_into_garage_lifecycle_config()?)); + garage.bucket_table.insert(&bucket).await?; + + Ok(Response::builder() + .status(StatusCode::OK) + .body(Body::empty())?) +} + +// ---- SERIALIZATION AND DESERIALIZATION TO/FROM S3 XML ---- + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename = "LifecycleConfiguration")] +pub struct LifecycleConfiguration { + #[serde(serialize_with = "xmlns_tag", skip_deserializing)] + pub xmlns: (), + #[serde(rename = "Rule")] + pub lifecycle_rules: Vec, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub struct LifecycleRule { + #[serde(rename = "ID")] + pub id: Option, + #[serde(rename = "Status")] + pub status: Value, + #[serde(rename = "Filter", default)] + pub filter: Filter, + #[serde(rename = "Expiration", default)] + pub expiration: Option, + #[serde(rename = "AbortIncompleteMultipartUpload", default)] + pub abort_incomplete_mpu: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct Filter { + #[serde(rename = "And")] + pub and: Option>, + #[serde(rename = "Prefix")] + pub prefix: Option, + #[serde(rename = "ObjectSizeGreaterThan")] + pub size_gt: Option, + #[serde(rename = "ObjectSizeLessThan")] + pub size_lt: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub struct Expiration { + #[serde(rename = "Days")] + pub days: Option, + #[serde(rename = "Date")] + pub at_date: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub struct AbortIncompleteMpu { + #[serde(rename = "DaysAfterInitiation")] + pub days: Option, +} + +impl LifecycleConfiguration { + pub fn validate_into_garage_lifecycle_config(self) -> Result, Error> { + let mut ret = vec![]; + for rule in self.lifecycle_rules { + ret.push(rule.validate_into_garage_lifecycle_rule()?); + } + Ok(ret) + } + + pub fn from_garage_lifecycle_config(config: &[GarageLifecycleRule]) -> Self { + Self { + xmlns: (), + lifecycle_rules: config + .iter() + .map(LifecycleRule::from_garage_lifecycle_rule) + .collect(), + } + } +} + +impl LifecycleRule { + pub fn validate_into_garage_lifecycle_rule(self) -> Result { + todo!() + } + + pub fn from_garage_lifecycle_rule(rule: &GarageLifecycleRule) -> Self { + todo!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use quick_xml::de::from_str; + + #[test] + fn test_deserialize_lifecycle_config() -> Result<(), Error> { + let message = r#" + + + id1 + Enabled + + documents/ + + + 7 + + + + id2 + Enabled + + + logs/ + 1000000 + + + + 365 + + +"#; + let conf: LifecycleConfiguration = from_str(message).unwrap(); + let ref_value = LifecycleConfiguration { + xmlns: (), + lifecycle_rules: vec![ + LifecycleRule { + id: Some("id1".into()), + status: "Enabled".into(), + filter: Filter { + prefix: Some("documents/".into()), + ..Default::default() + }, + expiration: None, + abort_incomplete_mpu: Some(AbortIncompleteMpu { + days: Some(IntValue(7)), + }), + }, + LifecycleRule { + id: Some("id2".into()), + status: "Enabled".into(), + filter: Filter { + and: Some(Box::new(Filter { + prefix: Some("logs/".into()), + size_gt: Some(IntValue(1000000)), + ..Default::default() + })), + ..Default::default() + }, + expiration: Some(Expiration { + days: Some(IntValue(365)), + at_date: None, + }), + abort_incomplete_mpu: None, + }, + ], + }; + assert_eq! { + ref_value, + conf + }; + + let message2 = to_xml_with_header(&ref_value)?; + + let cleanup = |c: &str| c.replace(char::is_whitespace, ""); + assert_eq!(cleanup(message), cleanup(&message2)); + + Ok(()) + } +} diff --git a/src/api/s3/mod.rs b/src/api/s3/mod.rs index b5237bf7..cbdb94ab 100644 --- a/src/api/s3/mod.rs +++ b/src/api/s3/mod.rs @@ -6,6 +6,7 @@ mod copy; pub mod cors; mod delete; pub mod get; +mod lifecycle; mod list; mod multipart; mod post_object; -- cgit v1.2.3 From abf011c2906d04200bb39d7bc82f7ed973215500 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Tue, 29 Aug 2023 18:22:03 +0200 Subject: lifecycle: implement validation into garage's internal data structure --- src/api/s3/lifecycle.rs | 200 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 177 insertions(+), 23 deletions(-) (limited to 'src/api') diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs index cb0cc83a..48265870 100644 --- a/src/api/s3/lifecycle.rs +++ b/src/api/s3/lifecycle.rs @@ -22,13 +22,7 @@ pub async fn handle_get_lifecycle(bucket: &Bucket) -> Result, Err .ok_or_internal_error("Bucket should not be deleted at this point")?; if let Some(lifecycle) = param.lifecycle_config.get() { - let wc = LifecycleConfiguration { - xmlns: (), - lifecycle_rules: lifecycle - .iter() - .map(LifecycleRule::from_garage_lifecycle_rule) - .collect::>(), - }; + let wc = LifecycleConfiguration::from_garage_lifecycle_config(lifecycle); let xml = to_xml_with_header(&wc)?; Ok(Response::builder() .status(StatusCode::OK) @@ -81,9 +75,10 @@ pub async fn handle_put_lifecycle( let conf: LifecycleConfiguration = from_reader(&body as &[u8])?; - param - .lifecycle_config - .update(Some(conf.validate_into_garage_lifecycle_config()?)); + let config = conf + .validate_into_garage_lifecycle_config() + .ok_or_bad_request("Invalid lifecycle configuration")?; + param.lifecycle_config.update(Some(config)); garage.bucket_table.insert(&bucket).await?; Ok(Response::builder() @@ -109,7 +104,7 @@ pub struct LifecycleRule { #[serde(rename = "Status")] pub status: Value, #[serde(rename = "Filter", default)] - pub filter: Filter, + pub filter: Option, #[serde(rename = "Expiration", default)] pub expiration: Option, #[serde(rename = "AbortIncompleteMultipartUpload", default)] @@ -139,11 +134,13 @@ pub struct Expiration { #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct AbortIncompleteMpu { #[serde(rename = "DaysAfterInitiation")] - pub days: Option, + pub days: IntValue, } impl LifecycleConfiguration { - pub fn validate_into_garage_lifecycle_config(self) -> Result, Error> { + pub fn validate_into_garage_lifecycle_config( + self, + ) -> Result, &'static str> { let mut ret = vec![]; for rule in self.lifecycle_rules { ret.push(rule.validate_into_garage_lifecycle_rule()?); @@ -163,12 +160,136 @@ impl LifecycleConfiguration { } impl LifecycleRule { - pub fn validate_into_garage_lifecycle_rule(self) -> Result { - todo!() + pub fn validate_into_garage_lifecycle_rule(self) -> Result { + let enabled = match self.status.0.as_str() { + "Enabled" => true, + "Disabled" => false, + _ => return Err("invalid value for "), + }; + + let filter = self + .filter + .map(Filter::validate_into_garage_lifecycle_filter) + .transpose()? + .unwrap_or_default(); + + let abort_incomplete_mpu_days = self.abort_incomplete_mpu.map(|x| x.days.0 as usize); + + let expiration = self + .expiration + .map(Expiration::validate_into_garage_lifecycle_expiration) + .transpose()?; + + Ok(GarageLifecycleRule { + id: self.id.map(|x| x.0), + enabled, + filter, + abort_incomplete_mpu_days, + expiration, + }) } pub fn from_garage_lifecycle_rule(rule: &GarageLifecycleRule) -> Self { - todo!() + Self { + id: rule.id.as_deref().map(Value::from), + status: if rule.enabled { + Value::from("Enabled") + } else { + Value::from("Disabled") + }, + filter: Filter::from_garage_lifecycle_filter(&rule.filter), + abort_incomplete_mpu: rule + .abort_incomplete_mpu_days + .map(|days| AbortIncompleteMpu { + days: IntValue(days as i64), + }), + expiration: rule + .expiration + .as_ref() + .map(Expiration::from_garage_lifecycle_expiration), + } + } +} + +impl Filter { + pub fn count(&self) -> i32 { + fn count(x: &Option) -> i32 { + x.as_ref().map(|_| 1).unwrap_or(0) + } + count(&self.prefix) + count(&self.size_gt) + count(&self.size_lt) + } + + pub fn validate_into_garage_lifecycle_filter( + self, + ) -> Result { + if self.count() > 0 && self.and.is_some() { + Err("Filter tag cannot contain both and another condition") + } else if let Some(and) = self.and { + if and.and.is_some() { + return Err("Nested tags"); + } + Ok(and.internal_into_garage_lifecycle_filter()) + } else if self.count() > 1 { + Err("Multiple Filter conditions must be wrapped in an tag") + } else { + Ok(self.internal_into_garage_lifecycle_filter()) + } + } + + fn internal_into_garage_lifecycle_filter(self) -> GarageLifecycleFilter { + GarageLifecycleFilter { + prefix: self.prefix.map(|x| x.0), + size_gt: self.size_gt.map(|x| x.0 as usize), + size_lt: self.size_lt.map(|x| x.0 as usize), + } + } + + pub fn from_garage_lifecycle_filter(rule: &GarageLifecycleFilter) -> Option { + let filter = Filter { + and: None, + prefix: rule.prefix.as_deref().map(Value::from), + size_gt: rule.size_gt.map(|x| IntValue(x as i64)), + size_lt: rule.size_lt.map(|x| IntValue(x as i64)), + }; + match filter.count() { + 0 => None, + 1 => Some(filter), + _ => Some(Filter { + and: Some(Box::new(filter)), + ..Default::default() + }), + } + } +} + +impl Expiration { + pub fn validate_into_garage_lifecycle_expiration( + self, + ) -> Result { + match (self.days, self.at_date) { + (Some(_), Some(_)) => Err("cannot have both and in "), + (None, None) => Err(" must contain either or "), + (Some(days), None) => Ok(GarageLifecycleExpiration::AfterDays(days.0 as usize)), + (None, Some(date)) => { + if date.0.parse::().is_err() { + return Err("Invalid expiration "); + } + Ok(GarageLifecycleExpiration::AtDate(date.0)) + } + } + } + + pub fn from_garage_lifecycle_expiration(exp: &GarageLifecycleExpiration) -> Self { + match exp { + GarageLifecycleExpiration::AfterDays(days) => Expiration { + days: Some(IntValue(*days as i64)), + at_date: None, + }, + GarageLifecycleExpiration::AtDate(days) => Expiration { + days: None, + at_date: Some(Value::from(days.as_str())), + }, + } } } @@ -213,26 +334,24 @@ mod tests { LifecycleRule { id: Some("id1".into()), status: "Enabled".into(), - filter: Filter { + filter: Some(Filter { prefix: Some("documents/".into()), ..Default::default() - }, - expiration: None, - abort_incomplete_mpu: Some(AbortIncompleteMpu { - days: Some(IntValue(7)), }), + expiration: None, + abort_incomplete_mpu: Some(AbortIncompleteMpu { days: IntValue(7) }), }, LifecycleRule { id: Some("id2".into()), status: "Enabled".into(), - filter: Filter { + filter: Some(Filter { and: Some(Box::new(Filter { prefix: Some("logs/".into()), size_gt: Some(IntValue(1000000)), ..Default::default() })), ..Default::default() - }, + }), expiration: Some(Expiration { days: Some(IntValue(365)), at_date: None, @@ -251,6 +370,41 @@ mod tests { let cleanup = |c: &str| c.replace(char::is_whitespace, ""); assert_eq!(cleanup(message), cleanup(&message2)); + // Check validation + let validated = ref_value + .validate_into_garage_lifecycle_config() + .ok_or_bad_request("invalid xml config")?; + + let ref_config = vec![ + GarageLifecycleRule { + id: Some("id1".into()), + enabled: true, + filter: GarageLifecycleFilter { + prefix: Some("documents/".into()), + ..Default::default() + }, + expiration: None, + abort_incomplete_mpu_days: Some(7), + }, + GarageLifecycleRule { + id: Some("id2".into()), + enabled: true, + filter: GarageLifecycleFilter { + prefix: Some("logs/".into()), + size_gt: Some(1000000), + ..Default::default() + }, + expiration: Some(GarageLifecycleExpiration::AfterDays(365)), + abort_incomplete_mpu_days: None, + }, + ]; + assert_eq!(validated, ref_config); + + let message3 = to_xml_with_header(&LifecycleConfiguration::from_garage_lifecycle_config( + &validated, + ))?; + assert_eq!(cleanup(message), cleanup(&message3)); + Ok(()) } } -- cgit v1.2.3 From f7b409f1140addd508c626b1e80f0f8de52a5639 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Wed, 30 Aug 2023 11:24:01 +0200 Subject: use a NaiveDate in data model, it serializes to string (iso 8601 format) --- src/api/s3/lifecycle.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/api') diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs index 48265870..278cf26d 100644 --- a/src/api/s3/lifecycle.rs +++ b/src/api/s3/lifecycle.rs @@ -270,12 +270,11 @@ impl Expiration { (Some(_), Some(_)) => Err("cannot have both and in "), (None, None) => Err(" must contain either or "), (Some(days), None) => Ok(GarageLifecycleExpiration::AfterDays(days.0 as usize)), - (None, Some(date)) => { - if date.0.parse::().is_err() { - return Err("Invalid expiration "); - } - Ok(GarageLifecycleExpiration::AtDate(date.0)) - } + (None, Some(date)) => date + .0 + .parse::() + .map(GarageLifecycleExpiration::AtDate) + .map_err(|_| "Invalid expiration "), } } @@ -285,9 +284,9 @@ impl Expiration { days: Some(IntValue(*days as i64)), at_date: None, }, - GarageLifecycleExpiration::AtDate(days) => Expiration { + GarageLifecycleExpiration::AtDate(date) => Expiration { days: None, - at_date: Some(Value::from(days.as_str())), + at_date: Some(Value(date.to_string())), }, } } -- cgit v1.2.3 From 2996dc875fc378ec3597bfa3bdb8ba8951e1865c Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Wed, 30 Aug 2023 14:28:48 +0200 Subject: lifecycle worker: implement main functionality --- src/api/s3/lifecycle.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/api') diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs index 278cf26d..2d621eac 100644 --- a/src/api/s3/lifecycle.rs +++ b/src/api/s3/lifecycle.rs @@ -239,8 +239,8 @@ impl Filter { fn internal_into_garage_lifecycle_filter(self) -> GarageLifecycleFilter { GarageLifecycleFilter { prefix: self.prefix.map(|x| x.0), - size_gt: self.size_gt.map(|x| x.0 as usize), - size_lt: self.size_lt.map(|x| x.0 as usize), + size_gt: self.size_gt.map(|x| x.0 as u64), + size_lt: self.size_lt.map(|x| x.0 as u64), } } -- cgit v1.2.3 From 75ccc5a95c76f31235fcaab8a2c1795693733a4b Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Wed, 30 Aug 2023 20:02:07 +0200 Subject: lifecycle config: store date as given, try to debug --- src/api/s3/lifecycle.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src/api') 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, 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 and in "), (None, None) => Err(" must contain either or "), (Some(days), None) => Ok(GarageLifecycleExpiration::AfterDays(days.0 as usize)), - (None, Some(date)) => date - .0 - .parse::() - .map(GarageLifecycleExpiration::AtDate) - .map_err(|_| "Invalid expiration "), + (None, Some(date)) => { + trace!("date: {}", date.0); + parse_lifecycle_date(&date.0)?; + Ok(GarageLifecycleExpiration::AtDate(date.0)) + } } } -- cgit v1.2.3 From d2e94e36d64d4062ebe1fabac65ac1a6f265de17 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Wed, 30 Aug 2023 20:05:53 +0200 Subject: lifecycle config: add missing line in merge() and remove tracing --- src/api/s3/lifecycle.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'src/api') diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs index f0fde083..9036f84c 100644 --- a/src/api/s3/lifecycle.rs +++ b/src/api/s3/lifecycle.rs @@ -21,8 +21,6 @@ pub async fn handle_get_lifecycle(bucket: &Bucket) -> Result, 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)?; @@ -76,20 +74,12 @@ pub async fn handle_put_lifecycle( let param = bucket.params_mut().unwrap(); let conf: LifecycleConfiguration = from_reader(&body as &[u8])?; - let config = conf .validate_into_garage_lifecycle_config() .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?; - 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) @@ -281,7 +271,6 @@ impl Expiration { (None, None) => Err(" must contain either or "), (Some(days), None) => Ok(GarageLifecycleExpiration::AfterDays(days.0 as usize)), (None, Some(date)) => { - trace!("date: {}", date.0); parse_lifecycle_date(&date.0)?; Ok(GarageLifecycleExpiration::AtDate(date.0)) } -- cgit v1.2.3 From f0a395e2e5db977caff0ea46e17061e02929178a Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Wed, 30 Aug 2023 23:39:28 +0200 Subject: s3 bucket apis: remove redundant call --- src/api/s3/api_server.rs | 14 ++++++++------ src/api/s3/cors.rs | 22 ++++++++-------------- src/api/s3/lifecycle.rs | 22 ++++++++-------------- src/api/s3/website.rs | 22 ++++++++-------------- 4 files changed, 32 insertions(+), 48 deletions(-) (limited to 'src/api') diff --git a/src/api/s3/api_server.rs b/src/api/s3/api_server.rs index 06fef6d5..3f995d34 100644 --- a/src/api/s3/api_server.rs +++ b/src/api/s3/api_server.rs @@ -355,19 +355,21 @@ impl ApiHandler for S3ApiServer { } Endpoint::GetBucketWebsite {} => handle_get_website(&bucket).await, Endpoint::PutBucketWebsite {} => { - handle_put_website(garage, bucket_id, req, content_sha256).await + handle_put_website(garage, bucket.clone(), req, content_sha256).await } - Endpoint::DeleteBucketWebsite {} => handle_delete_website(garage, bucket_id).await, + Endpoint::DeleteBucketWebsite {} => handle_delete_website(garage, bucket.clone()).await, Endpoint::GetBucketCors {} => handle_get_cors(&bucket).await, Endpoint::PutBucketCors {} => { - handle_put_cors(garage, bucket_id, req, content_sha256).await + handle_put_cors(garage, bucket.clone(), req, content_sha256).await } - Endpoint::DeleteBucketCors {} => handle_delete_cors(garage, bucket_id).await, + Endpoint::DeleteBucketCors {} => handle_delete_cors(garage, bucket.clone()).await, Endpoint::GetBucketLifecycleConfiguration {} => handle_get_lifecycle(&bucket).await, Endpoint::PutBucketLifecycleConfiguration {} => { - handle_put_lifecycle(garage, bucket_id, req, content_sha256).await + handle_put_lifecycle(garage, bucket.clone(), req, content_sha256).await + } + Endpoint::DeleteBucketLifecycle {} => { + handle_delete_lifecycle(garage, bucket.clone()).await } - Endpoint::DeleteBucketLifecycle {} => handle_delete_lifecycle(garage, bucket_id).await, endpoint => Err(Error::NotImplemented(endpoint.name().to_owned())), }; diff --git a/src/api/s3/cors.rs b/src/api/s3/cors.rs index c7273464..49097ad1 100644 --- a/src/api/s3/cors.rs +++ b/src/api/s3/cors.rs @@ -44,14 +44,11 @@ pub async fn handle_get_cors(bucket: &Bucket) -> Result, Error> { pub async fn handle_delete_cors( garage: Arc, - bucket_id: Uuid, + mut bucket: Bucket, ) -> Result, Error> { - let mut bucket = garage - .bucket_helper() - .get_existing_bucket(bucket_id) - .await?; - - let param = bucket.params_mut().unwrap(); + let param = bucket + .params_mut() + .ok_or_internal_error("Bucket should not be deleted at this point")?; param.cors_config.update(None); garage.bucket_table.insert(&bucket).await?; @@ -63,7 +60,7 @@ pub async fn handle_delete_cors( pub async fn handle_put_cors( garage: Arc, - bucket_id: Uuid, + mut bucket: Bucket, req: Request, content_sha256: Option, ) -> Result, Error> { @@ -73,12 +70,9 @@ pub async fn handle_put_cors( verify_signed_content(content_sha256, &body[..])?; } - let mut bucket = garage - .bucket_helper() - .get_existing_bucket(bucket_id) - .await?; - - let param = bucket.params_mut().unwrap(); + let param = bucket + .params_mut() + .ok_or_internal_error("Bucket should not be deleted at this point")?; let conf: CorsConfiguration = from_reader(&body as &[u8])?; conf.validate()?; diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs index 9036f84c..11199190 100644 --- a/src/api/s3/lifecycle.rs +++ b/src/api/s3/lifecycle.rs @@ -37,14 +37,11 @@ pub async fn handle_get_lifecycle(bucket: &Bucket) -> Result, Err pub async fn handle_delete_lifecycle( garage: Arc, - bucket_id: Uuid, + mut bucket: Bucket, ) -> Result, Error> { - let mut bucket = garage - .bucket_helper() - .get_existing_bucket(bucket_id) - .await?; - - let param = bucket.params_mut().unwrap(); + let param = bucket + .params_mut() + .ok_or_internal_error("Bucket should not be deleted at this point")?; param.lifecycle_config.update(None); garage.bucket_table.insert(&bucket).await?; @@ -56,7 +53,7 @@ pub async fn handle_delete_lifecycle( pub async fn handle_put_lifecycle( garage: Arc, - bucket_id: Uuid, + mut bucket: Bucket, req: Request, content_sha256: Option, ) -> Result, Error> { @@ -66,12 +63,9 @@ pub async fn handle_put_lifecycle( verify_signed_content(content_sha256, &body[..])?; } - let mut bucket = garage - .bucket_helper() - .get_existing_bucket(bucket_id) - .await?; - - let param = bucket.params_mut().unwrap(); + let param = bucket + .params_mut() + .ok_or_internal_error("Bucket should not be deleted at this point")?; let conf: LifecycleConfiguration = from_reader(&body as &[u8])?; let config = conf diff --git a/src/api/s3/website.rs b/src/api/s3/website.rs index 77738971..7f2ab925 100644 --- a/src/api/s3/website.rs +++ b/src/api/s3/website.rs @@ -43,14 +43,11 @@ pub async fn handle_get_website(bucket: &Bucket) -> Result, Error pub async fn handle_delete_website( garage: Arc, - bucket_id: Uuid, + mut bucket: Bucket, ) -> Result, Error> { - let mut bucket = garage - .bucket_helper() - .get_existing_bucket(bucket_id) - .await?; - - let param = bucket.params_mut().unwrap(); + let param = bucket + .params_mut() + .ok_or_internal_error("Bucket should not be deleted at this point")?; param.website_config.update(None); garage.bucket_table.insert(&bucket).await?; @@ -62,7 +59,7 @@ pub async fn handle_delete_website( pub async fn handle_put_website( garage: Arc, - bucket_id: Uuid, + mut bucket: Bucket, req: Request, content_sha256: Option, ) -> Result, Error> { @@ -72,12 +69,9 @@ pub async fn handle_put_website( verify_signed_content(content_sha256, &body[..])?; } - let mut bucket = garage - .bucket_helper() - .get_existing_bucket(bucket_id) - .await?; - - let param = bucket.params_mut().unwrap(); + let param = bucket + .params_mut() + .ok_or_internal_error("Bucket should not be deleted at this point")?; let conf: WebsiteConfiguration = from_reader(&body as &[u8])?; conf.validate()?; -- cgit v1.2.3 From be03a4610f4a6e3863e6113491e308bbcea9ca94 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Thu, 31 Aug 2023 00:00:26 +0200 Subject: s3api: remove redundant serde rename attribute --- src/api/s3/lifecycle.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/api') diff --git a/src/api/s3/lifecycle.rs b/src/api/s3/lifecycle.rs index 11199190..1e7d6755 100644 --- a/src/api/s3/lifecycle.rs +++ b/src/api/s3/lifecycle.rs @@ -83,7 +83,6 @@ pub async fn handle_put_lifecycle( // ---- SERIALIZATION AND DESERIALIZATION TO/FROM S3 XML ---- #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] -#[serde(rename = "LifecycleConfiguration")] pub struct LifecycleConfiguration { #[serde(serialize_with = "xmlns_tag", skip_deserializing)] pub xmlns: (), -- cgit v1.2.3