api-bucket-lifecycle.go (4875B)
1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2020 MinIO, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package minio 19 20 import ( 21 "bytes" 22 "context" 23 "encoding/xml" 24 "io" 25 "net/http" 26 "net/url" 27 "time" 28 29 "github.com/minio/minio-go/v7/pkg/lifecycle" 30 "github.com/minio/minio-go/v7/pkg/s3utils" 31 ) 32 33 // SetBucketLifecycle set the lifecycle on an existing bucket. 34 func (c *Client) SetBucketLifecycle(ctx context.Context, bucketName string, config *lifecycle.Configuration) error { 35 // Input validation. 36 if err := s3utils.CheckValidBucketName(bucketName); err != nil { 37 return err 38 } 39 40 // If lifecycle is empty then delete it. 41 if config.Empty() { 42 return c.removeBucketLifecycle(ctx, bucketName) 43 } 44 45 buf, err := xml.Marshal(config) 46 if err != nil { 47 return err 48 } 49 50 // Save the updated lifecycle. 51 return c.putBucketLifecycle(ctx, bucketName, buf) 52 } 53 54 // Saves a new bucket lifecycle. 55 func (c *Client) putBucketLifecycle(ctx context.Context, bucketName string, buf []byte) error { 56 // Get resources properly escaped and lined up before 57 // using them in http request. 58 urlValues := make(url.Values) 59 urlValues.Set("lifecycle", "") 60 61 // Content-length is mandatory for put lifecycle request 62 reqMetadata := requestMetadata{ 63 bucketName: bucketName, 64 queryValues: urlValues, 65 contentBody: bytes.NewReader(buf), 66 contentLength: int64(len(buf)), 67 contentMD5Base64: sumMD5Base64(buf), 68 } 69 70 // Execute PUT to upload a new bucket lifecycle. 71 resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata) 72 defer closeResponse(resp) 73 if err != nil { 74 return err 75 } 76 if resp != nil { 77 if resp.StatusCode != http.StatusOK { 78 return httpRespToErrorResponse(resp, bucketName, "") 79 } 80 } 81 return nil 82 } 83 84 // Remove lifecycle from a bucket. 85 func (c *Client) removeBucketLifecycle(ctx context.Context, bucketName string) error { 86 // Get resources properly escaped and lined up before 87 // using them in http request. 88 urlValues := make(url.Values) 89 urlValues.Set("lifecycle", "") 90 91 // Execute DELETE on objectName. 92 resp, err := c.executeMethod(ctx, http.MethodDelete, requestMetadata{ 93 bucketName: bucketName, 94 queryValues: urlValues, 95 contentSHA256Hex: emptySHA256Hex, 96 }) 97 defer closeResponse(resp) 98 if err != nil { 99 return err 100 } 101 return nil 102 } 103 104 // GetBucketLifecycle fetch bucket lifecycle configuration 105 func (c *Client) GetBucketLifecycle(ctx context.Context, bucketName string) (*lifecycle.Configuration, error) { 106 lc, _, err := c.GetBucketLifecycleWithInfo(ctx, bucketName) 107 return lc, err 108 } 109 110 // GetBucketLifecycleWithInfo fetch bucket lifecycle configuration along with when it was last updated 111 func (c *Client) GetBucketLifecycleWithInfo(ctx context.Context, bucketName string) (*lifecycle.Configuration, time.Time, error) { 112 // Input validation. 113 if err := s3utils.CheckValidBucketName(bucketName); err != nil { 114 return nil, time.Time{}, err 115 } 116 117 bucketLifecycle, updatedAt, err := c.getBucketLifecycle(ctx, bucketName) 118 if err != nil { 119 return nil, time.Time{}, err 120 } 121 122 config := lifecycle.NewConfiguration() 123 if err = xml.Unmarshal(bucketLifecycle, config); err != nil { 124 return nil, time.Time{}, err 125 } 126 return config, updatedAt, nil 127 } 128 129 // Request server for current bucket lifecycle. 130 func (c *Client) getBucketLifecycle(ctx context.Context, bucketName string) ([]byte, time.Time, error) { 131 // Get resources properly escaped and lined up before 132 // using them in http request. 133 urlValues := make(url.Values) 134 urlValues.Set("lifecycle", "") 135 urlValues.Set("withUpdatedAt", "true") 136 137 // Execute GET on bucket to get lifecycle. 138 resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{ 139 bucketName: bucketName, 140 queryValues: urlValues, 141 }) 142 143 defer closeResponse(resp) 144 if err != nil { 145 return nil, time.Time{}, err 146 } 147 148 if resp != nil { 149 if resp.StatusCode != http.StatusOK { 150 return nil, time.Time{}, httpRespToErrorResponse(resp, bucketName, "") 151 } 152 } 153 154 lcBytes, err := io.ReadAll(resp.Body) 155 if err != nil { 156 return nil, time.Time{}, err 157 } 158 159 const minIOLifecycleCfgUpdatedAt = "X-Minio-LifecycleConfig-UpdatedAt" 160 var updatedAt time.Time 161 if timeStr := resp.Header.Get(minIOLifecycleCfgUpdatedAt); timeStr != "" { 162 updatedAt, err = time.Parse(iso8601DateFormat, timeStr) 163 if err != nil { 164 return nil, time.Time{}, err 165 } 166 } 167 168 return lcBytes, updatedAt, nil 169 }