fix: report site replication metadata per site

Count only each site own valid bucket metadata, populate quota totals, and keep malformed fields from suppressing unrelated bucket statistics. Emit bounded diagnostics for invalid payloads.

Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
Feng Ruohang
2026-08-29 17:25:11 +08:00
parent 04d3d316d2
commit fb406fdc94
2 changed files with 288 additions and 55 deletions
+97 -55
View File
@@ -3406,80 +3406,116 @@ func (c *SiteReplicationSys) siteReplicationStatus(ctx context.Context, objAPI O
quotaCfgs := make([]*madmin.BucketQuota, numSites)
sseCfgSet := set.NewStringSet()
versionCfgSet := set.NewStringSet()
var tagCount, olockCfgCount, sseCfgCount, corsCfgCount, versionCfgCount int
validReplCfg := make([]bool, numSites)
validVersionCfg := make([]bool, numSites)
validQuotaCfg := make([]bool, numSites)
validTags := make([]bool, numSites)
validPolicies := make([]bool, numSites)
validObjectLockCfg := make([]bool, numSites)
validSSECfg := make([]bool, numSites)
validCorsCfg := make([]bool, numSites)
var tagCount, olockCfgCount, policyCount, quotaCfgCount, sseCfgCount, corsCfgCount, versionCfgCount int
for i, s := range slc {
logInvalid := func(configType string, err error) {
replLogOnceIf(ctx,
fmt.Errorf("unable to parse %s metadata for bucket %s from site %s: %w", configType, b, s.DeploymentID, err),
"site-replication-status-"+configType+"-"+b+"-"+s.DeploymentID)
}
if s.ReplicationConfig != nil {
cfgBytes, err := base64.StdEncoding.DecodeString(*s.ReplicationConfig)
if err != nil {
continue
if err == nil {
cfg, err := sreplication.ParseConfig(bytes.NewReader(cfgBytes))
if err == nil {
replCfgs[i] = cfg
validReplCfg[i] = true
} else {
logInvalid("replication", err)
}
} else {
logInvalid("replication", err)
}
cfg, err := sreplication.ParseConfig(bytes.NewReader(cfgBytes))
if err != nil {
continue
}
replCfgs[i] = cfg
}
if s.Versioning != nil {
configData, err := base64.StdEncoding.DecodeString(*s.Versioning)
if err != nil {
continue
}
versionCfgCount++
if !versionCfgSet.Contains(string(configData)) {
versionCfgSet.Add(string(configData))
if err == nil {
validVersionCfg[i] = true
versionCfgCount++
if !versionCfgSet.Contains(string(configData)) {
versionCfgSet.Add(string(configData))
}
} else {
logInvalid("versioning", err)
}
}
if s.QuotaConfig != nil {
cfgBytes, err := base64.StdEncoding.DecodeString(*s.QuotaConfig)
if err != nil {
continue
if err == nil {
cfg, err := parseBucketQuota(b, cfgBytes)
if err == nil {
if cfg != nil && *cfg != (madmin.BucketQuota{}) {
quotaCfgs[i] = cfg
validQuotaCfg[i] = true
quotaCfgCount++
}
} else {
logInvalid("quota", err)
}
} else {
logInvalid("quota", err)
}
cfg, err := parseBucketQuota(b, cfgBytes)
if err != nil {
continue
}
quotaCfgs[i] = cfg
}
if s.Tags != nil {
tagBytes, err := base64.StdEncoding.DecodeString(*s.Tags)
if err != nil {
continue
}
tagCount++
if !tagSet.Contains(string(tagBytes)) {
tagSet.Add(string(tagBytes))
if err == nil {
validTags[i] = true
tagCount++
if !tagSet.Contains(string(tagBytes)) {
tagSet.Add(string(tagBytes))
}
} else {
logInvalid("tags", err)
}
}
if len(s.Policy) > 0 {
plcy, err := policy.ParseBucketPolicyConfig(bytes.NewReader(s.Policy), b)
if err != nil {
continue
if err == nil {
policies[i] = plcy
validPolicies[i] = true
policyCount++
} else {
logInvalid("policy", err)
}
policies[i] = plcy
}
if s.ObjectLockConfig != nil {
configData, err := base64.StdEncoding.DecodeString(*s.ObjectLockConfig)
if err != nil {
continue
}
olockCfgCount++
if !olockConfigSet.Contains(string(configData)) {
olockConfigSet.Add(string(configData))
if err == nil {
validObjectLockCfg[i] = true
olockCfgCount++
if !olockConfigSet.Contains(string(configData)) {
olockConfigSet.Add(string(configData))
}
} else {
logInvalid("object-lock", err)
}
}
if s.SSEConfig != nil {
configData, err := base64.StdEncoding.DecodeString(*s.SSEConfig)
if err != nil {
continue
}
sseCfgCount++
if !sseCfgSet.Contains(string(configData)) {
sseCfgSet.Add(string(configData))
if err == nil {
validSSECfg[i] = true
sseCfgCount++
if !sseCfgSet.Contains(string(configData)) {
sseCfgSet.Add(string(configData))
}
} else {
logInvalid("sse", err)
}
}
if s.CorsConfig != nil {
if _, err := decodeCORSReplicationPayload(s.CorsConfig); err == nil {
validCorsCfg[i] = true
corsCfgCount++
} else {
logInvalid("cors", err)
}
}
ss, ok := info.StatsSummary[s.DeploymentID]
@@ -3491,24 +3527,27 @@ func (c *SiteReplicationSys) siteReplicationStatus(ctx context.Context, objAPI O
ss.ReplicatedBuckets++
}
ss.TotalBucketsCount++
if tagCount > 0 {
if validTags[i] {
ss.TotalTagsCount++
}
if olockCfgCount > 0 {
if validObjectLockCfg[i] {
ss.TotalLockConfigCount++
}
if sseCfgCount > 0 {
if validSSECfg[i] {
ss.TotalSSEConfigCount++
}
if s.CorsConfig != nil {
if validCorsCfg[i] {
ss.TotalCorsConfigCount++
}
if versionCfgCount > 0 {
if validVersionCfg[i] {
ss.TotalVersioningConfigCount++
}
if len(policies) > 0 {
if validPolicies[i] {
ss.TotalBucketPoliciesCount++
}
if validQuotaCfg[i] {
ss.TotalQuotaConfigCount++
}
info.StatsSummary[s.DeploymentID] = ss
}
tagMismatch := !isReplicated(tagCount, numSites, tagSet)
@@ -3542,13 +3581,13 @@ func (c *SiteReplicationSys) siteReplicationStatus(ctx context.Context, objAPI O
PolicyMismatch: policyMismatch,
ReplicationCfgMismatch: replCfgMismatch,
QuotaCfgMismatch: quotaCfgMismatch,
HasReplicationCfg: s.ReplicationConfig != nil,
HasTagsSet: s.Tags != nil,
HasOLockConfigSet: s.ObjectLockConfig != nil,
HasPolicySet: s.Policy != nil,
HasReplicationCfg: validReplCfg[i],
HasTagsSet: validTags[i],
HasOLockConfigSet: validObjectLockCfg[i],
HasPolicySet: validPolicies[i],
HasQuotaCfgSet: quotaCfgSet,
HasSSECfgSet: s.SSEConfig != nil,
HasCorsCfgSet: s.CorsConfig != nil,
HasSSECfgSet: validSSECfg[i],
HasCorsCfgSet: validCorsCfg[i],
}
var m srBucketMetaInfo
if len(bucketStats[s.Bucket]) > dIdx {
@@ -3574,12 +3613,15 @@ func (c *SiteReplicationSys) siteReplicationStatus(ctx context.Context, objAPI O
if !corsCfgMismatch && corsCfgCount == numSites {
sum.ReplicatedCorsConfig++
}
if !policyMismatch && len(policies) == numSites {
if !policyMismatch && policyCount == numSites {
sum.ReplicatedBucketPolicies++
}
if !tagMismatch && tagCount == numSites {
sum.ReplicatedTags++
}
if !quotaCfgMismatch && quotaCfgCount == numSites {
sum.ReplicatedQuotaConfig++
}
info.StatsSummary[s.DeploymentID] = sum
}
}