feat(admin): expose versioned replication capabilities (#5631)

* feat(admin): expose replication capabilities

* fix(admin): route replication capabilities through facades
This commit is contained in:
cxymds
2026-08-02 22:54:38 +08:00
committed by GitHub
parent 52c70738eb
commit 114b2420a2
9 changed files with 274 additions and 16 deletions
+75
View File
@@ -26,6 +26,53 @@ use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use uuid::Uuid;
pub const REPLICATION_CAPABILITY_CONTRACT_VERSION: u32 = 1;
pub const REPLICATION_WRITABLE_FIELDS: &[&str] = &[
"Role",
"Rule.ID",
"Rule.Status",
"Rule.Priority",
"Rule.Filter.Prefix",
"Rule.Filter.Tag",
"Rule.Filter.And",
"Rule.Destination.Bucket",
"Rule.ExistingObjectReplication.Status",
"Rule.DeleteMarkerReplication.Status",
"Rule.DeleteReplication.Status",
"Rule.SourceSelectionCriteria.ReplicaModifications.Status",
];
pub const REPLICATION_READ_ONLY_HISTORICAL_FIELDS: &[&str] = &[
"SourceSelectionCriteria.SseKmsEncryptedObjects",
"Destination.EncryptionConfiguration",
"Destination.Metrics",
"Destination.ReplicationTime",
];
pub const REMOTE_TARGET_CAPABILITY_CONTRACT_VERSION: u32 = 1;
pub const REMOTE_TARGET_WRITABLE_FIELDS: &[&str] = &[
"sourcebucket",
"endpoint",
"credentials.accessKey",
"credentials.secretKey",
"targetbucket",
"secure",
"path",
"api",
"arn",
"type",
"region",
"bandwidth",
"replicationSync",
"storage_class",
"skipTlsVerify",
"caCertPem",
];
pub const REMOTE_TARGET_UNSUPPORTED_FIELDS: &[&str] = &["disableProxy", "healthCheckDuration", "edge", "edgeSyncBeforeExpiry"];
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ObjectOpts {
pub name: String,
@@ -920,6 +967,34 @@ mod tests {
assert_eq!(unsupported_replication_config_field(&config), None);
}
#[test]
fn capability_fields_match_validator_rejections() {
let rejected_fields = [
"SourceSelectionCriteria.SseKmsEncryptedObjects",
"Destination.EncryptionConfiguration",
"Destination.Metrics",
"Destination.ReplicationTime",
];
for field in rejected_fields {
assert!(
REPLICATION_READ_ONLY_HISTORICAL_FIELDS.contains(&field),
"rejected field {field} must be advertised as readable historical data"
);
assert!(
!REPLICATION_WRITABLE_FIELDS.contains(&field),
"rejected field {field} must not be advertised as writable"
);
}
for field in REPLICATION_WRITABLE_FIELDS {
assert!(
!REPLICATION_READ_ONLY_HISTORICAL_FIELDS.contains(field),
"field {field} cannot be both writable and historical-only"
);
}
}
#[test]
fn invalid_replication_status_fields_are_reported_before_persistence() {
let arn = "arn:rustfs:replication:us-east-1:target:bucket";
+3 -1
View File
@@ -29,7 +29,9 @@ mod storage_api;
pub mod tagging;
pub use config::{
ObjectOpts, ReplicationConfigurationExt, ReplicationTargetValidationError, active_replication_rule_destination_arns,
ObjectOpts, REMOTE_TARGET_CAPABILITY_CONTRACT_VERSION, REMOTE_TARGET_UNSUPPORTED_FIELDS, REMOTE_TARGET_WRITABLE_FIELDS,
REPLICATION_CAPABILITY_CONTRACT_VERSION, REPLICATION_READ_ONLY_HISTORICAL_FIELDS, REPLICATION_WRITABLE_FIELDS,
ReplicationConfigurationExt, ReplicationTargetValidationError, active_replication_rule_destination_arns,
invalid_replication_config_status_field, replication_target_arns, should_remove_replication_target,
unsupported_replication_config_field, validate_replication_config_target_arns,
};