Add put object retention api (#340)

This commit is contained in:
Cesar N
2020-10-23 15:04:02 -07:00
committed by GitHub
parent fce361e5bd
commit 0325bb7e2d
12 changed files with 1131 additions and 6 deletions

View File

@@ -0,0 +1,80 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
)
// ObjectRetentionMode object retention mode
//
// swagger:model objectRetentionMode
type ObjectRetentionMode string
const (
// ObjectRetentionModeGovernance captures enum value "governance"
ObjectRetentionModeGovernance ObjectRetentionMode = "governance"
// ObjectRetentionModeCompliance captures enum value "compliance"
ObjectRetentionModeCompliance ObjectRetentionMode = "compliance"
)
// for schema
var objectRetentionModeEnum []interface{}
func init() {
var res []ObjectRetentionMode
if err := json.Unmarshal([]byte(`["governance","compliance"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
objectRetentionModeEnum = append(objectRetentionModeEnum, v)
}
}
func (m ObjectRetentionMode) validateObjectRetentionModeEnum(path, location string, value ObjectRetentionMode) error {
if err := validate.EnumCase(path, location, value, objectRetentionModeEnum, true); err != nil {
return err
}
return nil
}
// Validate validates this object retention mode
func (m ObjectRetentionMode) Validate(formats strfmt.Registry) error {
var res []error
// value enum
if err := m.validateObjectRetentionModeEnum("", "body", m); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,104 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// PutObjectRetentionRequest put object retention request
//
// swagger:model putObjectRetentionRequest
type PutObjectRetentionRequest struct {
// expires
// Required: true
Expires *string `json:"expires"`
// governance bypass
GovernanceBypass bool `json:"governance_bypass,omitempty"`
// mode
// Required: true
Mode ObjectRetentionMode `json:"mode"`
}
// Validate validates this put object retention request
func (m *PutObjectRetentionRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateExpires(formats); err != nil {
res = append(res, err)
}
if err := m.validateMode(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PutObjectRetentionRequest) validateExpires(formats strfmt.Registry) error {
if err := validate.Required("expires", "body", m.Expires); err != nil {
return err
}
return nil
}
func (m *PutObjectRetentionRequest) validateMode(formats strfmt.Registry) error {
if err := m.Mode.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("mode")
}
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *PutObjectRetentionRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PutObjectRetentionRequest) UnmarshalBinary(b []byte) error {
var res PutObjectRetentionRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -60,6 +60,7 @@ type MinioClient interface {
getObjectLegalHold(ctx context.Context, bucketName, objectName string, opts minio.GetObjectLegalHoldOptions) (status *minio.LegalHoldStatus, err error)
putObject(ctx context.Context, bucketName, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (info minio.UploadInfo, err error)
putObjectLegalHold(ctx context.Context, bucketName, objectName string, opts minio.PutObjectLegalHoldOptions) error
putObjectRetention(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error
}
// Interface implementation
@@ -138,6 +139,10 @@ func (c minioClient) putObjectLegalHold(ctx context.Context, bucketName, objectN
return c.client.PutObjectLegalHold(ctx, bucketName, objectName, opts)
}
func (c minioClient) putObjectRetention(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return c.client.PutObjectRetention(ctx, bucketName, objectName, opts)
}
// MCClient interface with all functions to be implemented
// by mock when testing, it should include all mc/S3Client respective api calls
// that are used within this project.

View File

@@ -517,6 +517,54 @@ func init() {
}
}
},
"/buckets/{bucket_name}/objects/retention": {
"put": {
"tags": [
"UserAPI"
],
"summary": "Put Object's retention status",
"operationId": "PutObjectRetention",
"parameters": [
{
"type": "string",
"name": "bucket_name",
"in": "path",
"required": true
},
{
"type": "string",
"name": "prefix",
"in": "query",
"required": true
},
{
"type": "string",
"name": "version_id",
"in": "query",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/putObjectRetentionRequest"
}
}
],
"responses": {
"200": {
"description": "A successful response."
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/buckets/{bucket_name}/objects/share": {
"get": {
"tags": [
@@ -3750,6 +3798,13 @@ func init() {
"disabled"
]
},
"objectRetentionMode": {
"type": "string",
"enum": [
"governance",
"compliance"
]
},
"parityResponse": {
"type": "array",
"items": {
@@ -3891,6 +3946,24 @@ func init() {
}
}
},
"putObjectRetentionRequest": {
"type": "object",
"required": [
"mode",
"expires"
],
"properties": {
"expires": {
"type": "string"
},
"governance_bypass": {
"type": "boolean"
},
"mode": {
"$ref": "#/definitions/objectRetentionMode"
}
}
},
"remoteBucket": {
"type": "object",
"required": [
@@ -5124,6 +5197,54 @@ func init() {
}
}
},
"/buckets/{bucket_name}/objects/retention": {
"put": {
"tags": [
"UserAPI"
],
"summary": "Put Object's retention status",
"operationId": "PutObjectRetention",
"parameters": [
{
"type": "string",
"name": "bucket_name",
"in": "path",
"required": true
},
{
"type": "string",
"name": "prefix",
"in": "query",
"required": true
},
{
"type": "string",
"name": "version_id",
"in": "query",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/putObjectRetentionRequest"
}
}
],
"responses": {
"200": {
"description": "A successful response."
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/buckets/{bucket_name}/objects/share": {
"get": {
"tags": [
@@ -8836,6 +8957,13 @@ func init() {
"disabled"
]
},
"objectRetentionMode": {
"type": "string",
"enum": [
"governance",
"compliance"
]
},
"parityResponse": {
"type": "array",
"items": {
@@ -8955,6 +9083,24 @@ func init() {
}
}
},
"putObjectRetentionRequest": {
"type": "object",
"required": [
"mode",
"expires"
],
"properties": {
"expires": {
"type": "string"
},
"governance_bypass": {
"type": "boolean"
},
"mode": {
"$ref": "#/definitions/objectRetentionMode"
}
}
},
"remoteBucket": {
"type": "object",
"required": [

View File

@@ -226,6 +226,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
UserAPIPutObjectLegalHoldHandler: user_api.PutObjectLegalHoldHandlerFunc(func(params user_api.PutObjectLegalHoldParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.PutObjectLegalHold has not yet been implemented")
}),
UserAPIPutObjectRetentionHandler: user_api.PutObjectRetentionHandlerFunc(func(params user_api.PutObjectRetentionParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.PutObjectRetention has not yet been implemented")
}),
UserAPIRemoteBucketDetailsHandler: user_api.RemoteBucketDetailsHandlerFunc(func(params user_api.RemoteBucketDetailsParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.RemoteBucketDetails has not yet been implemented")
}),
@@ -446,6 +449,8 @@ type ConsoleAPI struct {
AdminAPIProfilingStopHandler admin_api.ProfilingStopHandler
// UserAPIPutObjectLegalHoldHandler sets the operation handler for the put object legal hold operation
UserAPIPutObjectLegalHoldHandler user_api.PutObjectLegalHoldHandler
// UserAPIPutObjectRetentionHandler sets the operation handler for the put object retention operation
UserAPIPutObjectRetentionHandler user_api.PutObjectRetentionHandler
// UserAPIRemoteBucketDetailsHandler sets the operation handler for the remote bucket details operation
UserAPIRemoteBucketDetailsHandler user_api.RemoteBucketDetailsHandler
// AdminAPIRemoveGroupHandler sets the operation handler for the remove group operation
@@ -724,6 +729,9 @@ func (o *ConsoleAPI) Validate() error {
if o.UserAPIPutObjectLegalHoldHandler == nil {
unregistered = append(unregistered, "user_api.PutObjectLegalHoldHandler")
}
if o.UserAPIPutObjectRetentionHandler == nil {
unregistered = append(unregistered, "user_api.PutObjectRetentionHandler")
}
if o.UserAPIRemoteBucketDetailsHandler == nil {
unregistered = append(unregistered, "user_api.RemoteBucketDetailsHandler")
}
@@ -1102,6 +1110,10 @@ func (o *ConsoleAPI) initHandlerCache() {
o.handlers["PUT"] = make(map[string]http.Handler)
}
o.handlers["PUT"]["/buckets/{bucket_name}/objects/legalhold"] = user_api.NewPutObjectLegalHold(o.context, o.UserAPIPutObjectLegalHoldHandler)
if o.handlers["PUT"] == nil {
o.handlers["PUT"] = make(map[string]http.Handler)
}
o.handlers["PUT"]["/buckets/{bucket_name}/objects/retention"] = user_api.NewPutObjectRetention(o.context, o.UserAPIPutObjectRetentionHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}

View File

@@ -0,0 +1,90 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package user_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// PutObjectRetentionHandlerFunc turns a function with the right signature into a put object retention handler
type PutObjectRetentionHandlerFunc func(PutObjectRetentionParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn PutObjectRetentionHandlerFunc) Handle(params PutObjectRetentionParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// PutObjectRetentionHandler interface for that can handle valid put object retention params
type PutObjectRetentionHandler interface {
Handle(PutObjectRetentionParams, *models.Principal) middleware.Responder
}
// NewPutObjectRetention creates a new http.Handler for the put object retention operation
func NewPutObjectRetention(ctx *middleware.Context, handler PutObjectRetentionHandler) *PutObjectRetention {
return &PutObjectRetention{Context: ctx, Handler: handler}
}
/*PutObjectRetention swagger:route PUT /buckets/{bucket_name}/objects/retention UserAPI putObjectRetention
Put Object's retention status
*/
type PutObjectRetention struct {
Context *middleware.Context
Handler PutObjectRetentionHandler
}
func (o *PutObjectRetention) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
}
var Params = NewPutObjectRetentionParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
r = aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -0,0 +1,185 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package user_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"io"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
"github.com/minio/console/models"
)
// NewPutObjectRetentionParams creates a new PutObjectRetentionParams object
// no default values defined in spec.
func NewPutObjectRetentionParams() PutObjectRetentionParams {
return PutObjectRetentionParams{}
}
// PutObjectRetentionParams contains all the bound params for the put object retention operation
// typically these are obtained from a http.Request
//
// swagger:parameters PutObjectRetention
type PutObjectRetentionParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: body
*/
Body *models.PutObjectRetentionRequest
/*
Required: true
In: path
*/
BucketName string
/*
Required: true
In: query
*/
Prefix string
/*
Required: true
In: query
*/
VersionID string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewPutObjectRetentionParams() beforehand.
func (o *PutObjectRetentionParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
qs := runtime.Values(r.URL.Query())
if runtime.HasBody(r) {
defer r.Body.Close()
var body models.PutObjectRetentionRequest
if err := route.Consumer.Consume(r.Body, &body); err != nil {
if err == io.EOF {
res = append(res, errors.Required("body", "body", ""))
} else {
res = append(res, errors.NewParseError("body", "body", "", err))
}
} else {
// validate body object
if err := body.Validate(route.Formats); err != nil {
res = append(res, err)
}
if len(res) == 0 {
o.Body = &body
}
}
} else {
res = append(res, errors.Required("body", "body", ""))
}
rBucketName, rhkBucketName, _ := route.Params.GetOK("bucket_name")
if err := o.bindBucketName(rBucketName, rhkBucketName, route.Formats); err != nil {
res = append(res, err)
}
qPrefix, qhkPrefix, _ := qs.GetOK("prefix")
if err := o.bindPrefix(qPrefix, qhkPrefix, route.Formats); err != nil {
res = append(res, err)
}
qVersionID, qhkVersionID, _ := qs.GetOK("version_id")
if err := o.bindVersionID(qVersionID, qhkVersionID, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindBucketName binds and validates parameter BucketName from path.
func (o *PutObjectRetentionParams) bindBucketName(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.BucketName = raw
return nil
}
// bindPrefix binds and validates parameter Prefix from query.
func (o *PutObjectRetentionParams) bindPrefix(rawData []string, hasKey bool, formats strfmt.Registry) error {
if !hasKey {
return errors.Required("prefix", "query", rawData)
}
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// AllowEmptyValue: false
if err := validate.RequiredString("prefix", "query", raw); err != nil {
return err
}
o.Prefix = raw
return nil
}
// bindVersionID binds and validates parameter VersionID from query.
func (o *PutObjectRetentionParams) bindVersionID(rawData []string, hasKey bool, formats strfmt.Registry) error {
if !hasKey {
return errors.Required("version_id", "query", rawData)
}
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// AllowEmptyValue: false
if err := validate.RequiredString("version_id", "query", raw); err != nil {
return err
}
o.VersionID = raw
return nil
}

View File

@@ -0,0 +1,113 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package user_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// PutObjectRetentionOKCode is the HTTP code returned for type PutObjectRetentionOK
const PutObjectRetentionOKCode int = 200
/*PutObjectRetentionOK A successful response.
swagger:response putObjectRetentionOK
*/
type PutObjectRetentionOK struct {
}
// NewPutObjectRetentionOK creates PutObjectRetentionOK with default headers values
func NewPutObjectRetentionOK() *PutObjectRetentionOK {
return &PutObjectRetentionOK{}
}
// WriteResponse to the client
func (o *PutObjectRetentionOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
rw.WriteHeader(200)
}
/*PutObjectRetentionDefault Generic error response.
swagger:response putObjectRetentionDefault
*/
type PutObjectRetentionDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewPutObjectRetentionDefault creates PutObjectRetentionDefault with default headers values
func NewPutObjectRetentionDefault(code int) *PutObjectRetentionDefault {
if code <= 0 {
code = 500
}
return &PutObjectRetentionDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the put object retention default response
func (o *PutObjectRetentionDefault) WithStatusCode(code int) *PutObjectRetentionDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the put object retention default response
func (o *PutObjectRetentionDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the put object retention default response
func (o *PutObjectRetentionDefault) WithPayload(payload *models.Error) *PutObjectRetentionDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the put object retention default response
func (o *PutObjectRetentionDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *PutObjectRetentionDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -0,0 +1,133 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package user_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"strings"
)
// PutObjectRetentionURL generates an URL for the put object retention operation
type PutObjectRetentionURL struct {
BucketName string
Prefix string
VersionID string
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *PutObjectRetentionURL) WithBasePath(bp string) *PutObjectRetentionURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *PutObjectRetentionURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *PutObjectRetentionURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/buckets/{bucket_name}/objects/retention"
bucketName := o.BucketName
if bucketName != "" {
_path = strings.Replace(_path, "{bucket_name}", bucketName, -1)
} else {
return nil, errors.New("bucketName is required on PutObjectRetentionURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
qs := make(url.Values)
prefixQ := o.Prefix
if prefixQ != "" {
qs.Set("prefix", prefixQ)
}
versionIDQ := o.VersionID
if versionIDQ != "" {
qs.Set("version_id", versionIDQ)
}
_result.RawQuery = qs.Encode()
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *PutObjectRetentionURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *PutObjectRetentionURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *PutObjectRetentionURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on PutObjectRetentionURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on PutObjectRetentionURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *PutObjectRetentionURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -99,6 +99,13 @@ func registerObjectsHandlers(api *operations.ConsoleAPI) {
}
return user_api.NewPutObjectLegalHoldOK()
})
// set object retention
api.UserAPIPutObjectRetentionHandler = user_api.PutObjectRetentionHandlerFunc(func(params user_api.PutObjectRetentionParams, session *models.Principal) middleware.Responder {
if err := getSetObjectRetentionResponse(session, params); err != nil {
return user_api.NewPutObjectRetentionDefault(int(err.Code)).WithPayload(err)
}
return user_api.NewPutObjectRetentionOK()
})
}
// getListObjectsResponse returns a list of objects
@@ -269,6 +276,7 @@ func deleteMultipleObjects(ctx context.Context, client MCClient, recursive bool)
contentCh := make(chan *mc.ClientContent, 1)
errorCh := client.remove(ctx, isIncomplete, isRemoveBucket, isBypass, contentCh)
OUTER_LOOP:
for content := range client.list(ctx, listOpts) {
if content.Err != nil {
switch content.Err.ToGoError().(type) {
@@ -286,13 +294,17 @@ func deleteMultipleObjects(ctx context.Context, client MCClient, recursive bool)
case contentCh <- content:
sent = true
case pErr := <-errorCh:
switch pErr.ToGoError().(type) {
// ignore same as mc
case mc.PathInsufficientPermission:
// Ignore Permission error.
continue
if pErr != nil {
switch pErr.ToGoError().(type) {
// ignore same as mc
case mc.PathInsufficientPermission:
// Ignore Permission error.
continue
}
close(contentCh)
return pErr.Cause
}
return pErr.Cause
break OUTER_LOOP
}
}
}
@@ -439,6 +451,49 @@ func setObjectLegalHold(ctx context.Context, client MinioClient, bucketName, pre
return client.putObjectLegalHold(ctx, bucketName, prefix, minio.PutObjectLegalHoldOptions{VersionID: versionID, Status: &lstatus})
}
func getSetObjectRetentionResponse(session *models.Principal, params user_api.PutObjectRetentionParams) *models.Error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
mClient, err := newMinioClient(session)
if err != nil {
return prepareError(err)
}
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient{client: mClient}
err = setObjectRetention(ctx, minioClient, params.BucketName, params.Prefix, params.VersionID, params.Body)
if err != nil {
return prepareError(err)
}
return nil
}
func setObjectRetention(ctx context.Context, client MinioClient, bucketName, prefix, versionID string, retentionOps *models.PutObjectRetentionRequest) error {
if retentionOps == nil {
return errors.New("object retention options can't be nil")
}
if retentionOps.Expires == nil {
return errors.New("object retention expires can't be nil")
}
var mode minio.RetentionMode
if retentionOps.Mode == models.ObjectRetentionModeGovernance {
mode = minio.Governance
} else {
mode = minio.Compliance
}
retentionUntilDate, err := time.Parse(time.RFC3339, *retentionOps.Expires)
if err != nil {
return err
}
opts := minio.PutObjectRetentionOptions{
GovernanceBypass: retentionOps.GovernanceBypass,
RetainUntilDate: &retentionUntilDate,
Mode: &mode,
VersionID: versionID,
}
return client.putObjectRetention(ctx, bucketName, prefix, opts)
}
// newClientURL returns an abstracted URL for filesystems and object storage.
func newClientURL(urlStr string) *mc.ClientURL {
scheme, rest := getScheme(urlStr)

View File

@@ -20,11 +20,13 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"reflect"
"testing"
"time"
"github.com/go-openapi/swag"
"github.com/minio/console/models"
mc "github.com/minio/mc/cmd"
"github.com/minio/mc/pkg/probe"
@@ -37,6 +39,7 @@ var minioGetObjectLegalHoldMock func(ctx context.Context, bucketName, objectName
var minioGetObjectRetentionMock func(ctx context.Context, bucketName, objectName, versionID string) (mode *minio.RetentionMode, retainUntilDate *time.Time, err error)
var minioPutObjectMock func(ctx context.Context, bucketName, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (info minio.UploadInfo, err error)
var minioPutObjectLegalHoldMock func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectLegalHoldOptions) error
var miinoPutObjectRetentionMock func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error
var mcListMock func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
var mcRemoveMock func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error
@@ -63,6 +66,10 @@ func (ac minioClientMock) putObjectLegalHold(ctx context.Context, bucketName, ob
return minioPutObjectLegalHoldMock(ctx, bucketName, objectName, opts)
}
func (ac minioClientMock) putObjectRetention(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return miinoPutObjectRetentionMock(ctx, bucketName, objectName, opts)
}
// mock functions for s3ClientMock
func (c s3ClientMock) list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
return mcListMock(ctx, opts)
@@ -704,3 +711,133 @@ func Test_putObjectLegalHold(t *testing.T) {
})
}
}
func Test_putObjectRetention(t *testing.T) {
assert := assert.New(t)
ctx := context.Background()
client := minioClientMock{}
type args struct {
bucket string
prefix string
versionID string
opts *models.PutObjectRetentionRequest
retentionFunc func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error
}
tests := []struct {
test string
args args
wantError error
}{
{
test: "Put Object retention governance",
args: args{
bucket: "buck1",
versionID: "someversion",
prefix: "folder/file.txt",
opts: &models.PutObjectRetentionRequest{
Expires: swag.String("2006-01-02T15:04:05Z"),
GovernanceBypass: false,
Mode: models.ObjectRetentionModeGovernance,
},
retentionFunc: func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return nil
},
},
wantError: nil,
},
{
test: "Put Object retention compliance",
args: args{
bucket: "buck1",
versionID: "someversion",
prefix: "folder/file.txt",
opts: &models.PutObjectRetentionRequest{
Expires: swag.String("2006-01-02T15:04:05Z"),
GovernanceBypass: false,
Mode: models.ObjectRetentionModeCompliance,
},
retentionFunc: func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return nil
},
},
wantError: nil,
},
{
test: "Empty opts should return error",
args: args{
bucket: "buck1",
versionID: "someversion",
prefix: "folder/file.txt",
opts: nil,
retentionFunc: func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return nil
},
},
wantError: errors.New("object retention options can't be nil"),
},
{
test: "Empty expire on opts should return error",
args: args{
bucket: "buck1",
versionID: "someversion",
prefix: "folder/file.txt",
opts: &models.PutObjectRetentionRequest{
Expires: nil,
GovernanceBypass: false,
Mode: models.ObjectRetentionModeCompliance,
},
retentionFunc: func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return nil
},
},
wantError: errors.New("object retention expires can't be nil"),
},
{
test: "Handle invalid expire time",
args: args{
bucket: "buck1",
versionID: "someversion",
prefix: "folder/file.txt",
opts: &models.PutObjectRetentionRequest{
Expires: swag.String("invalidtime"),
GovernanceBypass: false,
Mode: models.ObjectRetentionModeCompliance,
},
retentionFunc: func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return nil
},
},
wantError: errors.New("parsing time \"invalidtime\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \"invalidtime\" as \"2006\""),
},
{
test: "Handle error on retention func",
args: args{
bucket: "buck1",
versionID: "someversion",
prefix: "folder/file.txt",
opts: &models.PutObjectRetentionRequest{
Expires: swag.String("2006-01-02T15:04:05Z"),
GovernanceBypass: false,
Mode: models.ObjectRetentionModeCompliance,
},
retentionFunc: func(ctx context.Context, bucketName, objectName string, opts minio.PutObjectRetentionOptions) error {
return errors.New("new Error")
},
},
wantError: errors.New("new Error"),
},
}
for _, tt := range tests {
t.Run(tt.test, func(t *testing.T) {
miinoPutObjectRetentionMock = tt.args.retentionFunc
err := setObjectRetention(ctx, client, tt.args.bucket, tt.args.prefix, tt.args.versionID, tt.args.opts)
if tt.wantError != nil {
assert.Equal(err.Error(), tt.wantError.Error(), fmt.Sprintf("setObjectRetention() error: %v, wantErr: %v", err, tt.wantError))
} else {
assert.Nil(err, fmt.Sprintf("setObjectRetention() error: %v, wantErr: %v", err, tt.wantError))
}
})
}
}

View File

@@ -405,6 +405,38 @@ paths:
tags:
- UserAPI
/buckets/{bucket_name}/objects/retention:
put:
summary: Put Object's retention status
operationId: PutObjectRetention
parameters:
- name: bucket_name
in: path
required: true
type: string
- name: prefix
in: query
required: true
type: string
- name: version_id
in: query
required: true
type: string
- name: body
in: body
required: true
schema:
$ref: "#/definitions/putObjectRetentionRequest"
responses:
200:
description: A successful response.
default:
description: Generic error response.
schema:
$ref: "#/definitions/error"
tags:
- UserAPI
/buckets/{name}/set-policy:
put:
summary: Bucket Set Policy
@@ -3331,3 +3363,36 @@ definitions:
properties:
status:
$ref: "#/definitions/objectLegalHoldStatus"
objectLegalHoldStatus:
type: string
enum:
- enabled
- disabled
putObjectLegalHoldRequest:
type: object
required:
- status
properties:
status:
$ref: "#/definitions/objectLegalHoldStatus"
objectRetentionMode:
type: string
enum:
- governance
- compliance
putObjectRetentionRequest:
type: object
required:
- mode
- expires
properties:
mode:
$ref: "#/definitions/objectRetentionMode"
expires:
type: string
governance_bypass:
type: boolean