mirror of
https://github.com/minio/minio-rs.git
synced 2025-12-06 15:26:51 +08:00
Refactor bucket lifecycle (#121)
* bugfix & added example * refactor set_bucket_lifecycle amd get_bucket_lifecycle
This commit is contained in:
parent
c4e302dda7
commit
b2a6cb2655
@ -34,7 +34,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
|
||||
let _resp: SetBucketEncryptionResponse = client
|
||||
.set_bucket_encryption(bucket_name)
|
||||
.config(SseConfig::default())
|
||||
.sse_config(SseConfig::default())
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
|
||||
88
examples/bucket_lifecycle.rs
Normal file
88
examples/bucket_lifecycle.rs
Normal file
@ -0,0 +1,88 @@
|
||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||
// Copyright 2025 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod common;
|
||||
|
||||
use crate::common::{create_bucket_if_not_exists, create_client_on_play};
|
||||
use minio::s3::args::DeleteBucketLifecycleArgs;
|
||||
use minio::s3::response::{
|
||||
DeleteBucketLifecycleResponse, GetBucketLifecycleResponse, SetBucketLifecycleResponse,
|
||||
};
|
||||
use minio::s3::types::{Filter, LifecycleConfig, LifecycleRule, S3Api};
|
||||
use minio::s3::Client;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
env_logger::init(); // Note: set environment variable RUST_LOG="INFO" to log info and higher
|
||||
let client: Client = create_client_on_play()?;
|
||||
|
||||
let bucket_name: &str = "lifecycle-rust-bucket";
|
||||
create_bucket_if_not_exists(bucket_name, &client).await?;
|
||||
|
||||
if false {
|
||||
// TODO
|
||||
let resp: GetBucketLifecycleResponse =
|
||||
client.get_bucket_lifecycle(bucket_name).send().await?;
|
||||
log::info!("life cycle settings before setting: resp={:?}", resp);
|
||||
}
|
||||
|
||||
let rules: Vec<LifecycleRule> = vec![LifecycleRule {
|
||||
abort_incomplete_multipart_upload_days_after_initiation: None,
|
||||
expiration_date: None,
|
||||
expiration_days: Some(365),
|
||||
expiration_expired_object_delete_marker: None,
|
||||
filter: Filter {
|
||||
and_operator: None,
|
||||
prefix: Some(String::from("logs/")),
|
||||
tag: None,
|
||||
},
|
||||
id: String::from("rule1"),
|
||||
noncurrent_version_expiration_noncurrent_days: None,
|
||||
noncurrent_version_transition_noncurrent_days: None,
|
||||
noncurrent_version_transition_storage_class: None,
|
||||
status: true,
|
||||
transition_date: None,
|
||||
transition_days: None,
|
||||
transition_storage_class: None,
|
||||
}];
|
||||
|
||||
let resp: SetBucketLifecycleResponse = client
|
||||
.set_bucket_lifecycle(bucket_name)
|
||||
.life_cycle_config(LifecycleConfig { rules })
|
||||
.send()
|
||||
.await?;
|
||||
log::info!("response of setting life cycle config: resp={:?}", resp);
|
||||
|
||||
if false {
|
||||
// TODO
|
||||
let resp: GetBucketLifecycleResponse =
|
||||
client.get_bucket_lifecycle(bucket_name).send().await?;
|
||||
log::info!("life cycle settings after setting: resp={:?}", resp);
|
||||
}
|
||||
|
||||
if false {
|
||||
// TODO
|
||||
let resp: DeleteBucketLifecycleResponse = client
|
||||
.delete_bucket_lifecycle(&DeleteBucketLifecycleArgs {
|
||||
extra_headers: None,
|
||||
extra_query_params: None,
|
||||
region: None,
|
||||
bucket: "",
|
||||
})
|
||||
.await?;
|
||||
log::info!("response of deleting lifecycle config: resp={:?}", resp);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -19,8 +19,8 @@ use crate::s3::error::Error;
|
||||
use crate::s3::signer::post_presign_v4;
|
||||
use crate::s3::sse::{Sse, SseCustomerKey};
|
||||
use crate::s3::types::{
|
||||
Directive, LifecycleConfig, NotificationConfig, ObjectLockConfig, Part, ReplicationConfig,
|
||||
Retention, RetentionMode, SelectRequest,
|
||||
Directive, NotificationConfig, ObjectLockConfig, Part, ReplicationConfig, Retention,
|
||||
RetentionMode, SelectRequest,
|
||||
};
|
||||
use crate::s3::utils::{
|
||||
b64encode, check_bucket_name, merge, to_amz_date, to_http_header_value, to_iso8601utc,
|
||||
@ -1333,58 +1333,6 @@ pub type DeleteBucketLifecycleArgs<'a> = BucketArgs<'a>;
|
||||
/// Argument for [get_bucket_lifecycle()](crate::s3::client::Client::get_bucket_lifecycle) API
|
||||
pub type GetBucketLifecycleArgs<'a> = BucketArgs<'a>;
|
||||
|
||||
/// Argument for [set_bucket_lifecycle()](crate::s3::client::Client::set_bucket_lifecycle) API
|
||||
pub struct SetBucketLifecycleArgs<'a> {
|
||||
pub extra_headers: Option<&'a Multimap>,
|
||||
pub extra_query_params: Option<&'a Multimap>,
|
||||
pub region: Option<&'a str>,
|
||||
pub bucket: &'a str,
|
||||
pub config: &'a LifecycleConfig,
|
||||
}
|
||||
|
||||
impl<'a> SetBucketLifecycleArgs<'a> {
|
||||
/// Returns argument for [set_bucket_lifecycle()](crate::s3::client::Client::set_bucket_lifecycle) API with given bucket name and configuration
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use minio::s3::args::*;
|
||||
/// use minio::s3::types::*;
|
||||
/// let mut rules: Vec<LifecycleRule> = Vec::new();
|
||||
/// rules.push(LifecycleRule {
|
||||
/// abort_incomplete_multipart_upload_days_after_initiation: None,
|
||||
/// expiration_date: None,
|
||||
/// expiration_days: Some(365),
|
||||
/// expiration_expired_object_delete_marker: None,
|
||||
/// filter: Filter {and_operator: None, prefix: Some(String::from("logs/")), tag: None},
|
||||
/// id: String::from("rule1"),
|
||||
/// noncurrent_version_expiration_noncurrent_days: None,
|
||||
/// noncurrent_version_transition_noncurrent_days: None,
|
||||
/// noncurrent_version_transition_storage_class: None,
|
||||
/// status: true,
|
||||
/// transition_date: None,
|
||||
/// transition_days: None,
|
||||
/// transition_storage_class: None,
|
||||
/// });
|
||||
/// let mut config = LifecycleConfig {rules};
|
||||
/// let args = SetBucketLifecycleArgs::new("my-bucket", &config).unwrap();
|
||||
/// ```
|
||||
pub fn new(
|
||||
bucket_name: &'a str,
|
||||
config: &'a LifecycleConfig,
|
||||
) -> Result<SetBucketLifecycleArgs<'a>, Error> {
|
||||
check_bucket_name(bucket_name, true)?;
|
||||
|
||||
Ok(SetBucketLifecycleArgs {
|
||||
extra_headers: None,
|
||||
extra_query_params: None,
|
||||
region: None,
|
||||
bucket: bucket_name,
|
||||
config,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Argument for [delete_bucket_notification()](crate::s3::client::Client::delete_bucket_notification) API
|
||||
pub type DeleteBucketNotificationArgs<'a> = BucketArgs<'a>;
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
mod bucket_common;
|
||||
mod get_bucket_encryption;
|
||||
mod get_bucket_lifecycle;
|
||||
mod get_bucket_versioning;
|
||||
mod get_object;
|
||||
mod list_buckets;
|
||||
@ -27,10 +28,12 @@ mod object_prompt;
|
||||
mod put_object;
|
||||
mod remove_objects;
|
||||
mod set_bucket_encryption;
|
||||
mod set_bucket_lifecycle;
|
||||
mod set_bucket_versioning;
|
||||
|
||||
pub use bucket_common::*;
|
||||
pub use get_bucket_encryption::*;
|
||||
pub use get_bucket_lifecycle::*;
|
||||
pub use get_bucket_versioning::*;
|
||||
pub use get_object::*;
|
||||
pub use list_buckets::*;
|
||||
@ -41,4 +44,5 @@ pub use object_prompt::*;
|
||||
pub use put_object::*;
|
||||
pub use remove_objects::*;
|
||||
pub use set_bucket_encryption::*;
|
||||
pub use set_bucket_lifecycle::*;
|
||||
pub use set_bucket_versioning::*;
|
||||
|
||||
@ -20,7 +20,7 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
|
||||
use crate::s3::utils::{check_bucket_name, merge, Multimap};
|
||||
use http::Method;
|
||||
|
||||
/// Argument builder for [get_bucket_encryption()](Client::get_bucket_encryption) API
|
||||
/// Argument builder for [get_bucket_encryption()](crate::s3::client::Client::get_bucket_encryption) API
|
||||
pub type GetBucketEncryption = BucketCommon<GetBucketEncryptionPhantomData>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
||||
63
src/s3/builders/get_bucket_lifecycle.rs
Normal file
63
src/s3/builders/get_bucket_lifecycle.rs
Normal file
@ -0,0 +1,63 @@
|
||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||
// Copyright 2025 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::s3::builders::BucketCommon;
|
||||
use crate::s3::error::Error;
|
||||
use crate::s3::response::GetBucketLifecycleResponse;
|
||||
use crate::s3::types::{S3Api, S3Request, ToS3Request};
|
||||
use crate::s3::utils::check_bucket_name;
|
||||
use crate::s3::Client;
|
||||
use http::Method;
|
||||
|
||||
/// Argument builder for [get_bucket_lifecycle()](Client::get_bucket_lifecycle) API
|
||||
pub type GetBucketLifecycle = BucketCommon<GetBucketLifecyclePhantomData>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct GetBucketLifecyclePhantomData;
|
||||
|
||||
impl S3Api for GetBucketLifecycle {
|
||||
type S3Response = GetBucketLifecycleResponse;
|
||||
}
|
||||
|
||||
impl ToS3Request for GetBucketLifecycle {
|
||||
fn to_s3request(&self) -> Result<S3Request, Error> {
|
||||
check_bucket_name(&self.bucket, true)?;
|
||||
|
||||
let headers = self
|
||||
.extra_headers
|
||||
.as_ref()
|
||||
.filter(|v| !v.is_empty())
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let mut query_params = self
|
||||
.extra_query_params
|
||||
.as_ref()
|
||||
.filter(|v| !v.is_empty())
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
query_params.insert("lifecycle".into(), String::new());
|
||||
|
||||
let client: &Client = self.client.as_ref().ok_or(Error::NoClientProvided)?;
|
||||
|
||||
let req = S3Request::new(client, Method::GET)
|
||||
.region(self.region.as_deref())
|
||||
.bucket(Some(&self.bucket))
|
||||
.query_params(query_params)
|
||||
.headers(headers);
|
||||
|
||||
Ok(req)
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
|
||||
use crate::s3::utils::{check_bucket_name, merge, Multimap};
|
||||
use http::Method;
|
||||
|
||||
/// Argument builder for [get_bucket_versioning()](Client::get_bucket_versioning) API
|
||||
/// Argument builder for [get_bucket_versioning()](crate::s3::client::Client::get_bucket_versioning) API
|
||||
pub type GetBucketVersioning = BucketCommon<GetBucketVersioningPhantomData>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
||||
@ -63,7 +63,7 @@ impl SetBucketEncryption {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn config(mut self, config: SseConfig) -> Self {
|
||||
pub fn sse_config(mut self, config: SseConfig) -> Self {
|
||||
self.config = config;
|
||||
self
|
||||
}
|
||||
|
||||
109
src/s3/builders/set_bucket_lifecycle.rs
Normal file
109
src/s3/builders/set_bucket_lifecycle.rs
Normal file
@ -0,0 +1,109 @@
|
||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||
// Copyright 2025 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::s3::builders::SegmentedBytes;
|
||||
use crate::s3::error::Error;
|
||||
use crate::s3::response::SetBucketLifecycleResponse;
|
||||
use crate::s3::types::{LifecycleConfig, S3Api, S3Request, ToS3Request};
|
||||
use crate::s3::utils::{check_bucket_name, md5sum_hash, Multimap};
|
||||
use crate::s3::Client;
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
|
||||
/// Argument builder for [set_bucket_lifecycle()](crate::s3::client::Client::set_bucket_lifecycle) API
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SetBucketLifecycle {
|
||||
pub(crate) client: Option<Client>,
|
||||
|
||||
pub(crate) extra_headers: Option<Multimap>,
|
||||
pub(crate) extra_query_params: Option<Multimap>,
|
||||
pub(crate) region: Option<String>,
|
||||
pub(crate) bucket: String,
|
||||
|
||||
pub(crate) config: LifecycleConfig,
|
||||
}
|
||||
|
||||
impl SetBucketLifecycle {
|
||||
pub fn new(bucket: &str) -> Self {
|
||||
Self {
|
||||
bucket: bucket.to_owned(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn client(mut self, client: &Client) -> Self {
|
||||
self.client = Some(client.clone());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn extra_headers(mut self, extra_headers: Option<Multimap>) -> Self {
|
||||
self.extra_headers = extra_headers;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn extra_query_params(mut self, extra_query_params: Option<Multimap>) -> Self {
|
||||
self.extra_query_params = extra_query_params;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn region(mut self, region: Option<String>) -> Self {
|
||||
self.region = region;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn life_cycle_config(mut self, config: LifecycleConfig) -> Self {
|
||||
self.config = config;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl S3Api for SetBucketLifecycle {
|
||||
type S3Response = SetBucketLifecycleResponse;
|
||||
}
|
||||
|
||||
impl ToS3Request for SetBucketLifecycle {
|
||||
fn to_s3request(&self) -> Result<S3Request, Error> {
|
||||
check_bucket_name(&self.bucket, true)?;
|
||||
|
||||
let mut headers = self
|
||||
.extra_headers
|
||||
.as_ref()
|
||||
.filter(|v| !v.is_empty())
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let mut query_params = self
|
||||
.extra_query_params
|
||||
.as_ref()
|
||||
.filter(|v| !v.is_empty())
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
query_params.insert("lifecycle".into(), String::new());
|
||||
|
||||
let bytes: Bytes = self.config.to_xml().into();
|
||||
headers.insert(String::from("Content-MD5"), md5sum_hash(&bytes));
|
||||
let body: Option<SegmentedBytes> = Some(SegmentedBytes::from(bytes));
|
||||
|
||||
let client: &Client = self.client.as_ref().ok_or(Error::NoClientProvided)?;
|
||||
|
||||
let req = S3Request::new(client, Method::PUT)
|
||||
.region(self.region.as_deref())
|
||||
.bucket(Some(&self.bucket))
|
||||
.query_params(query_params)
|
||||
.headers(headers)
|
||||
.body(body);
|
||||
|
||||
Ok(req)
|
||||
}
|
||||
}
|
||||
@ -40,7 +40,7 @@ impl fmt::Display for VersioningStatus {
|
||||
}
|
||||
}
|
||||
|
||||
/// Argument builder for [set_bucket_encryption()](Client::set_bucket_encryption) API
|
||||
/// Argument builder for [set_bucket_encryption()](crate::s3::client::Client::set_bucket_encryption) API
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SetBucketVersioning {
|
||||
pub(crate) client: Option<Client>,
|
||||
|
||||
131
src/s3/client.rs
131
src/s3/client.rs
@ -29,8 +29,7 @@ use crate::s3::response::*;
|
||||
use crate::s3::signer::{presign_v4, sign_v4_s3};
|
||||
use crate::s3::sse::SseCustomerKey;
|
||||
use crate::s3::types::{
|
||||
Directive, LifecycleConfig, NotificationConfig, ObjectLockConfig, Part, ReplicationConfig,
|
||||
RetentionMode,
|
||||
Directive, NotificationConfig, ObjectLockConfig, Part, ReplicationConfig, RetentionMode,
|
||||
};
|
||||
use crate::s3::utils::{
|
||||
from_iso8601utc, get_default_text, get_option_text, get_text, md5sum_hash, md5sum_hash_sb,
|
||||
@ -48,6 +47,7 @@ use tokio::fs;
|
||||
use xmltree::Element;
|
||||
|
||||
mod get_bucket_encryption;
|
||||
mod get_bucket_lifecycle;
|
||||
mod get_bucket_versioning;
|
||||
mod get_object;
|
||||
mod list_objects;
|
||||
@ -56,6 +56,7 @@ mod object_prompt;
|
||||
mod put_object;
|
||||
mod remove_objects;
|
||||
mod set_bucket_encryption;
|
||||
mod set_bucket_lifecycle;
|
||||
mod set_bucket_versioning;
|
||||
|
||||
use super::builders::{ListBuckets, SegmentedBytes};
|
||||
@ -1204,7 +1205,7 @@ impl Client {
|
||||
Ok(resp) => Ok(DeleteBucketEncryptionResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
}),
|
||||
Err(e) => match e {
|
||||
Error::S3Error(ref err) => {
|
||||
@ -1212,7 +1213,7 @@ impl Client {
|
||||
return Ok(DeleteBucketEncryptionResponse {
|
||||
headers: HeaderMap::new(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
});
|
||||
}
|
||||
Err(e)
|
||||
@ -1297,7 +1298,7 @@ impl Client {
|
||||
Ok(DeleteBucketLifecycleResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -1351,7 +1352,7 @@ impl Client {
|
||||
Ok(resp) => Ok(DeleteBucketPolicyResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
}),
|
||||
Err(e) => match e {
|
||||
Error::S3Error(ref err) => {
|
||||
@ -1359,7 +1360,7 @@ impl Client {
|
||||
return Ok(DeleteBucketPolicyResponse {
|
||||
headers: HeaderMap::new(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
});
|
||||
}
|
||||
Err(e)
|
||||
@ -1401,7 +1402,7 @@ impl Client {
|
||||
Ok(resp) => Ok(DeleteBucketReplicationResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
}),
|
||||
Err(e) => match e {
|
||||
Error::S3Error(ref err) => {
|
||||
@ -1409,7 +1410,7 @@ impl Client {
|
||||
return Ok(DeleteBucketReplicationResponse {
|
||||
headers: HeaderMap::new(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
});
|
||||
}
|
||||
Err(e)
|
||||
@ -1451,7 +1452,7 @@ impl Client {
|
||||
Ok(DeleteBucketTagsResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -1606,64 +1607,6 @@ impl Client {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_bucket_lifecycle(
|
||||
&self,
|
||||
args: &GetBucketLifecycleArgs<'_>,
|
||||
) -> Result<GetBucketLifecycleResponse, Error> {
|
||||
let region = self.get_region(args.bucket, args.region).await?;
|
||||
|
||||
let mut headers = Multimap::new();
|
||||
if let Some(v) = &args.extra_headers {
|
||||
merge(&mut headers, v);
|
||||
}
|
||||
|
||||
let mut query_params = Multimap::new();
|
||||
if let Some(v) = &args.extra_query_params {
|
||||
merge(&mut query_params, v);
|
||||
}
|
||||
query_params.insert(String::from("lifecycle"), String::new());
|
||||
|
||||
match self
|
||||
.execute(
|
||||
Method::GET,
|
||||
®ion,
|
||||
&mut headers,
|
||||
&query_params,
|
||||
Some(args.bucket),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(resp) => {
|
||||
let header_map = resp.headers().clone();
|
||||
let body = resp.bytes().await?;
|
||||
let root = Element::parse(body.reader())?;
|
||||
|
||||
Ok(GetBucketLifecycleResponse {
|
||||
headers: header_map.clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
config: LifecycleConfig::from_xml(&root)?,
|
||||
})
|
||||
}
|
||||
Err(e) => match e {
|
||||
Error::S3Error(ref err) => {
|
||||
if err.code == "NoSuchLifecycleConfiguration" {
|
||||
return Ok(GetBucketLifecycleResponse {
|
||||
headers: HeaderMap::new(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
config: LifecycleConfig { rules: Vec::new() },
|
||||
});
|
||||
}
|
||||
Err(e)
|
||||
}
|
||||
_ => Err(e),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_bucket_notification(
|
||||
&self,
|
||||
args: &GetBucketNotificationArgs<'_>,
|
||||
@ -2274,7 +2217,7 @@ impl Client {
|
||||
Ok(MakeBucketResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.to_string(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2521,43 +2464,7 @@ impl Client {
|
||||
Ok(RemoveBucketResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.to_string(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn set_bucket_lifecycle(
|
||||
&self,
|
||||
args: &SetBucketLifecycleArgs<'_>,
|
||||
) -> Result<SetBucketLifecycleResponse, Error> {
|
||||
let region = self.get_region(args.bucket, args.region).await?;
|
||||
|
||||
let mut headers = Multimap::new();
|
||||
if let Some(v) = &args.extra_headers {
|
||||
merge(&mut headers, v);
|
||||
}
|
||||
|
||||
let mut query_params = Multimap::new();
|
||||
if let Some(v) = &args.extra_query_params {
|
||||
merge(&mut query_params, v);
|
||||
}
|
||||
query_params.insert(String::from("lifecycle"), String::new());
|
||||
|
||||
let resp = self
|
||||
.execute(
|
||||
Method::PUT,
|
||||
®ion,
|
||||
&mut headers,
|
||||
&query_params,
|
||||
Some(args.bucket),
|
||||
None,
|
||||
Some(args.config.to_xml().into()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(SetBucketLifecycleResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2593,7 +2500,7 @@ impl Client {
|
||||
Ok(SetBucketNotificationResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2629,7 +2536,7 @@ impl Client {
|
||||
Ok(SetBucketPolicyResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2665,7 +2572,7 @@ impl Client {
|
||||
Ok(SetBucketReplicationResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2718,7 +2625,7 @@ impl Client {
|
||||
Ok(SetBucketTagsResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2754,7 +2661,7 @@ impl Client {
|
||||
Ok(SetObjectLockConfigResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: region.clone(),
|
||||
bucket_name: args.bucket.to_string(),
|
||||
bucket: args.bucket.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2797,7 +2704,7 @@ impl Client {
|
||||
}
|
||||
data.push_str("</Retention>");
|
||||
|
||||
headers.insert(String::from("Content-MD5"), md5sum_hash(data.as_bytes()));
|
||||
headers.insert(String::from("Content-MD5"), md5sum_hash(data.as_ref()));
|
||||
|
||||
let resp = self
|
||||
.execute(
|
||||
|
||||
26
src/s3/client/get_bucket_lifecycle.rs
Normal file
26
src/s3/client/get_bucket_lifecycle.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||
// Copyright 2025 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! S3 APIs for bucket objects.
|
||||
|
||||
use super::Client;
|
||||
use crate::s3::builders::GetBucketLifecycle;
|
||||
|
||||
impl Client {
|
||||
/// Create a GetBucketLifecycle request builder.
|
||||
pub fn get_bucket_lifecycle(&self, bucket: &str) -> GetBucketLifecycle {
|
||||
GetBucketLifecycle::new(bucket).client(self)
|
||||
}
|
||||
}
|
||||
59
src/s3/client/set_bucket_lifecycle.rs
Normal file
59
src/s3/client/set_bucket_lifecycle.rs
Normal file
@ -0,0 +1,59 @@
|
||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||
// Copyright 2025 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! S3 APIs for bucket objects.
|
||||
|
||||
use super::Client;
|
||||
use crate::s3::builders::SetBucketLifecycle;
|
||||
|
||||
impl Client {
|
||||
/// Create a SetBucketLifecycle request builder.
|
||||
///
|
||||
/// Returns argument for [set_bucket_lifecycle()](crate::s3::client::Client::set_bucket_lifecycle) API with given bucket name and configuration
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use minio::s3::Client;
|
||||
/// use minio::s3::types::{Filter, LifecycleConfig, LifecycleRule, S3Api};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let rules: Vec<LifecycleRule> = vec![LifecycleRule {
|
||||
/// abort_incomplete_multipart_upload_days_after_initiation: None,
|
||||
/// expiration_date: None,
|
||||
/// expiration_days: Some(365),
|
||||
/// expiration_expired_object_delete_marker: None,
|
||||
/// filter: Filter {and_operator: None, prefix: Some(String::from("logs/")), tag: None},
|
||||
/// id: String::from("rule1"),
|
||||
/// noncurrent_version_expiration_noncurrent_days: None,
|
||||
/// noncurrent_version_transition_noncurrent_days: None,
|
||||
/// noncurrent_version_transition_storage_class: None,
|
||||
/// status: true,
|
||||
/// transition_date: None,
|
||||
/// transition_days: None,
|
||||
/// transition_storage_class: None,
|
||||
/// }];
|
||||
/// let client = Client::default();
|
||||
/// let _resp = client
|
||||
/// .set_bucket_lifecycle("my-bucket-name")
|
||||
/// .life_cycle_config(LifecycleConfig { rules })
|
||||
/// .send().await;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn set_bucket_lifecycle(&self, bucket: &str) -> SetBucketLifecycle {
|
||||
SetBucketLifecycle::new(bucket).client(self)
|
||||
}
|
||||
}
|
||||
@ -24,14 +24,15 @@ use xmltree::Element;
|
||||
|
||||
use crate::s3::error::Error;
|
||||
use crate::s3::types::{
|
||||
parse_legal_hold, LifecycleConfig, NotificationConfig, ObjectLockConfig, ReplicationConfig,
|
||||
RetentionMode, SelectProgress,
|
||||
parse_legal_hold, NotificationConfig, ObjectLockConfig, ReplicationConfig, RetentionMode,
|
||||
SelectProgress,
|
||||
};
|
||||
use crate::s3::utils::{
|
||||
copy_slice, crc32, from_http_header_value, from_iso8601utc, get_text, uint32, UtcTime,
|
||||
};
|
||||
|
||||
mod get_bucket_encryption;
|
||||
mod get_bucket_lifecycle;
|
||||
mod get_bucket_versioning;
|
||||
mod get_object;
|
||||
mod list_buckets;
|
||||
@ -41,9 +42,11 @@ mod object_prompt;
|
||||
mod put_object;
|
||||
mod remove_objects;
|
||||
mod set_bucket_encryption;
|
||||
mod set_bucket_lifecycle;
|
||||
mod set_bucket_versioning;
|
||||
|
||||
pub use get_bucket_encryption::GetBucketEncryptionResponse;
|
||||
pub use get_bucket_lifecycle::GetBucketLifecycleResponse;
|
||||
pub use get_bucket_versioning::GetBucketVersioningResponse;
|
||||
pub use get_object::GetObjectResponse;
|
||||
pub use list_buckets::ListBucketsResponse;
|
||||
@ -57,6 +60,7 @@ pub use put_object::{
|
||||
};
|
||||
pub use remove_objects::{DeleteError, DeletedObject, RemoveObjectResponse, RemoveObjectsResponse};
|
||||
pub use set_bucket_encryption::SetBucketEncryptionResponse;
|
||||
pub use set_bucket_lifecycle::SetBucketLifecycleResponse;
|
||||
pub use set_bucket_versioning::SetBucketVersioningResponse;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -64,7 +68,7 @@ pub use set_bucket_versioning::SetBucketVersioningResponse;
|
||||
pub struct BucketResponse {
|
||||
pub headers: HeaderMap,
|
||||
pub region: String,
|
||||
pub bucket_name: String,
|
||||
pub bucket: String,
|
||||
}
|
||||
|
||||
/// Response of [make_bucket()](crate::s3::client::Client::make_bucket) API
|
||||
@ -577,18 +581,6 @@ pub struct IsObjectLegalHoldEnabledResponse {
|
||||
/// Response of [delete_bucket_lifecycle()](crate::s3::client::Client::delete_bucket_lifecycle) API
|
||||
pub type DeleteBucketLifecycleResponse = BucketResponse;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Response of [get_bucket_lifecycle()](crate::s3::client::Client::get_bucket_lifecycle) API
|
||||
pub struct GetBucketLifecycleResponse {
|
||||
pub headers: HeaderMap,
|
||||
pub region: String,
|
||||
pub bucket_name: String,
|
||||
pub config: LifecycleConfig,
|
||||
}
|
||||
|
||||
/// Response of [set_bucket_lifecycle()](crate::s3::client::Client::set_bucket_lifecycle) API
|
||||
pub type SetBucketLifecycleResponse = BucketResponse;
|
||||
|
||||
/// Response of [delete_bucket_notification()](crate::s3::client::Client::delete_bucket_notification) API
|
||||
pub type DeleteBucketNotificationResponse = BucketResponse;
|
||||
|
||||
|
||||
56
src/s3/response/get_bucket_lifecycle.rs
Normal file
56
src/s3/response/get_bucket_lifecycle.rs
Normal file
@ -0,0 +1,56 @@
|
||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||
// Copyright 2025 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::s3::error::Error;
|
||||
use crate::s3::types::{FromS3Response, LifecycleConfig, S3Request};
|
||||
use async_trait::async_trait;
|
||||
use bytes::Buf;
|
||||
use http::HeaderMap;
|
||||
use xmltree::Element;
|
||||
|
||||
/// Response of
|
||||
/// [get_bucket_lifecycle()](crate::s3::client::Client::get_bucket_lifecycle)
|
||||
/// API
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GetBucketLifecycleResponse {
|
||||
pub headers: HeaderMap,
|
||||
pub region: String,
|
||||
pub bucket: String,
|
||||
pub config: LifecycleConfig,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FromS3Response for GetBucketLifecycleResponse {
|
||||
async fn from_s3response<'a>(
|
||||
req: S3Request<'a>,
|
||||
resp: reqwest::Response,
|
||||
) -> Result<Self, Error> {
|
||||
let bucket: String = match req.bucket {
|
||||
None => return Err(Error::InvalidBucketName("no bucket specified".to_string())),
|
||||
Some(v) => v.to_string(),
|
||||
};
|
||||
let headers = resp.headers().clone();
|
||||
let body = resp.bytes().await?;
|
||||
let root = Element::parse(body.reader())?;
|
||||
let config = LifecycleConfig::from_xml(&root)?;
|
||||
|
||||
Ok(GetBucketLifecycleResponse {
|
||||
headers,
|
||||
region: req.get_computed_region(),
|
||||
bucket,
|
||||
config,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,7 @@ use xmltree::Element;
|
||||
/// Response of
|
||||
/// [set_bucket_encryption()](crate::s3::client::Client::set_bucket_encryption)
|
||||
/// API
|
||||
/// TODO equal to GetBucketEncryptionResponse
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SetBucketEncryptionResponse {
|
||||
pub headers: HeaderMap,
|
||||
|
||||
47
src/s3/response/set_bucket_lifecycle.rs
Normal file
47
src/s3/response/set_bucket_lifecycle.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||
// Copyright 2025 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::s3::error::Error;
|
||||
use crate::s3::types::{FromS3Response, S3Request};
|
||||
use async_trait::async_trait;
|
||||
use http::HeaderMap;
|
||||
|
||||
/// Response of [set_bucket_lifecycle()](crate::s3::client::Client::set_bucket_lifecycle) API
|
||||
#[derive(Debug)]
|
||||
/// TODO is identical ot BucketResponse
|
||||
pub struct SetBucketLifecycleResponse {
|
||||
pub headers: HeaderMap,
|
||||
pub region: String,
|
||||
pub bucket: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FromS3Response for SetBucketLifecycleResponse {
|
||||
async fn from_s3response<'a>(
|
||||
req: S3Request<'a>,
|
||||
resp: reqwest::Response,
|
||||
) -> Result<Self, Error> {
|
||||
let bucket: String = match req.bucket {
|
||||
None => return Err(Error::InvalidBucketName("no bucket specified".to_string())),
|
||||
Some(v) => v.to_string(),
|
||||
};
|
||||
|
||||
Ok(SetBucketLifecycleResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: req.get_computed_region(),
|
||||
bucket,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -14,12 +14,18 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::s3::error::Error;
|
||||
use crate::s3::response::BucketResponse;
|
||||
use crate::s3::types::{FromS3Response, S3Request};
|
||||
use async_trait::async_trait;
|
||||
use http::HeaderMap;
|
||||
|
||||
/// Response of [set_bucket_versioning()](Client::set_bucket_versioning) API
|
||||
pub type SetBucketVersioningResponse = BucketResponse;
|
||||
/// Response of [set_bucket_versioning()](crate::s3::client::Client::set_bucket_versioning) API
|
||||
#[derive(Debug)]
|
||||
/// TODO is identical ot BucketResponse
|
||||
pub struct SetBucketVersioningResponse {
|
||||
pub headers: HeaderMap,
|
||||
pub region: String,
|
||||
pub bucket: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FromS3Response for SetBucketVersioningResponse {
|
||||
@ -35,7 +41,7 @@ impl FromS3Response for SetBucketVersioningResponse {
|
||||
Ok(SetBucketVersioningResponse {
|
||||
headers: resp.headers().clone(),
|
||||
region: req.get_computed_region(),
|
||||
bucket_name: bucket,
|
||||
bucket,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1099,7 +1099,7 @@ impl LifecycleRule {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
/// Lifecycle configuration
|
||||
pub struct LifecycleConfig {
|
||||
pub rules: Vec<LifecycleRule>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user