mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-29 08:27:06 +00:00
refactor(replication): move app decisions into crate (#4191)
This commit is contained in:
@@ -105,8 +105,7 @@ use s3s::dto::{
|
||||
PutBucketNotificationConfigurationOutput, PutBucketPolicyInput, PutBucketPolicyOutput, PutBucketReplicationInput,
|
||||
PutBucketReplicationOutput, PutBucketTaggingInput, PutBucketTaggingOutput, PutBucketVersioningInput,
|
||||
PutBucketVersioningOutput, PutPublicAccessBlockInput, PutPublicAccessBlockOutput, ReplicationConfiguration,
|
||||
ReplicationRuleStatus, ServerSideEncryption, Tagging, Timestamp, UserMetadataCollection, UserMetadataEntry,
|
||||
VersioningConfiguration,
|
||||
ServerSideEncryption, Tagging, Timestamp, UserMetadataCollection, UserMetadataEntry, VersioningConfiguration,
|
||||
};
|
||||
use s3s::region::Region;
|
||||
use s3s::xml;
|
||||
@@ -246,58 +245,25 @@ fn notify_bucket_metadata_reload(
|
||||
});
|
||||
}
|
||||
|
||||
fn active_replication_rule_destination_arns(config: &ReplicationConfiguration) -> HashSet<String> {
|
||||
let mut arns = HashSet::new();
|
||||
|
||||
for rule in &config.rules {
|
||||
if rule.status == ReplicationRuleStatus::from_static(ReplicationRuleStatus::DISABLED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let arn = rule.destination.bucket.trim();
|
||||
if !arn.is_empty() {
|
||||
arns.insert(arn.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
arns
|
||||
}
|
||||
|
||||
fn replication_target_arns(config: &ReplicationConfiguration) -> HashSet<String> {
|
||||
let role = config.role.trim();
|
||||
if !role.is_empty() {
|
||||
let mut arns = HashSet::new();
|
||||
arns.insert(role.to_string());
|
||||
return arns;
|
||||
}
|
||||
|
||||
active_replication_rule_destination_arns(config)
|
||||
}
|
||||
|
||||
fn validate_replication_config_targets(targets: &BucketTargets, config: &ReplicationConfiguration) -> S3Result<()> {
|
||||
let configured_arns = targets
|
||||
.targets
|
||||
.iter()
|
||||
.filter(|target| target.target_type == BucketTargetType::ReplicationService)
|
||||
.map(|target| target.arn.as_str())
|
||||
.collect::<HashSet<_>>();
|
||||
.map(|target| target.arn.as_str());
|
||||
|
||||
let role = config.role.trim();
|
||||
let destination_arns = active_replication_rule_destination_arns(config);
|
||||
if !role.is_empty() && destination_arns.len() > 1 {
|
||||
return Err(s3_error!(
|
||||
InvalidRequest,
|
||||
"replication config with Role cannot define multiple destination targets"
|
||||
));
|
||||
}
|
||||
|
||||
for configured_arn in replication_target_arns(config) {
|
||||
if !configured_arns.contains(configured_arn.as_str()) {
|
||||
return Err(s3_error!(InvalidRequest, "replication config has a stale target"));
|
||||
match rustfs_replication::validate_replication_config_target_arns(configured_arns, config) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) => {
|
||||
let message = match err {
|
||||
rustfs_replication::ReplicationTargetValidationError::RoleWithMultipleDestinations => {
|
||||
"replication config with Role cannot define multiple destination targets"
|
||||
}
|
||||
rustfs_replication::ReplicationTargetValidationError::StaleTarget => "replication config has a stale target",
|
||||
};
|
||||
Err(S3Error::with_message(S3ErrorCode::InvalidRequest, message.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn validate_bucket_replication_update(bucket: &str, config: &ReplicationConfiguration) -> S3Result<()> {
|
||||
@@ -324,7 +290,7 @@ async fn replication_targets_without_config_targets(
|
||||
bucket: &str,
|
||||
config: &ReplicationConfiguration,
|
||||
) -> S3Result<Option<(BucketTargets, usize)>> {
|
||||
let target_arns = replication_target_arns(config);
|
||||
let target_arns = rustfs_replication::replication_target_arns(config);
|
||||
if target_arns.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -349,7 +315,11 @@ async fn replication_targets_without_config_targets(
|
||||
fn remove_replication_targets_from_config_targets(targets: &mut BucketTargets, target_arns: &HashSet<String>) -> usize {
|
||||
let original_len = targets.targets.len();
|
||||
targets.targets.retain(|target| {
|
||||
target.target_type != BucketTargetType::ReplicationService || !target_arns.contains(target.arn.as_str())
|
||||
!rustfs_replication::should_remove_replication_target(
|
||||
target.arn.as_str(),
|
||||
target.target_type == BucketTargetType::ReplicationService,
|
||||
target_arns,
|
||||
)
|
||||
});
|
||||
|
||||
original_len - targets.targets.len()
|
||||
@@ -2291,6 +2261,7 @@ impl DefaultBucketUsecase {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use http::{Extensions, HeaderMap, Method, Uri};
|
||||
use s3s::dto::ReplicationRuleStatus;
|
||||
use s3s::dto::{
|
||||
BucketVersioningStatus, CORSConfiguration, Destination, ExcludedPrefix, FilterRule, FilterRuleName, LifecycleExpiration,
|
||||
NoncurrentVersionTransition, PublicAccessBlockConfiguration, QueueConfiguration, ReplicationRule, S3KeyFilter,
|
||||
@@ -2374,7 +2345,7 @@ mod tests {
|
||||
rules: vec![replication_rule_for_target(destination)],
|
||||
};
|
||||
|
||||
let arns = replication_target_arns(&config);
|
||||
let arns = rustfs_replication::replication_target_arns(&config);
|
||||
|
||||
assert!(arns.contains(role));
|
||||
assert!(!arns.contains(destination));
|
||||
@@ -2388,7 +2359,7 @@ mod tests {
|
||||
rules: vec![replication_rule_for_target(destination)],
|
||||
};
|
||||
|
||||
let arns = replication_target_arns(&config);
|
||||
let arns = rustfs_replication::replication_target_arns(&config);
|
||||
|
||||
assert!(arns.contains(destination));
|
||||
}
|
||||
|
||||
@@ -610,7 +610,6 @@ pub(crate) mod bucket {
|
||||
|
||||
pub(crate) type DeletedObjectReplicationInfo =
|
||||
crate::storage::storage_api::ecstore_bucket::replication::DeletedObjectReplicationInfo;
|
||||
type ObjectOpts = crate::storage::storage_api::ecstore_bucket::replication::ObjectOpts;
|
||||
type ReplicationObjectBridge = crate::storage::storage_api::ecstore_bucket::replication::ReplicationObjectBridge;
|
||||
pub(crate) type ReplicateDecision = rustfs_replication::ReplicateDecision;
|
||||
|
||||
@@ -660,51 +659,14 @@ pub(crate) mod bucket {
|
||||
version_id: Option<Uuid>,
|
||||
replica: bool,
|
||||
) -> Option<rustfs_replication::ReplicationState> {
|
||||
let opts = ObjectOpts {
|
||||
let source = rustfs_replication::ReplicationDeleteStateSource {
|
||||
name: obj_info.name.clone(),
|
||||
user_tags: (*obj_info.user_tags).clone(),
|
||||
version_id,
|
||||
delete_marker: obj_info.delete_marker,
|
||||
op_type: rustfs_replication::ReplicationType::Delete,
|
||||
replica,
|
||||
..Default::default()
|
||||
};
|
||||
let target_arns =
|
||||
crate::storage::storage_api::ecstore_bucket::replication::ReplicationConfigurationExt::filter_target_arns(
|
||||
config, &opts,
|
||||
);
|
||||
if target_arns.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut decision = ReplicateDecision::new();
|
||||
for target_arn in target_arns {
|
||||
let mut target_opts = opts.clone();
|
||||
target_opts.target_arn = target_arn.clone();
|
||||
let replicate = crate::storage::storage_api::ecstore_bucket::replication::ReplicationConfigurationExt::replicate(
|
||||
config,
|
||||
&target_opts,
|
||||
);
|
||||
decision.set(rustfs_replication::ReplicateTargetDecision::new(target_arn, replicate, false));
|
||||
}
|
||||
if !decision.replicate_any() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let pending_status = decision.pending_status();
|
||||
let mut state = rustfs_replication::ReplicationState {
|
||||
replicate_decision_str: decision.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
if version_id.is_some() {
|
||||
state.version_purge_status_internal = pending_status.clone();
|
||||
state.purge_targets =
|
||||
rustfs_replication::version_purge_statuses_map(pending_status.as_deref().unwrap_or_default());
|
||||
} else {
|
||||
state.replication_status_internal = pending_status.clone();
|
||||
state.targets = rustfs_replication::replication_statuses_map(pending_status.as_deref().unwrap_or_default());
|
||||
}
|
||||
Some(state)
|
||||
rustfs_replication::delete_replication_state_from_config(config, &source)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user