Add Tiers improvements for Bucket Lifecycle management (#3380)

This commit is contained in:
Cesar N
2024-06-13 12:17:49 -07:00
committed by GitHub
parent 56f22a4479
commit fa32d78ff1
15 changed files with 810 additions and 103 deletions

View File

@@ -71,6 +71,7 @@ var (
minioAddTiersMock func(ctx context.Context, tier *madmin.TierConfig) error
minioRemoveTierMock func(ctx context.Context, tierName string) error
minioEditTiersMock func(ctx context.Context, tierName string, creds madmin.TierCreds) error
minioVerifyTierStatusMock func(ctx context.Context, tierName string) error
minioServiceTraceMock func(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo
@@ -121,8 +122,8 @@ func (ac AdminClientMock) speedtest(_ context.Context, _ madmin.SpeedtestOpts) (
return nil, nil
}
func (ac AdminClientMock) verifyTierStatus(_ context.Context, _ string) error {
return nil
func (ac AdminClientMock) verifyTierStatus(ctx context.Context, tier string) error {
return minioVerifyTierStatusMock(ctx, tier)
}
// mock function helpConfigKV()

View File

@@ -24,6 +24,7 @@ import (
"github.com/dustin/go-humanize"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
"github.com/minio/console/api/operations/tiering"
tieringApi "github.com/minio/console/api/operations/tiering"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
@@ -38,6 +39,13 @@ func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
}
return tieringApi.NewTiersListOK().WithPayload(tierList)
})
api.TieringTiersListNamesHandler = tiering.TiersListNamesHandlerFunc(func(params tiering.TiersListNamesParams, session *models.Principal) middleware.Responder {
tierList, err := getTiersNameResponse(session, params)
if err != nil {
return tieringApi.NewTiersListDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewTiersListNamesOK().WithPayload(tierList)
})
// add a new tiers
api.TieringAddTierHandler = tieringApi.AddTierHandlerFunc(func(params tieringApi.AddTierParams, session *models.Principal) middleware.Responder {
err := getAddTierResponse(session, params)
@@ -72,33 +80,36 @@ func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
})
}
// getNotificationEndpoints invokes admin info and returns a list of notification endpoints
// getTiers returns a list of tiers with their stats
func getTiers(ctx context.Context, client MinioAdmin) (*models.TierListResponse, error) {
tiers, err := client.listTiers(ctx)
if err != nil {
return nil, err
}
tiersInfo, err := client.tierStats(ctx)
tierStatsInfo, err := client.tierStats(ctx)
if err != nil {
return nil, err
}
tiersStatsMap := make(map[string]madmin.TierStats, len(tierStatsInfo))
for _, stat := range tierStatsInfo {
tiersStatsMap[stat.Name] = stat.Stats
}
var tiersList []*models.Tier
for _, tierData := range tiers {
// Default Tier Stats
stats := madmin.TierStats{
tierStats := madmin.TierStats{
NumObjects: 0,
NumVersions: 0,
TotalSize: 0,
}
if stats, ok := tiersStatsMap[tierData.Name]; ok {
tierStats = stats
}
status := client.verifyTierStatus(ctx, tierData.Name) == nil
// We look for the correct tier stats & set the values.
for _, stat := range tiersInfo {
if stat.Name == tierData.Name {
stats = stat.Stats
break
}
}
switch tierData.Type {
case madmin.S3:
tiersList = append(tiersList, &models.Tier{
@@ -112,11 +123,11 @@ func getTiers(ctx context.Context, client MinioAdmin) (*models.TierListResponse,
Region: tierData.S3.Region,
Secretkey: tierData.S3.SecretKey,
Storageclass: tierData.S3.StorageClass,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
Usage: humanize.IBytes(tierStats.TotalSize),
Objects: strconv.Itoa(tierStats.NumObjects),
Versions: strconv.Itoa(tierStats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
Status: status,
})
case madmin.MinIO:
tiersList = append(tiersList, &models.Tier{
@@ -129,11 +140,11 @@ func getTiers(ctx context.Context, client MinioAdmin) (*models.TierListResponse,
Prefix: tierData.MinIO.Prefix,
Region: tierData.MinIO.Region,
Secretkey: tierData.MinIO.SecretKey,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
Usage: humanize.IBytes(tierStats.TotalSize),
Objects: strconv.Itoa(tierStats.NumObjects),
Versions: strconv.Itoa(tierStats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
Status: status,
})
case madmin.GCS:
tiersList = append(tiersList, &models.Tier{
@@ -145,11 +156,11 @@ func getTiers(ctx context.Context, client MinioAdmin) (*models.TierListResponse,
Name: tierData.Name,
Prefix: tierData.GCS.Prefix,
Region: tierData.GCS.Region,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
Usage: humanize.IBytes(tierStats.TotalSize),
Objects: strconv.Itoa(tierStats.NumObjects),
Versions: strconv.Itoa(tierStats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
Status: status,
})
case madmin.Azure:
tiersList = append(tiersList, &models.Tier{
@@ -162,16 +173,16 @@ func getTiers(ctx context.Context, client MinioAdmin) (*models.TierListResponse,
Name: tierData.Name,
Prefix: tierData.Azure.Prefix,
Region: tierData.Azure.Region,
Usage: humanize.IBytes(stats.TotalSize),
Objects: strconv.Itoa(stats.NumObjects),
Versions: strconv.Itoa(stats.NumVersions),
Usage: humanize.IBytes(tierStats.TotalSize),
Objects: strconv.Itoa(tierStats.NumObjects),
Versions: strconv.Itoa(tierStats.NumVersions),
},
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
Status: status,
})
case madmin.Unsupported:
tiersList = append(tiersList, &models.Tier{
Type: models.TierTypeUnsupported,
Status: client.verifyTierStatus(ctx, tierData.Name) == nil,
Status: status,
})
}
}
@@ -200,6 +211,42 @@ func getTiersResponse(session *models.Principal, params tieringApi.TiersListPara
return tiersResp, nil
}
// getTiersNameResponse returns a response with a list of tiers' names
func getTiersNameResponse(session *models.Principal, params tieringApi.TiersListNamesParams) (*models.TiersNameListResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
// serialize output
tiersResp, err := getTiersName(ctx, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return tiersResp, nil
}
// getTiersName fetches listTiers and returns a list of the tiers' names
func getTiersName(ctx context.Context, client MinioAdmin) (*models.TiersNameListResponse, error) {
tiers, err := client.listTiers(ctx)
if err != nil {
return nil, err
}
tiersNameList := make([]string, len(tiers))
for i, tierData := range tiers {
tiersNameList[i] = tierData.Name
}
return &models.TiersNameListResponse{
Items: tiersNameList,
}, nil
}
func addTier(ctx context.Context, client MinioAdmin, params *tieringApi.AddTierParams) error {
var cfg *madmin.TierConfig
var err error

View File

@@ -36,12 +36,12 @@ func TestGetTiers(t *testing.T) {
function := "getTiers()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Test-1 : getBucketLifecycle() get list of tiers
// Test-1 : getTiers() get list of tiers
// mock lifecycle response from MinIO
returnListMock := []*madmin.TierConfig{
{
Version: "V1",
Type: madmin.TierType(0),
Type: madmin.S3,
Name: "S3 Tier",
S3: &madmin.TierS3{
Endpoint: "https://s3tier.test.com/",
@@ -53,6 +53,19 @@ func TestGetTiers(t *testing.T) {
StorageClass: "TT1",
},
},
{
Version: "V1",
Type: madmin.MinIO,
Name: "MinIO Tier",
MinIO: &madmin.TierMinIO{
Endpoint: "https://minio-endpoint.test.com/",
AccessKey: "access",
SecretKey: "secret",
Bucket: "somebucket",
Prefix: "p1",
Region: "us-east-2",
},
},
}
returnStatsMock := []madmin.TierInfo{
@@ -61,6 +74,11 @@ func TestGetTiers(t *testing.T) {
Type: "internal",
Stats: madmin.TierStats{NumObjects: 2, NumVersions: 2, TotalSize: 228915},
},
{
Name: "MinIO Tier",
Type: "internal",
Stats: madmin.TierStats{NumObjects: 10, NumVersions: 3, TotalSize: 132788},
},
{
Name: "S3 Tier",
Type: "s3",
@@ -71,7 +89,7 @@ func TestGetTiers(t *testing.T) {
expectedOutput := &models.TierListResponse{
Items: []*models.Tier{
{
Type: "S3",
Type: models.TierTypeS3,
S3: &models.TierS3{
Accesskey: "Access Key",
Secretkey: "Secret Key",
@@ -85,6 +103,23 @@ func TestGetTiers(t *testing.T) {
Objects: "0",
Versions: "0",
},
Status: false,
},
{
Type: models.TierTypeMinio,
Minio: &models.TierMinio{
Accesskey: "access",
Secretkey: "secret",
Bucket: "somebucket",
Endpoint: "https://minio-endpoint.test.com/",
Name: "MinIO Tier",
Prefix: "p1",
Region: "us-east-2",
Usage: "130 KiB",
Objects: "10",
Versions: "3",
},
Status: false,
},
},
}
@@ -97,47 +132,20 @@ func TestGetTiers(t *testing.T) {
return returnStatsMock, nil
}
minioVerifyTierStatusMock = func(_ context.Context, _ string) error {
return fmt.Errorf("someerror")
}
tiersList, err := getTiers(ctx, adminClient)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// verify length of tiers list is correct
assert.Equal(len(tiersList.Items), len(returnListMock), fmt.Sprintf("Failed on %s: length of lists is not the same", function))
for i, conf := range returnListMock {
switch conf.Type {
case madmin.TierType(0):
// S3
assert.Equal(expectedOutput.Items[i].S3.Name, conf.Name)
assert.Equal(expectedOutput.Items[i].S3.Bucket, conf.S3.Bucket)
assert.Equal(expectedOutput.Items[i].S3.Prefix, conf.S3.Prefix)
assert.Equal(expectedOutput.Items[i].S3.Accesskey, conf.S3.AccessKey)
assert.Equal(expectedOutput.Items[i].S3.Secretkey, conf.S3.SecretKey)
assert.Equal(expectedOutput.Items[i].S3.Endpoint, conf.S3.Endpoint)
assert.Equal(expectedOutput.Items[i].S3.Region, conf.S3.Region)
assert.Equal(expectedOutput.Items[i].S3.Storageclass, conf.S3.StorageClass)
case madmin.TierType(1):
// Azure
assert.Equal(expectedOutput.Items[i].Azure.Name, conf.Name)
assert.Equal(expectedOutput.Items[i].Azure.Bucket, conf.Azure.Bucket)
assert.Equal(expectedOutput.Items[i].Azure.Prefix, conf.Azure.Prefix)
assert.Equal(expectedOutput.Items[i].Azure.Accountkey, conf.Azure.AccountKey)
assert.Equal(expectedOutput.Items[i].Azure.Accountname, conf.Azure.AccountName)
assert.Equal(expectedOutput.Items[i].Azure.Endpoint, conf.Azure.Endpoint)
assert.Equal(expectedOutput.Items[i].Azure.Region, conf.Azure.Region)
case madmin.TierType(2):
// GCS
assert.Equal(expectedOutput.Items[i].Gcs.Name, conf.Name)
assert.Equal(expectedOutput.Items[i].Gcs.Bucket, conf.GCS.Bucket)
assert.Equal(expectedOutput.Items[i].Gcs.Prefix, conf.GCS.Prefix)
assert.Equal(expectedOutput.Items[i].Gcs.Creds, conf.GCS.Creds)
assert.Equal(expectedOutput.Items[i].Gcs.Endpoint, conf.GCS.Endpoint)
assert.Equal(expectedOutput.Items[i].Gcs.Region, conf.GCS.Region)
}
}
assert.Equal(expectedOutput, tiersList)
// Test-2 : getBucketLifecycle() list is empty
// Test-2 : getTiers() list is empty
returnListMockT2 := []*madmin.TierConfig{}
minioListTiersMock = func(_ context.Context) ([]*madmin.TierConfig, error) {
return returnListMockT2, nil
}
@@ -152,6 +160,78 @@ func TestGetTiers(t *testing.T) {
}
}
func TestGetTiersName(t *testing.T) {
assert := assert.New(t)
// mock minIO client
adminClient := AdminClientMock{}
function := "getTiersName()"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Test-1 : getTiersName() get list tiers' names
// mock lifecycle response from MinIO
returnListMock := []*madmin.TierConfig{
{
Version: "V1",
Type: madmin.S3,
Name: "S3 Tier",
S3: &madmin.TierS3{
Endpoint: "https://s3tier.test.com/",
AccessKey: "Access Key",
SecretKey: "Secret Key",
Bucket: "buckets3",
Prefix: "pref1",
Region: "us-west-1",
StorageClass: "TT1",
},
},
{
Version: "V1",
Type: madmin.MinIO,
Name: "MinIO Tier",
MinIO: &madmin.TierMinIO{
Endpoint: "https://minio-endpoint.test.com/",
AccessKey: "access",
SecretKey: "secret",
Bucket: "somebucket",
Prefix: "p1",
Region: "us-east-2",
},
},
}
expectedOutput := &models.TiersNameListResponse{
Items: []string{"S3 Tier", "MinIO Tier"},
}
minioListTiersMock = func(_ context.Context) ([]*madmin.TierConfig, error) {
return returnListMock, nil
}
tiersList, err := getTiersName(ctx, adminClient)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// verify length of tiers list is correct
assert.Equal(len(tiersList.Items), len(returnListMock), fmt.Sprintf("Failed on %s: length of lists is not the same", function))
assert.Equal(expectedOutput, tiersList)
// Test-2 : getTiersName() list is empty
returnListMockT2 := []*madmin.TierConfig{}
minioListTiersMock = func(_ context.Context) ([]*madmin.TierConfig, error) {
return returnListMockT2, nil
}
emptyTierList, err := getTiersName(ctx, adminClient)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
if len(emptyTierList.Items) != 0 {
t.Errorf("Failed on %s:, returned list was not empty", function)
}
}
func TestAddTier(t *testing.T) {
assert := assert.New(t)
// mock minIO client

View File

@@ -545,6 +545,29 @@ func init() {
}
}
},
"/admin/tiers/names": {
"get": {
"tags": [
"Tiering"
],
"summary": "Returns a list of tiers' names for ilm",
"operationId": "TiersListNames",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/tiersNameListResponse"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/ApiError"
}
}
}
}
},
"/admin/tiers/{name}/remove": {
"delete": {
"tags": [
@@ -8888,6 +8911,17 @@ func init() {
}
}
},
"tiersNameListResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"transitionResponse": {
"type": "object",
"properties": {
@@ -9757,6 +9791,29 @@ func init() {
}
}
},
"/admin/tiers/names": {
"get": {
"tags": [
"Tiering"
],
"summary": "Returns a list of tiers' names for ilm",
"operationId": "TiersListNames",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/tiersNameListResponse"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/ApiError"
}
}
}
}
},
"/admin/tiers/{name}/remove": {
"delete": {
"tags": [
@@ -18308,6 +18365,17 @@ func init() {
}
}
},
"tiersNameListResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"transitionResponse": {
"type": "object",
"properties": {

View File

@@ -542,6 +542,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
TieringTiersListHandler: tiering.TiersListHandlerFunc(func(params tiering.TiersListParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation tiering.TiersList has not yet been implemented")
}),
TieringTiersListNamesHandler: tiering.TiersListNamesHandlerFunc(func(params tiering.TiersListNamesParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation tiering.TiersListNames has not yet been implemented")
}),
BucketUpdateBucketLifecycleHandler: bucket.UpdateBucketLifecycleHandlerFunc(func(params bucket.UpdateBucketLifecycleParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation bucket.UpdateBucketLifecycle has not yet been implemented")
}),
@@ -931,6 +934,8 @@ type ConsoleAPI struct {
SubnetSubnetRegisterHandler subnet.SubnetRegisterHandler
// TieringTiersListHandler sets the operation handler for the tiers list operation
TieringTiersListHandler tiering.TiersListHandler
// TieringTiersListNamesHandler sets the operation handler for the tiers list names operation
TieringTiersListNamesHandler tiering.TiersListNamesHandler
// BucketUpdateBucketLifecycleHandler sets the operation handler for the update bucket lifecycle operation
BucketUpdateBucketLifecycleHandler bucket.UpdateBucketLifecycleHandler
// IdpUpdateConfigurationHandler sets the operation handler for the update configuration operation
@@ -1491,6 +1496,9 @@ func (o *ConsoleAPI) Validate() error {
if o.TieringTiersListHandler == nil {
unregistered = append(unregistered, "tiering.TiersListHandler")
}
if o.TieringTiersListNamesHandler == nil {
unregistered = append(unregistered, "tiering.TiersListNamesHandler")
}
if o.BucketUpdateBucketLifecycleHandler == nil {
unregistered = append(unregistered, "bucket.UpdateBucketLifecycleHandler")
}
@@ -2226,6 +2234,10 @@ func (o *ConsoleAPI) initHandlerCache() {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/admin/tiers"] = tiering.NewTiersList(o.context, o.TieringTiersListHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/admin/tiers/names"] = tiering.NewTiersListNames(o.context, o.TieringTiersListNamesHandler)
if o.handlers["PUT"] == nil {
o.handlers["PUT"] = make(map[string]http.Handler)
}

View File

@@ -0,0 +1,88 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 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 tiering
// 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"
)
// TiersListNamesHandlerFunc turns a function with the right signature into a tiers list names handler
type TiersListNamesHandlerFunc func(TiersListNamesParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn TiersListNamesHandlerFunc) Handle(params TiersListNamesParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// TiersListNamesHandler interface for that can handle valid tiers list names params
type TiersListNamesHandler interface {
Handle(TiersListNamesParams, *models.Principal) middleware.Responder
}
// NewTiersListNames creates a new http.Handler for the tiers list names operation
func NewTiersListNames(ctx *middleware.Context, handler TiersListNamesHandler) *TiersListNames {
return &TiersListNames{Context: ctx, Handler: handler}
}
/*
TiersListNames swagger:route GET /admin/tiers/names Tiering tiersListNames
Returns a list of tiers' names for ilm
*/
type TiersListNames struct {
Context *middleware.Context
Handler TiersListNamesHandler
}
func (o *TiersListNames) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewTiersListNamesParams()
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,63 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 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 tiering
// 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/errors"
"github.com/go-openapi/runtime/middleware"
)
// NewTiersListNamesParams creates a new TiersListNamesParams object
//
// There are no default values defined in the spec.
func NewTiersListNamesParams() TiersListNamesParams {
return TiersListNamesParams{}
}
// TiersListNamesParams contains all the bound params for the tiers list names operation
// typically these are obtained from a http.Request
//
// swagger:parameters TiersListNames
type TiersListNamesParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
}
// 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 NewTiersListNamesParams() beforehand.
func (o *TiersListNamesParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,135 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 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 tiering
// 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"
)
// TiersListNamesOKCode is the HTTP code returned for type TiersListNamesOK
const TiersListNamesOKCode int = 200
/*
TiersListNamesOK A successful response.
swagger:response tiersListNamesOK
*/
type TiersListNamesOK struct {
/*
In: Body
*/
Payload *models.TiersNameListResponse `json:"body,omitempty"`
}
// NewTiersListNamesOK creates TiersListNamesOK with default headers values
func NewTiersListNamesOK() *TiersListNamesOK {
return &TiersListNamesOK{}
}
// WithPayload adds the payload to the tiers list names o k response
func (o *TiersListNamesOK) WithPayload(payload *models.TiersNameListResponse) *TiersListNamesOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the tiers list names o k response
func (o *TiersListNamesOK) SetPayload(payload *models.TiersNameListResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *TiersListNamesOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*
TiersListNamesDefault Generic error response.
swagger:response tiersListNamesDefault
*/
type TiersListNamesDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.APIError `json:"body,omitempty"`
}
// NewTiersListNamesDefault creates TiersListNamesDefault with default headers values
func NewTiersListNamesDefault(code int) *TiersListNamesDefault {
if code <= 0 {
code = 500
}
return &TiersListNamesDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the tiers list names default response
func (o *TiersListNamesDefault) WithStatusCode(code int) *TiersListNamesDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the tiers list names default response
func (o *TiersListNamesDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the tiers list names default response
func (o *TiersListNamesDefault) WithPayload(payload *models.APIError) *TiersListNamesDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the tiers list names default response
func (o *TiersListNamesDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}
// WriteResponse to the client
func (o *TiersListNamesDefault) 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,104 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 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 tiering
// 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"
)
// TiersListNamesURL generates an URL for the tiers list names operation
type TiersListNamesURL struct {
_basePath string
}
// 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 *TiersListNamesURL) WithBasePath(bp string) *TiersListNamesURL {
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 *TiersListNamesURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *TiersListNamesURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/admin/tiers/names"
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *TiersListNamesURL) 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 *TiersListNamesURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *TiersListNamesURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on TiersListNamesURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on TiersListNamesURL")
}
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 *TiersListNamesURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -0,0 +1,67 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2023 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 (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// TiersNameListResponse tiers name list response
//
// swagger:model tiersNameListResponse
type TiersNameListResponse struct {
// items
Items []string `json:"items"`
}
// Validate validates this tiers name list response
func (m *TiersNameListResponse) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this tiers name list response based on context it is used
func (m *TiersNameListResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *TiersNameListResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *TiersNameListResponse) UnmarshalBinary(b []byte) error {
var res TiersNameListResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -2705,6 +2705,22 @@ paths:
tags:
- Tiering
/admin/tiers/names:
get:
summary: Returns a list of tiers' names for ilm
operationId: TiersListNames
responses:
200:
description: A successful response.
schema:
$ref: "#/definitions/tiersNameListResponse"
default:
description: Generic error response.
schema:
$ref: "#/definitions/ApiError"
tags:
- Tiering
/admin/tiers/{type}/{name}:
get:
summary: Get Tier
@@ -5598,6 +5614,14 @@ definitions:
items:
$ref: "#/definitions/tier"
tiersNameListResponse:
type: object
properties:
items:
type: array
items:
type: string
tierCredentialsRequest:
type: object
properties:

View File

@@ -1195,6 +1195,10 @@ export interface TierListResponse {
items?: Tier[];
}
export interface TiersNameListResponse {
items?: string[];
}
export interface TierCredentialsRequest {
access_key?: string;
secret_key?: string;
@@ -4496,6 +4500,24 @@ export class Api<
...params,
}),
/**
* No description
*
* @tags Tiering
* @name TiersListNames
* @summary Returns a list of tiers' names for ilm
* @request GET:/admin/tiers/names
* @secure
*/
tiersListNames: (params: RequestParams = {}) =>
this.request<TiersNameListResponse, ApiError>({
path: `/admin/tiers/names`,
method: "GET",
secure: true,
format: "json",
...params,
}),
/**
* No description
*

View File

@@ -33,7 +33,7 @@ import {
} from "mds";
import { useSelector } from "react-redux";
import { api } from "api";
import { BucketVersioningResponse, Tier } from "api/consoleApi";
import { BucketVersioningResponse } from "api/consoleApi";
import { errorToHandler } from "api/errors";
import { modalStyleUtils } from "../../Common/FormComponents/common/styleLibrary";
import { selDistSet, setModalErrorSnackMessage } from "../../../../systemSlice";
@@ -88,16 +88,13 @@ const AddLifecycleModal = ({
useEffect(() => {
if (loadingTiers) {
api.admin
.tiersList()
.tiersListNames()
.then((res) => {
const tiersList: Tier[] | null = get(res.data, "items", []);
const tiersList: string[] | null = get(res.data, "items", []);
if (tiersList !== null && tiersList.length >= 1) {
const objList = tiersList.map((tier: Tier) => {
const tierType = tier.type;
const value = get(tier, `${tierType}.name`, "");
return { label: value, value: value };
const objList = tiersList.map((tierName: string) => {
return { label: tierName, value: tierName };
});
setTiersList(objList);
@@ -107,11 +104,12 @@ const AddLifecycleModal = ({
}
setLoadingTiers(false);
})
.catch(() => {
.catch((err) => {
setLoadingTiers(false);
dispatch(setModalErrorSnackMessage(errorToHandler(err.error)));
});
}
}, [loadingTiers]);
}, [dispatch, loadingTiers]);
useEffect(() => {
let valid = true;

View File

@@ -30,10 +30,13 @@ import {
Switch,
} from "mds";
import { api } from "api";
import { ApiError, Tier } from "api/consoleApi";
import { ApiError } from "api/consoleApi";
import { modalStyleUtils } from "../../Common/FormComponents/common/styleLibrary";
import { ITiersDropDown, LifeCycleItem } from "../types";
import { setErrorSnackMessage } from "../../../../systemSlice";
import {
setErrorSnackMessage,
setModalErrorSnackMessage,
} from "../../../../systemSlice";
import { useAppDispatch } from "../../../../store";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import QueryMultiSelector from "../../Common/FormComponents/QueryMultiSelector/QueryMultiSelector";
@@ -81,16 +84,13 @@ const EditLifecycleConfiguration = ({
useEffect(() => {
if (loadingTiers) {
api.admin
.tiersList()
.tiersListNames()
.then((res) => {
const tiersList: Tier[] | null = get(res.data, "items", []);
const tiersList: string[] | null = get(res.data, "items", []);
if (tiersList !== null && tiersList.length >= 1) {
const objList = tiersList.map((tier: Tier) => {
const tierType = tier.type;
const value = get(tier, `${tierType}.name`, "");
return { label: value, value: value };
const objList = tiersList.map((tierName: string) => {
return { label: tierName, value: tierName };
});
setTiersList(objList);
if (objList.length > 0) {
@@ -99,11 +99,12 @@ const EditLifecycleConfiguration = ({
}
setLoadingTiers(false);
})
.catch(() => {
.catch((err) => {
setLoadingTiers(false);
dispatch(setModalErrorSnackMessage(errorToHandler(err.error)));
});
}
}, [loadingTiers, lifecycleRule.transition?.storage_class]);
}, [dispatch, loadingTiers, lifecycleRule.transition?.storage_class]);
useEffect(() => {
let valid = true;

View File

@@ -36,7 +36,7 @@ import { ITiersDropDown } from "../types";
import { setModalErrorSnackMessage } from "../../../../systemSlice";
import { useAppDispatch } from "../../../../store";
import { api } from "api";
import { MultiLifecycleResult, Tier } from "api/consoleApi";
import { MultiLifecycleResult } from "api/consoleApi";
import { errorToHandler } from "api/errors";
interface IBulkReplicationModal {
@@ -72,16 +72,13 @@ const AddBulkReplicationModal = ({
useEffect(() => {
if (loadingTiers) {
api.admin
.tiersList()
.tiersListNames()
.then((res) => {
const tiersList: Tier[] | null = get(res.data, "items", []);
const tiersList: string[] | null = get(res.data, "items", []);
if (tiersList !== null && tiersList.length >= 1) {
const objList = tiersList.map((tier: Tier) => {
const tierType = tier.type;
const value = get(tier, `${tierType}.name`, "");
return { label: value, value: value };
const objList = tiersList.map((tierName: string) => {
return { label: tierName, value: tierName };
});
setTiersList(objList);
@@ -96,7 +93,7 @@ const AddBulkReplicationModal = ({
dispatch(setModalErrorSnackMessage(errorToHandler(err.error)));
});
}
}, [loadingTiers, dispatch]);
}, [dispatch, loadingTiers]);
useEffect(() => {
let valid = true;