api-object-retention.go (4745B)
1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2019-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 "fmt" 25 "net/http" 26 "net/url" 27 "time" 28 29 "github.com/minio/minio-go/v7/pkg/s3utils" 30 ) 31 32 // objectRetention - object retention specified in 33 // https://docs.aws.amazon.com/AmazonS3/latest/API/Type_API_ObjectLockConfiguration.html 34 type objectRetention struct { 35 XMLNS string `xml:"xmlns,attr,omitempty"` 36 XMLName xml.Name `xml:"Retention"` 37 Mode RetentionMode `xml:"Mode,omitempty"` 38 RetainUntilDate *time.Time `type:"timestamp" timestampFormat:"iso8601" xml:"RetainUntilDate,omitempty"` 39 } 40 41 func newObjectRetention(mode *RetentionMode, date *time.Time) (*objectRetention, error) { 42 objectRetention := &objectRetention{} 43 44 if date != nil && !date.IsZero() { 45 objectRetention.RetainUntilDate = date 46 } 47 if mode != nil { 48 if !mode.IsValid() { 49 return nil, fmt.Errorf("invalid retention mode `%v`", mode) 50 } 51 objectRetention.Mode = *mode 52 } 53 54 return objectRetention, nil 55 } 56 57 // PutObjectRetentionOptions represents options specified by user for PutObject call 58 type PutObjectRetentionOptions struct { 59 GovernanceBypass bool 60 Mode *RetentionMode 61 RetainUntilDate *time.Time 62 VersionID string 63 } 64 65 // PutObjectRetention sets object retention for a given object and versionID. 66 func (c *Client) PutObjectRetention(ctx context.Context, bucketName, objectName string, opts PutObjectRetentionOptions) error { 67 // Input validation. 68 if err := s3utils.CheckValidBucketName(bucketName); err != nil { 69 return err 70 } 71 72 if err := s3utils.CheckValidObjectName(objectName); err != nil { 73 return err 74 } 75 76 // Get resources properly escaped and lined up before 77 // using them in http request. 78 urlValues := make(url.Values) 79 urlValues.Set("retention", "") 80 81 if opts.VersionID != "" { 82 urlValues.Set("versionId", opts.VersionID) 83 } 84 85 retention, err := newObjectRetention(opts.Mode, opts.RetainUntilDate) 86 if err != nil { 87 return err 88 } 89 90 retentionData, err := xml.Marshal(retention) 91 if err != nil { 92 return err 93 } 94 95 // Build headers. 96 headers := make(http.Header) 97 98 if opts.GovernanceBypass { 99 // Set the bypass goverenance retention header 100 headers.Set(amzBypassGovernance, "true") 101 } 102 103 reqMetadata := requestMetadata{ 104 bucketName: bucketName, 105 objectName: objectName, 106 queryValues: urlValues, 107 contentBody: bytes.NewReader(retentionData), 108 contentLength: int64(len(retentionData)), 109 contentMD5Base64: sumMD5Base64(retentionData), 110 contentSHA256Hex: sum256Hex(retentionData), 111 customHeader: headers, 112 } 113 114 // Execute PUT Object Retention. 115 resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata) 116 defer closeResponse(resp) 117 if err != nil { 118 return err 119 } 120 if resp != nil { 121 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { 122 return httpRespToErrorResponse(resp, bucketName, objectName) 123 } 124 } 125 return nil 126 } 127 128 // GetObjectRetention gets retention of given object. 129 func (c *Client) GetObjectRetention(ctx context.Context, bucketName, objectName, versionID string) (mode *RetentionMode, retainUntilDate *time.Time, err error) { 130 // Input validation. 131 if err := s3utils.CheckValidBucketName(bucketName); err != nil { 132 return nil, nil, err 133 } 134 135 if err := s3utils.CheckValidObjectName(objectName); err != nil { 136 return nil, nil, err 137 } 138 urlValues := make(url.Values) 139 urlValues.Set("retention", "") 140 if versionID != "" { 141 urlValues.Set("versionId", versionID) 142 } 143 // Execute GET on bucket to list objects. 144 resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{ 145 bucketName: bucketName, 146 objectName: objectName, 147 queryValues: urlValues, 148 contentSHA256Hex: emptySHA256Hex, 149 }) 150 defer closeResponse(resp) 151 if err != nil { 152 return nil, nil, err 153 } 154 if resp != nil { 155 if resp.StatusCode != http.StatusOK { 156 return nil, nil, httpRespToErrorResponse(resp, bucketName, objectName) 157 } 158 } 159 retention := &objectRetention{} 160 if err = xml.NewDecoder(resp.Body).Decode(retention); err != nil { 161 return nil, nil, err 162 } 163 164 return &retention.Mode, retention.RetainUntilDate, nil 165 }