diff --git a/api/admin_client_mock.go b/api/admin_client_mock.go
index 91e1b98dc2..0036b7a633 100644
--- a/api/admin_client_mock.go
+++ b/api/admin_client_mock.go
@@ -66,11 +66,12 @@ var (
deleteSiteReplicationInfoMock func(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error)
getSiteReplicationStatus func(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error)
- minioListTiersMock func(ctx context.Context) ([]*madmin.TierConfig, error)
- minioTierStatsMock func(ctx context.Context) ([]madmin.TierInfo, error)
- 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
+ minioListTiersMock func(ctx context.Context) ([]*madmin.TierConfig, error)
+ minioTierStatsMock func(ctx context.Context) ([]madmin.TierInfo, error)
+ 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()
diff --git a/api/admin_tiers.go b/api/admin_tiers.go
index 5c13cb36cf..b662d2b35f 100644
--- a/api/admin_tiers.go
+++ b/api/admin_tiers.go
@@ -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,
}
-
- // We look for the correct tier stats & set the values.
- for _, stat := range tiersInfo {
- if stat.Name == tierData.Name {
- stats = stat.Stats
- break
- }
+ if stats, ok := tiersStatsMap[tierData.Name]; ok {
+ tierStats = stats
}
+
+ status := client.verifyTierStatus(ctx, tierData.Name) == nil
+
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
diff --git a/api/admin_tiers_test.go b/api/admin_tiers_test.go
index 12cdb7c283..791a4e35dd 100644
--- a/api/admin_tiers_test.go
+++ b/api/admin_tiers_test.go
@@ -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)
- }
- }
-
- // Test-2 : getBucketLifecycle() list is empty
- returnListMockT2 := []*madmin.TierConfig{}
+ assert.Equal(expectedOutput, tiersList)
+ // 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
diff --git a/api/embedded_spec.go b/api/embedded_spec.go
index 2a9083d84b..de48e606a0 100644
--- a/api/embedded_spec.go
+++ b/api/embedded_spec.go
@@ -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": {
diff --git a/api/operations/console_api.go b/api/operations/console_api.go
index b5ed8f7b52..f4bab978e9 100644
--- a/api/operations/console_api.go
+++ b/api/operations/console_api.go
@@ -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)
}
diff --git a/api/operations/tiering/tiers_list_names.go b/api/operations/tiering/tiers_list_names.go
new file mode 100644
index 0000000000..2e4203949d
--- /dev/null
+++ b/api/operations/tiering/tiers_list_names.go
@@ -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 .
+//
+
+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)
+
+}
diff --git a/api/operations/tiering/tiers_list_names_parameters.go b/api/operations/tiering/tiers_list_names_parameters.go
new file mode 100644
index 0000000000..7ab9445b85
--- /dev/null
+++ b/api/operations/tiering/tiers_list_names_parameters.go
@@ -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 .
+//
+
+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
+}
diff --git a/api/operations/tiering/tiers_list_names_responses.go b/api/operations/tiering/tiers_list_names_responses.go
new file mode 100644
index 0000000000..0f30b084c1
--- /dev/null
+++ b/api/operations/tiering/tiers_list_names_responses.go
@@ -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 .
+//
+
+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
+ }
+ }
+}
diff --git a/api/operations/tiering/tiers_list_names_urlbuilder.go b/api/operations/tiering/tiers_list_names_urlbuilder.go
new file mode 100644
index 0000000000..287badaf75
--- /dev/null
+++ b/api/operations/tiering/tiers_list_names_urlbuilder.go
@@ -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 .
+//
+
+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()
+}
diff --git a/models/tiers_name_list_response.go b/models/tiers_name_list_response.go
new file mode 100644
index 0000000000..8ff1359a07
--- /dev/null
+++ b/models/tiers_name_list_response.go
@@ -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 .
+//
+
+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
+}
diff --git a/swagger.yml b/swagger.yml
index 457944ce61..bec05df4b7 100644
--- a/swagger.yml
+++ b/swagger.yml
@@ -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
@@ -2769,7 +2785,7 @@ paths:
- Tiering
/admin/tiers/{name}/remove:
delete:
- summary: Remove Tier
+ summary: Remove Tier
operationId: RemoveTier
parameters:
- name: name
@@ -2784,7 +2800,7 @@ paths:
schema:
$ref: "#/definitions/ApiError"
tags:
- - Tiering
+ - Tiering
/nodes:
get:
@@ -5598,6 +5614,14 @@ definitions:
items:
$ref: "#/definitions/tier"
+ tiersNameListResponse:
+ type: object
+ properties:
+ items:
+ type: array
+ items:
+ type: string
+
tierCredentialsRequest:
type: object
properties:
diff --git a/web-app/src/api/consoleApi.ts b/web-app/src/api/consoleApi.ts
index 93d3c345d2..4abfd23ed1 100644
--- a/web-app/src/api/consoleApi.ts
+++ b/web-app/src/api/consoleApi.ts
@@ -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({
+ path: `/admin/tiers/names`,
+ method: "GET",
+ secure: true,
+ format: "json",
+ ...params,
+ }),
+
/**
* No description
*
diff --git a/web-app/src/screens/Console/Buckets/BucketDetails/AddLifecycleModal.tsx b/web-app/src/screens/Console/Buckets/BucketDetails/AddLifecycleModal.tsx
index 83955f6840..b4c17b8d12 100644
--- a/web-app/src/screens/Console/Buckets/BucketDetails/AddLifecycleModal.tsx
+++ b/web-app/src/screens/Console/Buckets/BucketDetails/AddLifecycleModal.tsx
@@ -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;
diff --git a/web-app/src/screens/Console/Buckets/BucketDetails/EditLifecycleConfiguration.tsx b/web-app/src/screens/Console/Buckets/BucketDetails/EditLifecycleConfiguration.tsx
index 62cfbf662c..3046e12f95 100644
--- a/web-app/src/screens/Console/Buckets/BucketDetails/EditLifecycleConfiguration.tsx
+++ b/web-app/src/screens/Console/Buckets/BucketDetails/EditLifecycleConfiguration.tsx
@@ -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;
diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/BulkLifecycleModal.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/BulkLifecycleModal.tsx
index f7c739185d..cad0893911 100644
--- a/web-app/src/screens/Console/Buckets/ListBuckets/BulkLifecycleModal.tsx
+++ b/web-app/src/screens/Console/Buckets/ListBuckets/BulkLifecycleModal.tsx
@@ -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;