api-object-lock.go (6985B)
1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2019 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 "fmt" 25 "net/http" 26 "net/url" 27 "time" 28 29 "github.com/minio/minio-go/v7/pkg/s3utils" 30 ) 31 32 // RetentionMode - object retention mode. 33 type RetentionMode string 34 35 const ( 36 // Governance - governance mode. 37 Governance RetentionMode = "GOVERNANCE" 38 39 // Compliance - compliance mode. 40 Compliance RetentionMode = "COMPLIANCE" 41 ) 42 43 func (r RetentionMode) String() string { 44 return string(r) 45 } 46 47 // IsValid - check whether this retention mode is valid or not. 48 func (r RetentionMode) IsValid() bool { 49 return r == Governance || r == Compliance 50 } 51 52 // ValidityUnit - retention validity unit. 53 type ValidityUnit string 54 55 const ( 56 // Days - denotes no. of days. 57 Days ValidityUnit = "DAYS" 58 59 // Years - denotes no. of years. 60 Years ValidityUnit = "YEARS" 61 ) 62 63 func (unit ValidityUnit) String() string { 64 return string(unit) 65 } 66 67 // IsValid - check whether this validity unit is valid or not. 68 func (unit ValidityUnit) isValid() bool { 69 return unit == Days || unit == Years 70 } 71 72 // Retention - bucket level retention configuration. 73 type Retention struct { 74 Mode RetentionMode 75 Validity time.Duration 76 } 77 78 func (r Retention) String() string { 79 return fmt.Sprintf("{Mode:%v, Validity:%v}", r.Mode, r.Validity) 80 } 81 82 // IsEmpty - returns whether retention is empty or not. 83 func (r Retention) IsEmpty() bool { 84 return r.Mode == "" || r.Validity == 0 85 } 86 87 // objectLockConfig - object lock configuration specified in 88 // https://docs.aws.amazon.com/AmazonS3/latest/API/Type_API_ObjectLockConfiguration.html 89 type objectLockConfig struct { 90 XMLNS string `xml:"xmlns,attr,omitempty"` 91 XMLName xml.Name `xml:"ObjectLockConfiguration"` 92 ObjectLockEnabled string `xml:"ObjectLockEnabled"` 93 Rule *struct { 94 DefaultRetention struct { 95 Mode RetentionMode `xml:"Mode"` 96 Days *uint `xml:"Days"` 97 Years *uint `xml:"Years"` 98 } `xml:"DefaultRetention"` 99 } `xml:"Rule,omitempty"` 100 } 101 102 func newObjectLockConfig(mode *RetentionMode, validity *uint, unit *ValidityUnit) (*objectLockConfig, error) { 103 config := &objectLockConfig{ 104 ObjectLockEnabled: "Enabled", 105 } 106 107 if mode != nil && validity != nil && unit != nil { 108 if !mode.IsValid() { 109 return nil, fmt.Errorf("invalid retention mode `%v`", mode) 110 } 111 112 if !unit.isValid() { 113 return nil, fmt.Errorf("invalid validity unit `%v`", unit) 114 } 115 116 config.Rule = &struct { 117 DefaultRetention struct { 118 Mode RetentionMode `xml:"Mode"` 119 Days *uint `xml:"Days"` 120 Years *uint `xml:"Years"` 121 } `xml:"DefaultRetention"` 122 }{} 123 124 config.Rule.DefaultRetention.Mode = *mode 125 if *unit == Days { 126 config.Rule.DefaultRetention.Days = validity 127 } else { 128 config.Rule.DefaultRetention.Years = validity 129 } 130 131 return config, nil 132 } 133 134 if mode == nil && validity == nil && unit == nil { 135 return config, nil 136 } 137 138 return nil, fmt.Errorf("all of retention mode, validity and validity unit must be passed") 139 } 140 141 // SetBucketObjectLockConfig sets object lock configuration in given bucket. mode, validity and unit are either all set or all nil. 142 func (c *Client) SetBucketObjectLockConfig(ctx context.Context, bucketName string, mode *RetentionMode, validity *uint, unit *ValidityUnit) error { 143 // Input validation. 144 if err := s3utils.CheckValidBucketName(bucketName); err != nil { 145 return err 146 } 147 148 // Get resources properly escaped and lined up before 149 // using them in http request. 150 urlValues := make(url.Values) 151 urlValues.Set("object-lock", "") 152 153 config, err := newObjectLockConfig(mode, validity, unit) 154 if err != nil { 155 return err 156 } 157 158 configData, err := xml.Marshal(config) 159 if err != nil { 160 return err 161 } 162 163 reqMetadata := requestMetadata{ 164 bucketName: bucketName, 165 queryValues: urlValues, 166 contentBody: bytes.NewReader(configData), 167 contentLength: int64(len(configData)), 168 contentMD5Base64: sumMD5Base64(configData), 169 contentSHA256Hex: sum256Hex(configData), 170 } 171 172 // Execute PUT bucket object lock configuration. 173 resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata) 174 defer closeResponse(resp) 175 if err != nil { 176 return err 177 } 178 if resp != nil { 179 if resp.StatusCode != http.StatusOK { 180 return httpRespToErrorResponse(resp, bucketName, "") 181 } 182 } 183 return nil 184 } 185 186 // GetObjectLockConfig gets object lock configuration of given bucket. 187 func (c *Client) GetObjectLockConfig(ctx context.Context, bucketName string) (objectLock string, mode *RetentionMode, validity *uint, unit *ValidityUnit, err error) { 188 // Input validation. 189 if err := s3utils.CheckValidBucketName(bucketName); err != nil { 190 return "", nil, nil, nil, err 191 } 192 193 urlValues := make(url.Values) 194 urlValues.Set("object-lock", "") 195 196 // Execute GET on bucket to list objects. 197 resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{ 198 bucketName: bucketName, 199 queryValues: urlValues, 200 contentSHA256Hex: emptySHA256Hex, 201 }) 202 defer closeResponse(resp) 203 if err != nil { 204 return "", nil, nil, nil, err 205 } 206 if resp != nil { 207 if resp.StatusCode != http.StatusOK { 208 return "", nil, nil, nil, httpRespToErrorResponse(resp, bucketName, "") 209 } 210 } 211 config := &objectLockConfig{} 212 if err = xml.NewDecoder(resp.Body).Decode(config); err != nil { 213 return "", nil, nil, nil, err 214 } 215 216 if config.Rule != nil { 217 mode = &config.Rule.DefaultRetention.Mode 218 if config.Rule.DefaultRetention.Days != nil { 219 validity = config.Rule.DefaultRetention.Days 220 days := Days 221 unit = &days 222 } else { 223 validity = config.Rule.DefaultRetention.Years 224 years := Years 225 unit = &years 226 } 227 return config.ObjectLockEnabled, mode, validity, unit, nil 228 } 229 return config.ObjectLockEnabled, nil, nil, nil, nil 230 } 231 232 // GetBucketObjectLockConfig gets object lock configuration of given bucket. 233 func (c *Client) GetBucketObjectLockConfig(ctx context.Context, bucketName string) (mode *RetentionMode, validity *uint, unit *ValidityUnit, err error) { 234 _, mode, validity, unit, err = c.GetObjectLockConfig(ctx, bucketName) 235 return mode, validity, unit, err 236 } 237 238 // SetObjectLockConfig sets object lock configuration in given bucket. mode, validity and unit are either all set or all nil. 239 func (c *Client) SetObjectLockConfig(ctx context.Context, bucketName string, mode *RetentionMode, validity *uint, unit *ValidityUnit) error { 240 return c.SetBucketObjectLockConfig(ctx, bucketName, mode, validity, unit) 241 }