Add support for multi site replication (#12880)

This commit is contained in:
Poorna Krishnamoorthy
2021-09-18 16:31:35 -04:00
committed by GitHub
parent 0b8c5a6872
commit c4373ef290
52 changed files with 6492 additions and 1230 deletions
+68 -44
View File
@@ -25,40 +25,14 @@ import (
"strings"
)
// StatusType of Replication for x-amz-replication-status header
type StatusType string
const (
// Pending - replication is pending.
Pending StatusType = "PENDING"
// Completed - replication completed ok.
Completed StatusType = "COMPLETED"
// Failed - replication failed.
Failed StatusType = "FAILED"
// Replica - this is a replica.
Replica StatusType = "REPLICA"
)
// String returns string representation of status
func (s StatusType) String() string {
return string(s)
}
// Empty returns true if this status is not set
func (s StatusType) Empty() bool {
return string(s) == ""
}
var (
errReplicationTooManyRules = Errorf("Replication configuration allows a maximum of 1000 rules")
errReplicationNoRule = Errorf("Replication configuration should have at least one rule")
errReplicationUniquePriority = Errorf("Replication configuration has duplicate priority")
errReplicationDestinationMismatch = Errorf("The destination bucket must be same for all rules")
errRoleArnMissing = Errorf("Missing required parameter `Role` in ReplicationConfiguration")
errInvalidSourceSelectionCriteria = Errorf("Invalid ReplicaModification status")
errReplicationTooManyRules = Errorf("Replication configuration allows a maximum of 1000 rules")
errReplicationNoRule = Errorf("Replication configuration should have at least one rule")
errReplicationUniquePriority = Errorf("Replication configuration has duplicate priority")
errRoleArnMissingLegacy = Errorf("Missing required parameter `Role` in ReplicationConfiguration")
errDestinationArnMissing = Errorf("Missing required parameter `Destination` in Replication rule")
errInvalidSourceSelectionCriteria = Errorf("Invalid ReplicaModification status")
errRoleArnPresentForMultipleTargets = Errorf("`Role` should be empty in ReplicationConfiguration for multiple targets")
)
// Config - replication configuration specified in
@@ -102,18 +76,14 @@ func (c Config) Validate(bucket string, sameTarget bool) error {
if len(c.Rules) == 0 {
return errReplicationNoRule
}
if c.RoleArn == "" {
return errRoleArnMissing
}
// Validate all the rules in the replication config
targetMap := make(map[string]struct{})
priorityMap := make(map[string]struct{})
var legacyArn bool
for _, r := range c.Rules {
if len(targetMap) == 0 {
targetMap[r.Destination.Bucket] = struct{}{}
}
if _, ok := targetMap[r.Destination.Bucket]; !ok {
return errReplicationDestinationMismatch
targetMap[r.Destination.Bucket] = struct{}{}
}
if err := r.Validate(bucket, sameTarget); err != nil {
return err
@@ -122,6 +92,22 @@ func (c Config) Validate(bucket string, sameTarget bool) error {
return errReplicationUniquePriority
}
priorityMap[strconv.Itoa(r.Priority)] = struct{}{}
if r.Destination.LegacyArn() {
legacyArn = true
}
if c.RoleArn == "" && !r.Destination.TargetArn() {
return errDestinationArnMissing
}
}
// disallow combining old replication configuration which used RoleArn as target ARN with multiple
// destination replication
if c.RoleArn != "" && len(targetMap) > 1 {
return errRoleArnPresentForMultipleTargets
}
// validate RoleArn if destination used legacy ARN format.
if c.RoleArn == "" && legacyArn {
return errRoleArnMissingLegacy
}
return nil
}
@@ -137,6 +123,7 @@ const (
MetadataReplicationType
HealReplicationType
ExistingObjectReplicationType
ResyncReplicationType
)
// Valid returns true if replication type is set
@@ -150,18 +137,18 @@ type ObjectOpts struct {
Name string
UserTags string
VersionID string
IsLatest bool
DeleteMarker bool
SSEC bool
OpType Type
Replica bool
ExistingObject bool
TargetArn string
}
// FilterActionableRules returns the rules actions that need to be executed
// after evaluating prefix/tag filtering
func (c Config) FilterActionableRules(obj ObjectOpts) []Rule {
if obj.Name == "" {
if obj.Name == "" && obj.OpType != ResyncReplicationType {
return nil
}
var rules []Rule
@@ -169,6 +156,18 @@ func (c Config) FilterActionableRules(obj ObjectOpts) []Rule {
if rule.Status == Disabled {
continue
}
if obj.TargetArn != "" && rule.Destination.ARN != obj.TargetArn && c.RoleArn != obj.TargetArn {
continue
}
// Ignore other object level and prefix filters for resyncing target
if obj.OpType == ResyncReplicationType {
rules = append(rules, rule)
continue
}
if obj.ExistingObject && rule.ExistingObjectReplication.Status == Disabled {
continue
}
if !strings.HasPrefix(obj.Name, rule.Prefix()) {
continue
}
@@ -177,8 +176,9 @@ func (c Config) FilterActionableRules(obj ObjectOpts) []Rule {
}
}
sort.Slice(rules[:], func(i, j int) bool {
return rules[i].Priority > rules[j].Priority
return rules[i].Priority > rules[j].Priority && rules[i].Destination.String() == rules[j].Destination.String()
})
return rules
}
@@ -205,7 +205,7 @@ func (c Config) Replicate(obj ObjectOpts) bool {
if obj.OpType == DeleteReplicationType {
switch {
case obj.VersionID != "":
// // check MinIO extension for versioned deletes
// check MinIO extension for versioned deletes
return rule.DeleteReplication.Status == Enabled
default:
return rule.DeleteMarkerReplication.Status == Enabled
@@ -243,3 +243,27 @@ func (c Config) HasActiveRules(prefix string, recursive bool) bool {
}
return false
}
// FilterTargetArns returns a slice of distinct target arns in the config
func (c Config) FilterTargetArns(obj ObjectOpts) []string {
var arns []string
tgtsMap := make(map[string]struct{})
rules := c.FilterActionableRules(obj)
for _, rule := range rules {
if rule.Status == Disabled {
continue
}
if c.RoleArn != "" {
arns = append(arns, c.RoleArn) // use legacy RoleArn if present
return arns
}
if _, ok := tgtsMap[rule.Destination.ARN]; !ok {
tgtsMap[rule.Destination.ARN] = struct{}{}
}
}
for k := range tgtsMap {
arns = append(arns, k)
}
return arns
}