Added bucket details inside objects listing (#1502)

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2022-02-01 21:48:58 -07:00
committed by GitHub
parent 02acb76ac9
commit 96b1d4fe85
4 changed files with 93 additions and 38 deletions

View File

@@ -45,6 +45,7 @@ import {
decodeFileName,
encodeFileName,
niceBytes,
niceBytesInt,
} from "../../../../../../common/utils";
import {
@@ -1094,27 +1095,6 @@ const ListObjects = ({
uploadPath = uploadPath.concat(currentPath);
}
// TODO: Add bucket information panel
/*
*
* subTitle={
<Fragment>
<Grid item xs={12} className={classes.bucketDetails}>
<span className={classes.detailsSpacer}>
Created:&nbsp;&nbsp;&nbsp;<strong></strong>
</span>
<span className={classes.detailsSpacer}>
Access:&nbsp;&nbsp;&nbsp;<strong></strong>
</span>
<span className={classes.detailsSpacer}>
SIZE / TOTAL OBJECTS
</span>
</Grid>
</Fragment>
}
*
* */
return (
<React.Fragment>
{shareFileModalOpen && selectedPreview && (
@@ -1178,6 +1158,38 @@ const ListObjects = ({
fullSizeBreadcrumbs
/>
}
subTitle={
<Fragment>
<Grid item xs={12} className={classes.bucketDetails}>
<span className={classes.detailsSpacer}>
Created:&nbsp;&nbsp;&nbsp;
<strong>{bucketInfo?.creation_date || ""}</strong>
</span>
<span className={classes.detailsSpacer}>
Access:&nbsp;&nbsp;&nbsp;
<strong>{bucketInfo?.access || ""}</strong>
</span>
{bucketInfo && (
<Fragment>
<span className={classes.detailsSpacer}>
{bucketInfo.size && (
<Fragment>{niceBytesInt(bucketInfo.size)}</Fragment>
)}
{bucketInfo.size && bucketInfo.objects ? " / " : ""}
{bucketInfo.objects && (
<Fragment>
{bucketInfo.objects}&nbsp;Object
{bucketInfo.objects && bucketInfo.objects !== 1
? "s"
: ""}
</Fragment>
)}
</span>
</Fragment>
)}
</Grid>
</Fragment>
}
actions={
<Fragment>
<input

View File

@@ -45,6 +45,9 @@ export interface BucketInfo {
name: string;
access: string;
definition: string;
creation_date?: string;
objects?: number;
size?: number;
}
export interface BucketList {

View File

@@ -24,6 +24,7 @@ import (
"strings"
"time"
"github.com/minio/madmin-go"
"github.com/minio/mc/cmd"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio-go/v7"
@@ -561,11 +562,19 @@ func getBucketSetPolicyResponse(session *models.Principal, bucketName string, re
// defining the client to be used
minioClient := minioClient{client: mClient}
mAdmin, err := NewMinioAdminClient(session)
if err != nil {
return nil, prepareError(err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
if err := setBucketAccessPolicy(ctx, minioClient, bucketName, *req.Access, req.Definition); err != nil {
return nil, prepareError(err)
}
// set bucket access policy
bucket, err := getBucketInfo(ctx, minioClient, bucketName)
bucket, err := getBucketInfo(ctx, minioClient, adminClient, bucketName)
if err != nil {
return nil, prepareError(err)
}
@@ -624,7 +633,7 @@ func getDeleteBucketResponse(session *models.Principal, params user_api.DeleteBu
}
// getBucketInfo return bucket information including name, policy access, size and creation date
func getBucketInfo(ctx context.Context, client MinioClient, bucketName string) (*models.Bucket, error) {
func getBucketInfo(ctx context.Context, client MinioClient, adminClient MinioAdmin, bucketName string) (*models.Bucket, error) {
var bucketAccess models.BucketAccess
policyStr, err := client.getBucketPolicy(context.Background(), bucketName)
if err != nil {
@@ -655,13 +664,28 @@ func getBucketInfo(ctx context.Context, client MinioClient, bucketName string) (
if bucketTags != nil {
bucketDetails.Tags = bucketTags.ToMap()
}
info, err := adminClient.AccountInfo(ctx)
if err != nil {
return nil, err
}
var bucketInfo madmin.BucketAccessInfo
for _, bucket := range info.Buckets {
if bucket.Name == bucketName {
bucketInfo = bucket
}
}
return &models.Bucket{
Name: &bucketName,
Access: &bucketAccess,
Definition: policyStr,
CreationDate: "", // to be implemented
Size: 0, // to be implemented
CreationDate: bucketInfo.Created.Format(time.RFC3339),
Size: int64(bucketInfo.Size),
Details: bucketDetails,
Objects: int64(bucketInfo.Objects),
}, nil
}
@@ -676,7 +700,16 @@ func getBucketInfoResponse(session *models.Principal, params user_api.BucketInfo
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient{client: mClient}
bucket, err := getBucketInfo(ctx, minioClient, params.Name)
mAdmin, err := NewMinioAdminClient(session)
if err != nil {
return nil, prepareError(err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
bucket, err := getBucketInfo(ctx, minioClient, adminClient, params.Name)
if err != nil {
return nil, prepareError(err)
}

View File

@@ -256,6 +256,7 @@ func TestBucketInfo(t *testing.T) {
assert := assert.New(t)
// mock minIO client
minClient := minioClientMock{}
adminClient := adminClientMock{}
ctx := context.Background()
function := "getBucketInfo()"
@@ -269,8 +270,9 @@ func TestBucketInfo(t *testing.T) {
outputExpected := &models.Bucket{
Name: swag.String(bucketToSet),
Access: models.NewBucketAccess(models.BucketAccessPRIVATE),
CreationDate: "", // to be implemented
Size: 0, // to be implemented
CreationDate: "0001-01-01T00:00:00Z",
Size: 0,
Objects: 0,
}
infoPolicy := `
{
@@ -307,7 +309,7 @@ func TestBucketInfo(t *testing.T) {
return mockBucketList, nil
}
bucketInfo, err := getBucketInfo(ctx, minClient, bucketToSet)
bucketInfo, err := getBucketInfo(ctx, minClient, adminClient, bucketToSet)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
@@ -315,6 +317,7 @@ func TestBucketInfo(t *testing.T) {
assert.Equal(outputExpected.Access, bucketInfo.Access)
assert.Equal(outputExpected.CreationDate, bucketInfo.CreationDate)
assert.Equal(outputExpected.Size, bucketInfo.Size)
assert.Equal(outputExpected.Objects, bucketInfo.Objects)
// Test-2: getBucketInfo() get a bucket with PUBLIC access
// mock policy for bucket csbucket with readWrite access (should return PUBLIC)
@@ -326,10 +329,11 @@ func TestBucketInfo(t *testing.T) {
outputExpected = &models.Bucket{
Name: swag.String(bucketToSet),
Access: models.NewBucketAccess(models.BucketAccessPUBLIC),
CreationDate: "", // to be implemented
Size: 0, // to be implemented
CreationDate: "0001-01-01T00:00:00Z",
Size: 0,
Objects: 0,
}
bucketInfo, err = getBucketInfo(ctx, minClient, bucketToSet)
bucketInfo, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
@@ -337,6 +341,7 @@ func TestBucketInfo(t *testing.T) {
assert.Equal(outputExpected.Access, bucketInfo.Access)
assert.Equal(outputExpected.CreationDate, bucketInfo.CreationDate)
assert.Equal(outputExpected.Size, bucketInfo.Size)
assert.Equal(outputExpected.Objects, bucketInfo.Objects)
// Test-3: getBucketInfo() get a bucket with PRIVATE access
// if bucket has a null statement, the the bucket is PRIVATE
@@ -348,10 +353,11 @@ func TestBucketInfo(t *testing.T) {
outputExpected = &models.Bucket{
Name: swag.String(bucketToSet),
Access: models.NewBucketAccess(models.BucketAccessPRIVATE),
CreationDate: "", // to be implemented
Size: 0, // to be implemented
CreationDate: "0001-01-01T00:00:00Z",
Size: 0,
Objects: 0,
}
bucketInfo, err = getBucketInfo(ctx, minClient, bucketToSet)
bucketInfo, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
@@ -359,6 +365,7 @@ func TestBucketInfo(t *testing.T) {
assert.Equal(outputExpected.Access, bucketInfo.Access)
assert.Equal(outputExpected.CreationDate, bucketInfo.CreationDate)
assert.Equal(outputExpected.Size, bucketInfo.Size)
assert.Equal(outputExpected.Objects, bucketInfo.Objects)
// Test-4: getBucketInfo() returns an error while parsing invalid policy
mockPolicy = "policyinvalid"
@@ -369,10 +376,10 @@ func TestBucketInfo(t *testing.T) {
outputExpected = &models.Bucket{
Name: swag.String(bucketToSet),
Access: models.NewBucketAccess(models.BucketAccessCUSTOM),
CreationDate: "", // to be implemented
Size: 0, // to be implemented
CreationDate: "",
Size: 0,
}
_, err = getBucketInfo(ctx, minClient, bucketToSet)
_, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet)
if assert.Error(err) {
assert.Equal("invalid character 'p' looking for beginning of value", err.Error())
}