Skip to content

Commit

Permalink
Add retention mode and legal hold mode on list objects api (#312)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
  • Loading branch information
cesnietor and dvaldivia committed Oct 6, 2020
1 parent dccdfb5 commit f91346d
Show file tree
Hide file tree
Showing 8 changed files with 442 additions and 35 deletions.
27 changes: 27 additions & 0 deletions models/bucket_object.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions restapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"
"strings"
"time"

"github.com/minio/minio-go/v7/pkg/replication"

Expand Down Expand Up @@ -54,6 +55,8 @@ type MinioClient interface {
getBucketNotification(ctx context.Context, bucketName string) (config notification.Configuration, err error)
getBucketPolicy(ctx context.Context, bucketName string) (string, error)
listObjects(ctx context.Context, bucket string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo
getObjectRetention(ctx context.Context, bucketName, objectName, versionID string) (mode *minio.RetentionMode, retainUntilDate *time.Time, err error)
getObjectLegalHold(ctx context.Context, bucketName, objectName string, opts minio.GetObjectLegalHoldOptions) (status *minio.LegalHoldStatus, err error)
}

// Interface implementation
Expand Down Expand Up @@ -116,6 +119,14 @@ func (c minioClient) listObjects(ctx context.Context, bucket string, opts minio.
return c.client.ListObjects(ctx, bucket, opts)
}

func (c minioClient) getObjectRetention(ctx context.Context, bucketName, objectName, versionID string) (mode *minio.RetentionMode, retainUntilDate *time.Time, err error) {
return c.client.GetObjectRetention(ctx, bucketName, objectName, versionID)
}

func (c minioClient) getObjectLegalHold(ctx context.Context, bucketName, objectName string, opts minio.GetObjectLegalHoldOptions) (status *minio.LegalHoldStatus, err error) {
return c.client.GetObjectLegalHold(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.
Expand Down
70 changes: 70 additions & 0 deletions restapi/embedded_spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions restapi/operations/user_api/list_objects_parameters.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions restapi/operations/user_api/list_objects_urlbuilder.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 46 additions & 7 deletions restapi/user_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package restapi
import (
"context"
"fmt"
"log"
"path/filepath"
"regexp"
"strings"
Expand All @@ -29,6 +30,7 @@ import (
"github.com/minio/console/restapi/operations"
"github.com/minio/console/restapi/operations/user_api"
mc "github.com/minio/mc/cmd"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio-go/v7"
)

Expand Down Expand Up @@ -62,12 +64,16 @@ func getListObjectsResponse(session *models.Principal, params user_api.ListObjec
defer cancel()
var prefix string
var recursive bool
var withVersions bool
if params.Prefix != nil {
prefix = *params.Prefix
}
if params.Recursive != nil {
recursive = *params.Recursive
}
if params.WithVersions != nil {
withVersions = *params.WithVersions
}
// bucket request needed to proceed
if params.BucketName == "" {
return nil, prepareError(errBucketNameNotInRequest)
Expand All @@ -80,7 +86,7 @@ func getListObjectsResponse(session *models.Principal, params user_api.ListObjec
// defining the client to be used
minioClient := minioClient{client: mClient}

objs, err := listBucketObjects(ctx, minioClient, params.BucketName, prefix, recursive)
objs, err := listBucketObjects(ctx, minioClient, params.BucketName, prefix, recursive, withVersions)
if err != nil {
return nil, prepareError(err)
}
Expand All @@ -93,17 +99,50 @@ func getListObjectsResponse(session *models.Principal, params user_api.ListObjec
}

// listBucketObjects gets an array of objects in a bucket
func listBucketObjects(ctx context.Context, client MinioClient, bucketName string, prefix string, recursive bool) ([]*models.BucketObject, error) {
func listBucketObjects(ctx context.Context, client MinioClient, bucketName string, prefix string, recursive, withVersions bool) ([]*models.BucketObject, error) {
var objects []*models.BucketObject
for lsObj := range client.listObjects(ctx, bucketName, minio.ListObjectsOptions{Prefix: prefix, Recursive: recursive}) {
for lsObj := range client.listObjects(ctx, bucketName, minio.ListObjectsOptions{Prefix: prefix, Recursive: recursive, WithVersions: withVersions}) {
if lsObj.Err != nil {
return nil, lsObj.Err
}
obj := &models.BucketObject{
Name: lsObj.Key,
Size: lsObj.Size,
LastModified: lsObj.LastModified.String(),
ContentType: lsObj.ContentType,
Name: lsObj.Key,
Size: lsObj.Size,
LastModified: lsObj.LastModified.String(),
ContentType: lsObj.ContentType,
VersionID: lsObj.VersionID,
IsLatest: lsObj.IsLatest,
IsDeleteMarker: lsObj.IsDeleteMarker,
UserTags: lsObj.UserTags,
}
if !lsObj.IsDeleteMarker {
// Add Legal Hold Status if available
legalHoldStatus, err := client.getObjectLegalHold(ctx, bucketName, lsObj.Key, minio.GetObjectLegalHoldOptions{VersionID: lsObj.VersionID})
if err != nil {
errResp := minio.ToErrorResponse(probe.NewError(err).ToGoError())
if errResp.Code != "NoSuchObjectLockConfiguration" {
log.Printf("error getting legal hold status for %s : %s", lsObj.VersionID, err)
}

} else {
if legalHoldStatus != nil {
obj.LegalHoldStatus = string(*legalHoldStatus)
}
}
// Add Retention Status if available
retention, retUntilDate, err := client.getObjectRetention(ctx, bucketName, lsObj.Key, lsObj.VersionID)
if err != nil {
errResp := minio.ToErrorResponse(probe.NewError(err).ToGoError())
if errResp.Code != "NoSuchObjectLockConfiguration" {
log.Printf("error getting retention status for %s : %s", lsObj.VersionID, err)
}
} else {
if retention != nil && retUntilDate != nil {
date := *retUntilDate
obj.RetentionMode = string(*retention)
obj.RetentionUntilDate = date.String()
}
}
}
objects = append(objects, obj)
}
Expand Down

0 comments on commit f91346d

Please sign in to comment.