Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add header for lifecycle config expiry to ignore replication #1999

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions api-bucket-lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,30 +41,36 @@ func (c *Client) SetBucketLifecycle(ctx context.Context, bucketName string, conf
if config.Empty() {
return c.removeBucketLifecycle(ctx, bucketName)
}

expAfterRepl := config.ExpireAfterReplication
config.ExpireAfterReplication = ""
buf, err := xml.Marshal(config)
if err != nil {
return err
}

// Save the updated lifecycle.
return c.putBucketLifecycle(ctx, bucketName, buf)
return c.putBucketLifecycle(ctx, bucketName, buf, expAfterRepl)
}

// Saves a new bucket lifecycle.
func (c *Client) putBucketLifecycle(ctx context.Context, bucketName string, buf []byte) error {
func (c *Client) putBucketLifecycle(ctx context.Context, bucketName string, buf []byte, expAfterRepl string) error {
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
urlValues.Set("lifecycle", "")

var cheaders http.Header
if expAfterRepl != "" {
cheaders = make(http.Header)
cheaders.Set(minioLifecycleExpiryAfterReplication, expAfterRepl)
}
// Content-length is mandatory for put lifecycle request
reqMetadata := requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentBody: bytes.NewReader(buf),
contentLength: int64(len(buf)),
contentMD5Base64: sumMD5Base64(buf),
customHeader: cheaders,
}

// Execute PUT to upload a new bucket lifecycle.
Expand Down Expand Up @@ -114,7 +120,7 @@ func (c *Client) GetBucketLifecycleWithInfo(ctx context.Context, bucketName stri
return nil, time.Time{}, err
}

bucketLifecycle, updatedAt, err := c.getBucketLifecycle(ctx, bucketName)
bucketLifecycle, updatedAt, expAfterRepl, err := c.getBucketLifecycle(ctx, bucketName)
if err != nil {
return nil, time.Time{}, err
}
Expand All @@ -123,11 +129,12 @@ func (c *Client) GetBucketLifecycleWithInfo(ctx context.Context, bucketName stri
if err = xml.Unmarshal(bucketLifecycle, config); err != nil {
return nil, time.Time{}, err
}
config.ExpireAfterReplication = expAfterRepl
return config, updatedAt, nil
}

// Request server for current bucket lifecycle.
func (c *Client) getBucketLifecycle(ctx context.Context, bucketName string) ([]byte, time.Time, error) {
func (c *Client) getBucketLifecycle(ctx context.Context, bucketName string) ([]byte, time.Time, string, error) {
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
Expand All @@ -142,28 +149,28 @@ func (c *Client) getBucketLifecycle(ctx context.Context, bucketName string) ([]b

defer closeResponse(resp)
if err != nil {
return nil, time.Time{}, err
return nil, time.Time{}, "", err
}

if resp != nil {
if resp.StatusCode != http.StatusOK {
return nil, time.Time{}, httpRespToErrorResponse(resp, bucketName, "")
return nil, time.Time{}, "", httpRespToErrorResponse(resp, bucketName, "")
}
}

lcBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, time.Time{}, err
return nil, time.Time{}, "", err
}

const minIOLifecycleCfgUpdatedAt = "X-Minio-LifecycleConfig-UpdatedAt"
var updatedAt time.Time
if timeStr := resp.Header.Get(minIOLifecycleCfgUpdatedAt); timeStr != "" {
updatedAt, err = time.Parse(iso8601DateFormat, timeStr)
if err != nil {
return nil, time.Time{}, err
return nil, time.Time{}, "", err
}
}

return lcBytes, updatedAt, nil
expAfterRepl := resp.Header.Get(minioLifecycleExpiryAfterReplication)
return lcBytes, updatedAt, expAfterRepl, nil
}
2 changes: 2 additions & 0 deletions api-put-object.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ const (
ReplicationStatusFailed ReplicationStatus = "FAILED"
// ReplicationStatusReplica indicates object is a replica of a source
ReplicationStatusReplica ReplicationStatus = "REPLICA"
// ReplicationStatusReplicaEdge indicates object is a replica of a edge source
ReplicationStatusReplicaEdge ReplicationStatus = "REPLICA-EDGE"
)

// Empty returns true if no replication status set.
Expand Down
3 changes: 3 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,7 @@ const (
minioTgtReplicationReady = "X-Minio-Replication-Ready"
// Header asks if delete marker replication request can be sent by source now.
isMinioTgtReplicationReady = "X-Minio-Check-Replication-Ready"

// Header indicating if ilm expiry ignores replication status
harshavardhana marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Header indicates if ILM expiration must trigger after replication

minioLifecycleExpiryAfterReplication = "X-Minio-Lifecycle-Expiry-After-Replication"
)
5 changes: 3 additions & 2 deletions pkg/lifecycle/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,9 @@ type Rule struct {

// Configuration is a collection of Rule objects.
type Configuration struct {
XMLName xml.Name `xml:"LifecycleConfiguration,omitempty" json:"-"`
Rules []Rule `xml:"Rule"`
XMLName xml.Name `xml:"LifecycleConfiguration,omitempty" json:"-"`
Rules []Rule `xml:"Rule"`
ExpireAfterReplication string `xml:"-" json:"-"`
}

// Empty check if lifecycle configuration is empty
Expand Down
Loading