api-object-retention.go 4.6 KB

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