From 9469dfa5b811d6cf22d3b6e109f0960638ebc0f1 Mon Sep 17 00:00:00 2001 From: Jason Kossis Date: Tue, 21 Jul 2026 13:22:41 -0400 Subject: [PATCH] fix(site-replication): delete replicated buckets --- .config/nextest.toml | 4 +- .../site-replication/run-object-flow-check.sh | 41 +++- .../site-replication-bucket-delete-epoch.png | Bin 0 -> 107742 bytes .../ecstore/src/cluster/rpc/peer_s3_client.rs | 19 +- crates/ecstore/src/store/bucket.rs | 210 ++++++++++++++---- crates/ecstore/src/store/mod.rs | 24 +- .../src/generated/proto_gen/node_service.rs | 2 + crates/protos/src/node.proto | 1 + crates/storage-api/src/bucket.rs | 6 +- rustfs/src/storage/rpc/node_service.rs | 19 ++ rustfs/src/storage/rpc/node_service/bucket.rs | 25 ++- 11 files changed, 270 insertions(+), 81 deletions(-) create mode 100644 .github/assets/site-replication-bucket-delete-epoch.png diff --git a/.config/nextest.toml b/.config/nextest.toml index 06e69a29d..03529d03e 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -42,7 +42,7 @@ e2e-reliability = { max-threads = 1 } # --- default profile (local): serialize the flaky groups, never retry -------- [[profile.default.overrides]] -filter = 'package(rustfs-ecstore) & (test(concurrent_resend_same_part_commits_one_generation) | test(/^store::bucket::tests::bucket_delete_(mark_delete_marks|purge_removes|default_s3_delete)/))' +filter = 'package(rustfs-ecstore) & (test(concurrent_resend_same_part_commits_one_generation) | test(/^store::bucket::tests::bucket_delete_(mark_delete|purge_removes|default_s3_delete)/))' test-group = 'ecstore-serial-flaky' # Serialize the multipart crash-consistency scenarios (dist-2, backlog#1150): @@ -99,7 +99,7 @@ retries = 2 # QUARANTINE: OPEN backlog#937 — store::bucket::tests::bucket_delete_* race # make_bucket into InsufficientWriteQuorum via shared global state under load. [[profile.ci.overrides]] -filter = 'package(rustfs-ecstore) & test(/^store::bucket::tests::bucket_delete_(mark_delete_marks|purge_removes|default_s3_delete)/)' +filter = 'package(rustfs-ecstore) & test(/^store::bucket::tests::bucket_delete_(mark_delete|purge_removes|default_s3_delete)/)' test-group = 'ecstore-serial-flaky' retries = 2 diff --git a/.docker/test/site-replication/run-object-flow-check.sh b/.docker/test/site-replication/run-object-flow-check.sh index f351e2587..f96d69469 100755 --- a/.docker/test/site-replication/run-object-flow-check.sh +++ b/.docker/test/site-replication/run-object-flow-check.sh @@ -18,6 +18,7 @@ set -eu ACCESS_KEY="${RUSTFS_SITE_REPL_ACCESS_KEY:-rustfsadmin}" SECRET_KEY="${RUSTFS_SITE_REPL_SECRET_KEY:-rustfsadmin}" BUCKET="${RUSTFS_SITE_REPL_FLOW_BUCKET:-site-repl-flow-check}" +DELETE_BUCKET="${RUSTFS_SITE_REPL_DELETE_BUCKET:-site-repl-delete-$(date +%Y%m%d-%H%M%S)-$$}" PREFIX="${RUSTFS_SITE_REPL_FLOW_PREFIX:-flow-$(date +%Y%m%d-%H%M%S)}" WAIT_ATTEMPTS="${RUSTFS_SITE_REPL_WAIT_ATTEMPTS:-90}" WAIT_SLEEP_SECONDS="${RUSTFS_SITE_REPL_WAIT_SLEEP_SECONDS:-2}" @@ -85,17 +86,39 @@ wait_for_object() { wait_for_bucket() { site="$1" + bucket="${2:-$BUCKET}" attempt=1 while [ "$attempt" -le "$WAIT_ATTEMPTS" ]; do - if mc stat "$site/$BUCKET" >/dev/null 2>&1; then + if mc stat "$site/$bucket" >/dev/null 2>&1; then return 0 fi sleep "$WAIT_SLEEP_SECONDS" attempt=$((attempt + 1)) done - echo "bucket was not replicated in time: $site/$BUCKET" >&2 + echo "bucket was not replicated in time: $site/$bucket" >&2 + return 1 +} + +wait_for_bucket_delete() { + site="$1" + bucket="$2" + attempt=1 + + while [ "$attempt" -le "$WAIT_ATTEMPTS" ]; do + if result="$(mc stat --json "$site/$bucket" 2>&1)"; then + : + else + case "$result" in + *NoSuchBucket*) return 0 ;; + esac + fi + sleep "$WAIT_SLEEP_SECONDS" + attempt=$((attempt + 1)) + done + + echo "bucket deletion was not replicated in time: $site/$bucket" >&2 return 1 } @@ -186,6 +209,20 @@ EOF echo "verified replicated downloads for $object_name" done +echo "creating empty bucket for replicated delete check: $DELETE_BUCKET" +mc mb "site1/$DELETE_BUCKET" >/dev/null + +for site in site1 site2 site3; do + wait_for_bucket "$site" "$DELETE_BUCKET" +done + +echo "deleting empty bucket on site1: $DELETE_BUCKET" +mc rb "site1/$DELETE_BUCKET" >/dev/null + +for site in site1 site2 site3; do + wait_for_bucket_delete "$site" "$DELETE_BUCKET" +done + echo "site replication object flow check passed" echo "bucket: $BUCKET" echo "prefix: $PREFIX" diff --git a/.github/assets/site-replication-bucket-delete-epoch.png b/.github/assets/site-replication-bucket-delete-epoch.png new file mode 100644 index 0000000000000000000000000000000000000000..9ed91877973863d34f9e61cd73a9669334608a4a GIT binary patch literal 107742 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 literal 0 HcmV?d00001 diff --git a/crates/ecstore/src/cluster/rpc/peer_s3_client.rs b/crates/ecstore/src/cluster/rpc/peer_s3_client.rs index c16588362..3f4b5602b 100644 --- a/crates/ecstore/src/cluster/rpc/peer_s3_client.rs +++ b/crates/ecstore/src/cluster/rpc/peer_s3_client.rs @@ -23,7 +23,7 @@ use crate::disk::{DiskAPI, DiskStore, disk_store::get_max_timeout_duration}; use crate::runtime::instance::{InstanceContext, bootstrap_ctx}; use crate::runtime::sources as runtime_sources; use crate::storage_api_contracts::bucket::{BucketInfo, BucketOptions, DeleteBucketOptions, MakeBucketOptions}; -use crate::store::utils::is_reserved_or_invalid_bucket; +use crate::store::{has_xlmeta_files, utils::is_reserved_or_invalid_bucket}; use crate::{ disk::{ self, VolumeInfo, @@ -614,13 +614,24 @@ impl PeerS3Client for LocalPeerS3Client { return Err(Error::ErasureWriteQuorum); } + let force = if opts.force_if_empty && !opts.force { + for disk in local_disks.iter() { + if has_xlmeta_files(&disk.path().join(bucket)).await.map_err(Error::Io)? { + return Err(Error::VolumeNotEmpty); + } + } + true + } else { + opts.force + }; + let mut futures = Vec::with_capacity(local_disks.len()); for disk in local_disks.iter() { // Non-force delete refuses a non-empty bucket (VolumeNotEmpty), which // the recreate loop below turns into BucketNotEmpty; only an explicit // force delete removes recursively (backlog#799 B1). - futures.push(disk.delete_volume(bucket, opts.force)); + futures.push(disk.delete_volume(bucket, force)); } let results = join_all(futures).await; @@ -988,13 +999,15 @@ impl PeerS3Client for RemotePeerS3Client { .await } - async fn delete_bucket(&self, bucket: &str, _opts: &DeleteBucketOptions) -> Result<()> { + async fn delete_bucket(&self, bucket: &str, opts: &DeleteBucketOptions) -> Result<()> { self.execute_with_timeout( || async { + let options = serde_json::to_string(opts)?; let mut client = self.get_client().await?; let request = Request::new(DeleteBucketRequest { bucket: bucket.to_string(), + options, }); let response = client.delete_bucket(request).await?.into_inner(); if !response.success { diff --git a/crates/ecstore/src/store/bucket.rs b/crates/ecstore/src/store/bucket.rs index a2968b3b5..0e25ea824 100644 --- a/crates/ecstore/src/store/bucket.rs +++ b/crates/ecstore/src/store/bucket.rs @@ -40,16 +40,16 @@ fn validate_table_bucket_delete_allowed( Ok(()) } -async fn table_catalog_metadata_exists(ctx: &crate::runtime::instance::InstanceContext, bucket: &str) -> bool { +async fn table_catalog_metadata_exists(ctx: &crate::runtime::instance::InstanceContext, bucket: &str) -> Result { let local_disks = runtime_sources::local_disks_in(ctx).await; for disk in local_disks.iter() { let catalog_path = disk.path().join(bucket).join(BUCKET_TABLE_RESERVED_PREFIX); - if has_xlmeta_files(&catalog_path).await { - return true; + if has_xlmeta_files(&catalog_path).await? { + return Ok(true); } } - false + Ok(false) } async fn validate_table_bucket_delete_guard(ctx: &crate::runtime::instance::InstanceContext, bucket: &str) -> Result<()> { @@ -57,7 +57,7 @@ async fn validate_table_bucket_delete_guard(ctx: &crate::runtime::instance::Inst .await .is_ok_and(|metadata| metadata.table_bucket_enabled()); if table_bucket_enabled { - validate_table_bucket_delete_allowed(bucket, true, table_catalog_metadata_exists(ctx, bucket).await)?; + validate_table_bucket_delete_allowed(bucket, true, table_catalog_metadata_exists(ctx, bucket).await?)?; } Ok(()) @@ -257,49 +257,57 @@ impl ECStore { None }; - // Check bucket exists before deletion (per S3 API spec) - // If bucket doesn't exist, return NoSuchBucket error - if let Err(err) = self.peer_sys.get_bucket_info(bucket, &BucketOptions::default()).await { - // Convert DiskError to StorageError for comparison - let storage_err: StorageError = err.into(); - if is_err_bucket_not_found(&storage_err) { - return Err(StorageError::BucketNotFound(bucket.to_string())); - } - return Err(to_object_err(storage_err, vec![bucket])); - } - - validate_table_bucket_delete_guard(&self.ctx, bucket).await?; - let sr_mark_delete = opts.srdelete_op == SRBucketDeleteOp::MarkDelete; let sr_purge = opts.srdelete_op == SRBucketDeleteOp::Purge; - - // Check bucket is empty before deletion (per S3 API spec) - // If bucket is not empty (contains actual objects with xl.meta files) and force - // is not set, return BucketNotEmpty error. - // Note: Empty directories (left after object deletion) should NOT count as objects. - if !opts.force && !sr_mark_delete { - let local_disks = runtime_sources::local_disks_in(&self.ctx).await; - for disk in local_disks.iter() { - // Check if bucket directory contains any xl.meta files (actual objects) - // We recursively scan for xl.meta files to determine if bucket has objects - // Use the disk's root path to construct bucket path - let bucket_path = disk.path().join(bucket); - if has_xlmeta_files(&bucket_path).await { - return Err(StorageError::BucketNotEmpty(bucket.to_string())); + let sr_delete = sr_mark_delete || sr_purge; + let mut delete_opts = opts.clone(); + let bucket_exists = match self.peer_sys.get_bucket_info(bucket, &BucketOptions::default()).await { + Ok(_) => true, + Err(err) => { + let storage_err: StorageError = err.into(); + if is_err_strict_volume_not_found(&storage_err) && sr_delete { + false + } else if is_err_strict_volume_not_found(&storage_err) { + return Err(StorageError::BucketNotFound(bucket.to_string())); + } else { + return Err(to_object_err(storage_err, vec![bucket])); } } + }; + + if bucket_exists { + validate_table_bucket_delete_guard(&self.ctx, bucket).await?; + + // Check bucket is empty before deletion (per S3 API spec) + // If bucket is not empty (contains actual objects with xl.meta files) and force + // is not set, return BucketNotEmpty error. + // Note: Empty directories (left after object deletion) should NOT count as objects. + if !opts.force { + let local_disks = runtime_sources::local_disks_in(&self.ctx).await; + for disk in local_disks.iter() { + let bucket_path = disk.path().join(bucket); + if has_xlmeta_files(&bucket_path).await? { + return Err(StorageError::BucketNotEmpty(bucket.to_string())); + } + } + delete_opts.force_if_empty = true; + } + } + + if sr_delete && !bucket_exists { + delete_opts.force_if_empty = true; } if sr_mark_delete { self.mark_bucket_deleted(bucket).await?; - self.cleanup_deleted_bucket_metadata(bucket, false).await?; - return Ok(()); } - self.peer_sys - .delete_bucket(bucket, opts) - .await - .map_err(|e| to_object_err(e.into(), vec![bucket]))?; + if let Err(err) = self.peer_sys.delete_bucket(bucket, &delete_opts).await { + let storage_err = to_object_err(err.into(), vec![bucket]); + if !sr_delete || !is_err_strict_volume_not_found(&storage_err) { + return Err(storage_err); + } + } self.cleanup_deleted_bucket_metadata(bucket, sr_purge).await?; Ok(()) @@ -319,7 +327,7 @@ mod tests { use crate::object_api::{ObjectOptions, PutObjReader}; use crate::runtime::instance::InstanceContext; use crate::storage_api_contracts::{ - bucket::{BucketOperations as _, DeleteBucketOptions, MakeBucketOptions, SRBucketDeleteOp}, + bucket::{BucketOperations as _, BucketOptions, DeleteBucketOptions, MakeBucketOptions, SRBucketDeleteOp}, object::{ObjectIO as _, ObjectOperations as _}, }; use crate::store::{ECStore, init_local_disks_with_instance_ctx}; @@ -448,7 +456,10 @@ mod tests { async fn any_disk_has_object_metadata(disk_paths: &[PathBuf], bucket: &str) -> bool { for disk_path in disk_paths { - if super::has_xlmeta_files(&disk_path.join(bucket)).await { + if super::has_xlmeta_files(&disk_path.join(bucket)) + .await + .expect("object metadata scan should succeed") + { return true; } } @@ -508,12 +519,19 @@ mod tests { // serialize them so their assertions cannot observe each other's operations. #[tokio::test] #[serial] - async fn bucket_delete_mark_delete_marks_metadata_deleted_without_physical_object_delete() { + async fn bucket_delete_mark_delete_removes_empty_bucket_and_keeps_deleted_marker() { let (disk_paths, ecstore) = setup_bucket_delete_test_env().await; let bucket = format!("bucket-mark-delete-{}", Uuid::new_v4().simple()); - let object = "object.txt"; - create_bucket_with_object(&ecstore, &bucket, object).await; + ecstore + .make_bucket(&bucket, &MakeBucketOptions::default()) + .await + .expect("bucket should be created"); + for disk_path in &disk_paths { + tokio::fs::create_dir_all(disk_path.join(&bucket).join("empty-directory")) + .await + .expect("empty directory remnant should be created"); + } assert!(metadata_sys::get_in(&ecstore.ctx, &bucket).await.is_ok()); let generation_before_delete = ecstore.scanner_namespace_mutation_generation(); @@ -526,7 +544,7 @@ mod tests { }, ) .await - .expect("MarkDelete should not reject non-empty bucket data"); + .expect("MarkDelete should remove an empty bucket"); assert_eq!( ecstore.scanner_namespace_mutation_generation(), generation_before_delete.saturating_add(1), @@ -534,8 +552,8 @@ mod tests { ); assert!( - any_disk_has_object_metadata(&disk_paths, &bucket).await, - "MarkDelete must not physically remove object xl.meta data" + !any_disk_path_exists(&disk_paths, &bucket).await, + "MarkDelete should remove the bucket volume" ); assert!( any_disk_path_exists(&disk_paths, bucket_deleted_marker_volume(&bucket)).await, @@ -545,6 +563,79 @@ mod tests { metadata_sys::get_in(&ecstore.ctx, &bucket).await.is_err(), "deleted bucket metadata must be removed from the local cache" ); + let buckets = ecstore + .list_bucket(&BucketOptions::default()) + .await + .expect("bucket listing should succeed after MarkDelete"); + assert!(!buckets.iter().any(|info| info.name == bucket)); + ecstore + .delete_all(RUSTFS_META_BUCKET, &bucket_deleted_marker_prefix(&bucket)) + .await + .expect("deleted-bucket marker should be removed to simulate a partial failure"); + assert!(!any_disk_path_exists(&disk_paths, bucket_deleted_marker_volume(&bucket)).await); + ecstore + .delete_bucket( + &bucket, + &DeleteBucketOptions { + srdelete_op: SRBucketDeleteOp::MarkDelete, + ..Default::default() + }, + ) + .await + .expect("retried MarkDelete should recreate a missing tombstone"); + assert!(any_disk_path_exists(&disk_paths, bucket_deleted_marker_volume(&bucket)).await); + } + + #[tokio::test] + #[serial] + async fn bucket_delete_mark_delete_rejects_non_empty_bucket_without_force() { + let (disk_paths, ecstore) = setup_bucket_delete_test_env().await; + let bucket = format!("bucket-mark-delete-non-empty-{}", Uuid::new_v4().simple()); + + create_bucket_with_object(&ecstore, &bucket, "object.txt").await; + + let err = ecstore + .delete_bucket( + &bucket, + &DeleteBucketOptions { + srdelete_op: SRBucketDeleteOp::MarkDelete, + ..Default::default() + }, + ) + .await + .expect_err("MarkDelete should reject a non-empty bucket without force"); + + assert!(matches!(err, StorageError::BucketNotEmpty(name) if name == bucket)); + assert!(any_disk_has_object_metadata(&disk_paths, &bucket).await); + assert!(!any_disk_path_exists(&disk_paths, bucket_deleted_marker_volume(&bucket)).await); + } + + #[tokio::test] + #[serial] + async fn bucket_delete_mark_delete_rejects_hidden_object_paths_without_force() { + let (disk_paths, ecstore) = setup_bucket_delete_test_env().await; + let bucket = format!("bucket-mark-delete-hidden-{}", Uuid::new_v4().simple()); + + create_bucket_with_object(&ecstore, &bucket, ".well-known/acme-challenge").await; + let mut reader = PutObjReader::from_vec(b"delete bucket semantics".to_vec()); + ecstore + .put_object(&bucket, ".rustfs.sys/object", &mut reader, &ObjectOptions::default()) + .await + .expect("second hidden object should be written"); + + let err = ecstore + .delete_bucket( + &bucket, + &DeleteBucketOptions { + srdelete_op: SRBucketDeleteOp::MarkDelete, + ..Default::default() + }, + ) + .await + .expect_err("MarkDelete should reject a hidden object path without force"); + + assert!(matches!(err, StorageError::BucketNotEmpty(name) if name == bucket)); + assert!(any_disk_has_object_metadata(&disk_paths, &bucket).await); } #[tokio::test] @@ -557,7 +648,12 @@ mod tests { create_bucket_with_object(&ecstore, &bucket, object).await; write_bucket_metadata_marker(&disk_paths, &metadata_prefix).await; + ecstore + .mark_bucket_deleted(&bucket) + .await + .expect("deleted-bucket marker should be created"); assert!(any_disk_path_exists(&disk_paths, &metadata_prefix).await); + assert!(any_disk_path_exists(&disk_paths, bucket_deleted_marker_volume(&bucket)).await); let generation_before_delete = ecstore.scanner_namespace_mutation_generation(); ecstore @@ -582,10 +678,32 @@ mod tests { !any_disk_path_exists(&disk_paths, &metadata_prefix).await, "Purge should remove bucket metadata prefix" ); + assert!( + !any_disk_path_exists(&disk_paths, bucket_deleted_marker_volume(&bucket)).await, + "Purge should remove the deleted-bucket marker" + ); assert!( metadata_sys::get_in(&ecstore.ctx, &bucket).await.is_err(), "purged bucket metadata must be removed from the local cache" ); + write_bucket_metadata_marker(&disk_paths, &metadata_prefix).await; + ecstore + .mark_bucket_deleted(&bucket) + .await + .expect("stale deleted-bucket marker should be recreated"); + ecstore + .delete_bucket( + &bucket, + &DeleteBucketOptions { + force: true, + srdelete_op: SRBucketDeleteOp::Purge, + ..Default::default() + }, + ) + .await + .expect("retried Purge should remove stale metadata without a bucket volume"); + assert!(!any_disk_path_exists(&disk_paths, &metadata_prefix).await); + assert!(!any_disk_path_exists(&disk_paths, bucket_deleted_marker_volume(&bucket)).await); } #[tokio::test] diff --git a/crates/ecstore/src/store/mod.rs b/crates/ecstore/src/store/mod.rs index 90e851c17..4f8e8e7cb 100644 --- a/crates/ecstore/src/store/mod.rs +++ b/crates/ecstore/src/store/mod.rs @@ -40,8 +40,8 @@ use crate::disk::endpoint::{Endpoint, EndpointType}; use crate::disk::{DiskAPI, DiskInfo, DiskInfoOptions}; use crate::error::{Error, Result}; use crate::error::{ - StorageError, is_err_bucket_exists, is_err_bucket_not_found, is_err_invalid_upload_id, is_err_object_not_found, - is_err_read_quorum, is_err_version_not_found, to_object_err, + StorageError, is_err_bucket_exists, is_err_invalid_upload_id, is_err_object_not_found, is_err_read_quorum, + is_err_strict_volume_not_found, is_err_version_not_found, to_object_err, }; use crate::runtime::global::DISK_RESERVE_FRACTION; use crate::runtime::instance::InstanceContext; @@ -91,7 +91,7 @@ type WalkOptions = StorageWalkOptions bool>; /// Check if a directory contains any xl.meta files (indicating actual S3 objects) /// This is used to determine if a bucket is empty for deletion purposes. -async fn has_xlmeta_files(path: &std::path::Path) -> bool { +pub(crate) async fn has_xlmeta_files(path: &std::path::Path) -> std::io::Result { use crate::disk::STORAGE_FORMAT_FILE; use tokio::fs; @@ -100,33 +100,27 @@ async fn has_xlmeta_files(path: &std::path::Path) -> bool { while let Some(current_path) = stack.pop() { let mut entries = match fs::read_dir(¤t_path).await { Ok(entries) => entries, - Err(_) => continue, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => continue, + Err(err) => return Err(err), }; - while let Ok(Some(entry)) = entries.next_entry().await { + while let Some(entry) = entries.next_entry().await? { let file_name = entry.file_name(); let file_name_str = file_name.to_string_lossy(); - // Skip hidden files/directories (like .rustfs.sys) - if file_name_str.starts_with('.') { - continue; - } - // Check if this is an xl.meta file if file_name_str == STORAGE_FORMAT_FILE { - return true; + return Ok(true); } // If it's a directory, add to stack for further exploration - if let Ok(file_type) = entry.file_type().await - && file_type.is_dir() - { + if entry.file_type().await?.is_dir() { stack.push(entry.path()); } } } - false + Ok(false) } async fn enqueue_transition_after_write(result: Result, src: LcEventSrc) -> Result { diff --git a/crates/protos/src/generated/proto_gen/node_service.rs b/crates/protos/src/generated/proto_gen/node_service.rs index d22104b1d..0c3b8cb1d 100644 --- a/crates/protos/src/generated/proto_gen/node_service.rs +++ b/crates/protos/src/generated/proto_gen/node_service.rs @@ -83,6 +83,8 @@ pub struct GetBucketInfoResponse { pub struct DeleteBucketRequest { #[prost(string, tag = "1")] pub bucket: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub options: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DeleteBucketResponse { diff --git a/crates/protos/src/node.proto b/crates/protos/src/node.proto index 918f92c79..92b4e74a7 100644 --- a/crates/protos/src/node.proto +++ b/crates/protos/src/node.proto @@ -74,6 +74,7 @@ message GetBucketInfoResponse { message DeleteBucketRequest { string bucket = 1; + string options = 2; } message DeleteBucketResponse { diff --git a/crates/storage-api/src/bucket.rs b/crates/storage-api/src/bucket.rs index 1774fa8ad..d2e0411af 100644 --- a/crates/storage-api/src/bucket.rs +++ b/crates/storage-api/src/bucket.rs @@ -33,7 +33,7 @@ pub struct MakeBucketOptions { } /// Operation to perform on a bucket during site replication delete. -#[derive(Debug, Default, Clone, PartialEq)] +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub enum SRBucketDeleteOp { /// No operation. #[default] @@ -45,7 +45,7 @@ pub enum SRBucketDeleteOp { } /// Options for deleting a bucket. -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct DeleteBucketOptions { /// Skip acquiring namespace lock. pub no_lock: bool, @@ -53,6 +53,8 @@ pub struct DeleteBucketOptions { pub no_recreate: bool, /// Force deletion even if bucket is not empty. pub force: bool, + /// Force deletion only after the local peer verifies the bucket is empty. + pub force_if_empty: bool, /// Site replication delete operation. pub srdelete_op: SRBucketDeleteOp, } diff --git a/rustfs/src/storage/rpc/node_service.rs b/rustfs/src/storage/rpc/node_service.rs index 513745ef7..864fff455 100644 --- a/rustfs/src/storage/rpc/node_service.rs +++ b/rustfs/src/storage/rpc/node_service.rs @@ -2671,6 +2671,7 @@ mod tests { let request = Request::new(DeleteBucketRequest { bucket: "test-bucket".to_string(), + options: String::new(), }); let response = service.delete_bucket(request).await; @@ -2681,6 +2682,24 @@ mod tests { assert!(delete_response.success || delete_response.error.is_some()); } + #[tokio::test] + async fn test_delete_bucket_rejects_invalid_options() { + let service = create_test_node_service(); + + let request = Request::new(DeleteBucketRequest { + bucket: "test-bucket".to_string(), + options: "invalid json".to_string(), + }); + + let response = service + .delete_bucket(request) + .await + .expect("RPC response should be returned") + .into_inner(); + assert!(!response.success); + assert!(response.error.is_some()); + } + #[tokio::test] async fn test_read_all_invalid_disk() { let service = create_test_node_service(); diff --git a/rustfs/src/storage/rpc/node_service/bucket.rs b/rustfs/src/storage/rpc/node_service/bucket.rs index 3e7c76586..2d383f65b 100644 --- a/rustfs/src/storage/rpc/node_service/bucket.rs +++ b/rustfs/src/storage/rpc/node_service/bucket.rs @@ -103,17 +103,20 @@ impl NodeService { debug!("delete bucket"); let request = request.into_inner(); - match self - .local_peer - .delete_bucket( - &request.bucket, - &DeleteBucketOptions { - force: false, - ..Default::default() - }, - ) - .await - { + let options = if request.options.is_empty() { + DeleteBucketOptions::default() + } else { + match serde_json::from_str::(&request.options) { + Ok(options) => options, + Err(err) => { + return Ok(Response::new(DeleteBucketResponse { + success: false, + error: Some(DiskError::other(format!("decode DeleteBucketOptions failed: {err}")).into()), + })); + } + } + }; + match self.local_peer.delete_bucket(&request.bucket, &options).await { Ok(_) => Ok(Response::new(DeleteBucketResponse { success: true, error: None,