mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-07 22:03:14 +00:00
fix(lifecycle): harden S3 lifecycle rule handling (#4115)
* fix(lifecycle): honor noncurrent version retention * fix(lifecycle): validate transition rules * fix(lifecycle): support immediate multipart abort * fix(lifecycle): harden select restore metadata * fix(lifecycle): expose stale multipart cleanup to app * fix(lifecycle): reduce expiry helper arguments
This commit is contained in:
@@ -23,8 +23,8 @@ use super::storage_api::bucket_usecase::bucket::{
|
||||
ObjectLockConfigExt as _, VersioningConfigExt as _,
|
||||
bucket_target_sys::BucketTargetSys,
|
||||
lifecycle::bucket_lifecycle_ops::{
|
||||
enqueue_expiry_for_existing_objects, enqueue_transition_for_existing_objects, validate_lifecycle_config,
|
||||
validate_transition_tier,
|
||||
enqueue_expiry_for_existing_objects, enqueue_transition_for_existing_objects, run_stale_multipart_upload_cleanup_once,
|
||||
validate_lifecycle_config, validate_transition_tier,
|
||||
},
|
||||
metadata::{
|
||||
BUCKET_CORS_CONFIG, BUCKET_LIFECYCLE_CONFIG, BUCKET_NOTIFICATION_CONFIG, BUCKET_POLICY_CONFIG,
|
||||
@@ -756,6 +756,13 @@ fn lifecycle_has_expiry_rules(config: &BucketLifecycleConfiguration) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
fn lifecycle_has_abort_multipart_rules(config: &BucketLifecycleConfiguration) -> bool {
|
||||
config.rules.iter().any(|rule| {
|
||||
rule.status == ExpirationStatus::from_static(ExpirationStatus::ENABLED)
|
||||
&& rule.abort_incomplete_multipart_upload.is_some()
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DefaultBucketUsecase {
|
||||
context: Option<Arc<AppContext>>,
|
||||
@@ -1721,6 +1728,17 @@ impl DefaultBucketUsecase {
|
||||
});
|
||||
}
|
||||
|
||||
if lifecycle_has_abort_multipart_rules(&input_cfg)
|
||||
&& let Some(store) = self.object_store()
|
||||
{
|
||||
let bucket_name = bucket.clone();
|
||||
let request_context = req.extensions.get::<request_context::RequestContext>().cloned();
|
||||
spawn_background_with_context(request_context, async move {
|
||||
let deleted = run_stale_multipart_upload_cleanup_once(store).await;
|
||||
debug!(bucket = %bucket_name, deleted, "completed lifecycle abort multipart cleanup trigger");
|
||||
});
|
||||
}
|
||||
|
||||
rustfs_scanner::record_dirty_usage_bucket(&bucket);
|
||||
Ok(S3Response::new(PutBucketLifecycleConfigurationOutput::default()))
|
||||
}
|
||||
@@ -2789,6 +2807,30 @@ mod tests {
|
||||
assert!(lifecycle_has_transition_rules(&config));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lifecycle_has_abort_multipart_rules_accepts_enabled_abort_rule() {
|
||||
let config = BucketLifecycleConfiguration {
|
||||
expiry_updated_at: None,
|
||||
rules: vec![LifecycleRule {
|
||||
status: ExpirationStatus::from_static(ExpirationStatus::ENABLED),
|
||||
expiration: None,
|
||||
abort_incomplete_multipart_upload: Some(s3s::dto::AbortIncompleteMultipartUpload {
|
||||
days_after_initiation: Some(0),
|
||||
}),
|
||||
del_marker_expiration: None,
|
||||
filter: None,
|
||||
id: Some("enabled-abort".to_string()),
|
||||
noncurrent_version_expiration: None,
|
||||
noncurrent_version_transitions: None,
|
||||
prefix: None,
|
||||
transitions: None,
|
||||
}],
|
||||
};
|
||||
|
||||
assert!(lifecycle_has_abort_multipart_rules(&config));
|
||||
assert!(!lifecycle_has_expiry_rules(&config));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn execute_list_buckets_returns_internal_error_when_store_uninitialized() {
|
||||
let input = ListBucketsInput::builder().build().unwrap();
|
||||
|
||||
@@ -336,6 +336,13 @@ pub(crate) mod bucket {
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn run_stale_multipart_upload_cleanup_once(api: Arc<crate::storage::storage_api::ECStore>) -> usize {
|
||||
crate::storage::storage_api::ecstore_bucket::lifecycle::bucket_lifecycle_ops::run_stale_multipart_upload_cleanup_once(
|
||||
api,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn enqueue_transition_immediate(
|
||||
oi: &crate::storage::storage_api::StorageObjectInfo,
|
||||
src: LcEventSrc,
|
||||
|
||||
Reference in New Issue
Block a user