diff --git a/weed/s3api/auth_credentials_subscribe.go b/weed/s3api/auth_credentials_subscribe.go index 52e548a68..4d6b0fd19 100644 --- a/weed/s3api/auth_credentials_subscribe.go +++ b/weed/s3api/auth_credentials_subscribe.go @@ -1,7 +1,6 @@ package s3api import ( - "encoding/xml" "time" "github.com/seaweedfs/seaweedfs/weed/filer" @@ -131,14 +130,9 @@ func (s3a *S3ApiServer) updateBucketConfigCacheFromEntry(entry *filer_pb.Entry) config.Owner = string(owner) } // Parse Object Lock configuration if present - if objectLockConfigXML, exists := entry.Extended[s3_constants.ExtObjectLockConfigKey]; exists { - var objectLockConfig ObjectLockConfiguration - if err := xml.Unmarshal(objectLockConfigXML, &objectLockConfig); err != nil { - glog.Errorf("updateBucketConfigCacheFromEntry: failed to parse Object Lock configuration for bucket %s: %v", bucket, err) - } else { - config.ObjectLockConfig = &objectLockConfig - glog.V(2).Infof("updateBucketConfigCacheFromEntry: cached Object Lock configuration for bucket %s", bucket) - } + if objectLockConfig, found := LoadObjectLockConfigurationFromExtended(entry); found { + config.ObjectLockConfig = objectLockConfig + glog.V(2).Infof("updateBucketConfigCacheFromEntry: cached Object Lock configuration for bucket %s", bucket) } } diff --git a/weed/s3api/object_lock_utils.go b/weed/s3api/object_lock_utils.go index 6d2df7854..771004e24 100644 --- a/weed/s3api/object_lock_utils.go +++ b/weed/s3api/object_lock_utils.go @@ -79,20 +79,6 @@ func ObjectLockConfigurationToXML(config *ObjectLockConfiguration) ([]byte, erro return xml.Marshal(config) } -// XMLToObjectLockConfiguration parses XML bytes to ObjectLockConfiguration -func XMLToObjectLockConfiguration(xmlData []byte) (*ObjectLockConfiguration, error) { - if len(xmlData) == 0 { - return nil, fmt.Errorf("XML data is empty") - } - - var config ObjectLockConfiguration - if err := xml.Unmarshal(xmlData, &config); err != nil { - return nil, fmt.Errorf("failed to parse Object Lock configuration XML: %w", err) - } - - return &config, nil -} - // StoreObjectLockConfigurationInExtended stores Object Lock configuration in entry extended attributes func StoreObjectLockConfigurationInExtended(entry *filer_pb.Entry, config *ObjectLockConfiguration) error { if entry.Extended == nil { @@ -102,19 +88,39 @@ func StoreObjectLockConfigurationInExtended(entry *filer_pb.Entry, config *Objec if config == nil { // Remove Object Lock configuration delete(entry.Extended, s3_constants.ExtObjectLockEnabledKey) - delete(entry.Extended, s3_constants.ExtObjectLockConfigKey) + delete(entry.Extended, s3_constants.ExtObjectLockDefaultModeKey) + delete(entry.Extended, s3_constants.ExtObjectLockDefaultDaysKey) + delete(entry.Extended, s3_constants.ExtObjectLockDefaultYearsKey) return nil } // Store the enabled flag entry.Extended[s3_constants.ExtObjectLockEnabledKey] = []byte(config.ObjectLockEnabled) - // Store the full XML configuration - configXML, err := ObjectLockConfigurationToXML(config) - if err != nil { - return fmt.Errorf("failed to marshal Object Lock configuration: %w", err) + // Store default retention configuration if present + if config.Rule != nil && config.Rule.DefaultRetention != nil { + defaultRetention := config.Rule.DefaultRetention + + // Store mode + if defaultRetention.Mode != "" { + entry.Extended[s3_constants.ExtObjectLockDefaultModeKey] = []byte(defaultRetention.Mode) + } + + // Store days + if defaultRetention.Days > 0 { + entry.Extended[s3_constants.ExtObjectLockDefaultDaysKey] = []byte(strconv.Itoa(defaultRetention.Days)) + } + + // Store years + if defaultRetention.Years > 0 { + entry.Extended[s3_constants.ExtObjectLockDefaultYearsKey] = []byte(strconv.Itoa(defaultRetention.Years)) + } + } else { + // Remove default retention if not present + delete(entry.Extended, s3_constants.ExtObjectLockDefaultModeKey) + delete(entry.Extended, s3_constants.ExtObjectLockDefaultDaysKey) + delete(entry.Extended, s3_constants.ExtObjectLockDefaultYearsKey) } - entry.Extended[s3_constants.ExtObjectLockConfigKey] = configXML return nil } @@ -136,17 +142,41 @@ func LoadObjectLockConfigurationFromExtended(entry *filer_pb.Entry) (*ObjectLock return nil, false } - // Try to load full XML configuration - if configXML, exists := entry.Extended[s3_constants.ExtObjectLockConfigKey]; exists { - if config, err := XMLToObjectLockConfiguration(configXML); err == nil { - return config, true + // Create basic configuration + config := &ObjectLockConfiguration{ + ObjectLockEnabled: s3_constants.ObjectLockEnabled, + } + + // Load default retention configuration if present + if modeBytes, exists := entry.Extended[s3_constants.ExtObjectLockDefaultModeKey]; exists { + mode := string(modeBytes) + + // Parse days and years + var days, years int + if daysBytes, exists := entry.Extended[s3_constants.ExtObjectLockDefaultDaysKey]; exists { + if parsed, err := strconv.Atoi(string(daysBytes)); err == nil { + days = parsed + } + } + if yearsBytes, exists := entry.Extended[s3_constants.ExtObjectLockDefaultYearsKey]; exists { + if parsed, err := strconv.Atoi(string(yearsBytes)); err == nil { + years = parsed + } + } + + // Create rule if we have a mode and at least days or years + if mode != "" && (days > 0 || years > 0) { + config.Rule = &ObjectLockRule{ + DefaultRetention: &DefaultRetention{ + Mode: mode, + Days: days, + Years: years, + }, + } } } - // Fallback: create minimal configuration for enabled Object Lock - return &ObjectLockConfiguration{ - ObjectLockEnabled: s3_constants.ObjectLockEnabled, - }, true + return config, true } // ExtractObjectLockInfoFromConfig extracts basic Object Lock information from configuration diff --git a/weed/s3api/s3_constants/extend_key.go b/weed/s3api/s3_constants/extend_key.go index edfa4fe1d..f0f223a45 100644 --- a/weed/s3api/s3_constants/extend_key.go +++ b/weed/s3api/s3_constants/extend_key.go @@ -20,7 +20,11 @@ const ( ExtRetentionUntilDateKey = "Seaweed-X-Amz-Retention-Until-Date" ExtLegalHoldKey = "Seaweed-X-Amz-Legal-Hold" ExtObjectLockEnabledKey = "Seaweed-X-Amz-Object-Lock-Enabled" - ExtObjectLockConfigKey = "Seaweed-X-Amz-Object-Lock-Config" + + // Object Lock Bucket Configuration (individual components, not XML) + ExtObjectLockDefaultModeKey = "Lock-Default-Mode" + ExtObjectLockDefaultDaysKey = "Lock-Default-Days" + ExtObjectLockDefaultYearsKey = "Lock-Default-Years" ) // Object Lock and Retention Constants diff --git a/weed/s3api/s3api_bucket_config.go b/weed/s3api/s3api_bucket_config.go index 1c2bcbd98..725ee3596 100644 --- a/weed/s3api/s3api_bucket_config.go +++ b/weed/s3api/s3api_bucket_config.go @@ -2,7 +2,6 @@ package s3api import ( "encoding/json" - "encoding/xml" "fmt" "path/filepath" "strings" @@ -128,14 +127,9 @@ func (s3a *S3ApiServer) getBucketConfig(bucket string) (*BucketConfig, s3err.Err config.Owner = string(owner) } // Parse Object Lock configuration if present - if objectLockConfigXML, exists := bucketEntry.Extended[s3_constants.ExtObjectLockConfigKey]; exists { - var objectLockConfig ObjectLockConfiguration - if err := xml.Unmarshal(objectLockConfigXML, &objectLockConfig); err != nil { - glog.Errorf("getBucketConfig: failed to parse Object Lock configuration for bucket %s: %v", bucket, err) - } else { - config.ObjectLockConfig = &objectLockConfig - glog.V(2).Infof("getBucketConfig: cached Object Lock configuration for bucket %s", bucket) - } + if objectLockConfig, found := LoadObjectLockConfigurationFromExtended(bucketEntry); found { + config.ObjectLockConfig = objectLockConfig + glog.V(2).Infof("getBucketConfig: cached Object Lock configuration for bucket %s", bucket) } } @@ -189,19 +183,12 @@ func (s3a *S3ApiServer) updateBucketConfig(bucket string, updateFn func(*BucketC if config.Owner != "" { config.Entry.Extended[s3_constants.ExtAmzOwnerKey] = []byte(config.Owner) } - // Update Object Lock configuration in extended attributes + // Update Object Lock configuration if config.ObjectLockConfig != nil { - configXML, err := xml.Marshal(config.ObjectLockConfig) - if err != nil { - glog.Errorf("updateBucketConfig: failed to marshal Object Lock configuration for bucket %s: %v", bucket, err) + if err := StoreObjectLockConfigurationInExtended(config.Entry, config.ObjectLockConfig); err != nil { + glog.Errorf("updateBucketConfig: failed to store Object Lock configuration for bucket %s: %v", bucket, err) return s3err.ErrInternalError } - config.Entry.Extended[s3_constants.ExtObjectLockConfigKey] = configXML - - // Also set the boolean flag for backward compatibility - if config.ObjectLockConfig.ObjectLockEnabled != "" { - config.Entry.Extended[s3_constants.ExtObjectLockEnabledKey] = []byte(config.ObjectLockConfig.ObjectLockEnabled) - } } // Save to filer