API Resource Quota return all storage classes if no quota is set for a namespace (#560)
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
)
|
)
|
||||||
@@ -29,6 +30,8 @@ import (
|
|||||||
// that are used within this project.
|
// that are used within this project.
|
||||||
type K8sClientI interface {
|
type K8sClientI interface {
|
||||||
getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error)
|
getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error)
|
||||||
|
getNamespace(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Namespace, error)
|
||||||
|
getStorageClasses(ctx context.Context, opts metav1.ListOptions) (*storagev1.StorageClassList, error)
|
||||||
getSecret(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*v1.Secret, error)
|
getSecret(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*v1.Secret, error)
|
||||||
getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error)
|
getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error)
|
||||||
deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||||
@@ -66,3 +69,11 @@ func (c *k8sClient) deleteSecret(ctx context.Context, namespace string, name str
|
|||||||
func (c *k8sClient) createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
func (c *k8sClient) createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||||
return c.client.CoreV1().Secrets(namespace).Create(ctx, secret, opts)
|
return c.client.CoreV1().Secrets(namespace).Create(ctx, secret, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *k8sClient) getNamespace(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Namespace, error) {
|
||||||
|
return c.client.CoreV1().Namespaces().Get(ctx, name, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *k8sClient) getStorageClasses(ctx context.Context, opts metav1.ListOptions) (*storagev1.StorageClassList, error) {
|
||||||
|
return c.client.StorageV1().StorageClasses().List(ctx, opts)
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ package restapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
|
||||||
"github.com/minio/console/cluster"
|
"github.com/minio/console/cluster"
|
||||||
|
|
||||||
@@ -43,6 +46,30 @@ func registerResourceQuotaHandlers(api *operations.ConsoleAPI) {
|
|||||||
func getResourceQuota(ctx context.Context, client K8sClientI, namespace, resourcequota string) (*models.ResourceQuota, error) {
|
func getResourceQuota(ctx context.Context, client K8sClientI, namespace, resourcequota string) (*models.ResourceQuota, error) {
|
||||||
resourceQuota, err := client.getResourceQuota(ctx, namespace, resourcequota, metav1.GetOptions{})
|
resourceQuota, err := client.getResourceQuota(ctx, namespace, resourcequota, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// if there's no resource quotas
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
// validate if at least the namespace is valid, if it is, return all storage classes with max capacity
|
||||||
|
_, err := client.getNamespace(ctx, namespace, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
storageClasses, err := client.getStorageClasses(ctx, metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rq := models.ResourceQuota{Name: resourceQuota.Name}
|
||||||
|
for _, sc := range storageClasses.Items {
|
||||||
|
// Create Resource element with hard limit maxed out
|
||||||
|
name := fmt.Sprintf("%s.storageclass.storage.k8s.io/requests.storage", sc.Name)
|
||||||
|
element := models.ResourceQuotaElement{
|
||||||
|
Name: name,
|
||||||
|
Hard: 9223372036854775807,
|
||||||
|
}
|
||||||
|
rq.Elements = append(rq.Elements, &element)
|
||||||
|
}
|
||||||
|
return &rq, nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rq := models.ResourceQuota{Name: resourceQuota.Name}
|
rq := models.ResourceQuota{Name: resourceQuota.Name}
|
||||||
@@ -78,7 +105,6 @@ func getResourceQuotaResponse(session *models.Principal, params admin_api.GetRes
|
|||||||
resourceQuota, err := getResourceQuota(ctx, k8sClient, params.Namespace, params.ResourceQuotaName)
|
resourceQuota, err := getResourceQuota(ctx, k8sClient, params.Namespace, params.ResourceQuotaName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, prepareError(err)
|
return nil, prepareError(err)
|
||||||
|
|
||||||
}
|
}
|
||||||
return resourceQuota, nil
|
return resourceQuota, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/minio/console/models"
|
"github.com/minio/console/models"
|
||||||
@@ -16,12 +18,24 @@ import (
|
|||||||
type k8sClientMock struct{}
|
type k8sClientMock struct{}
|
||||||
|
|
||||||
var k8sclientGetResourceQuotaMock func(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error)
|
var k8sclientGetResourceQuotaMock func(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error)
|
||||||
|
var k8sclientGetNameSpaceMock func(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Namespace, error)
|
||||||
|
var k8sclientStorageClassesMock func(ctx context.Context, opts metav1.ListOptions) (*storagev1.StorageClassList, error)
|
||||||
|
|
||||||
// mock functions
|
// mock functions
|
||||||
func (c k8sClientMock) getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error) {
|
func (c k8sClientMock) getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error) {
|
||||||
return k8sclientGetResourceQuotaMock(ctx, namespace, resource, opts)
|
return k8sclientGetResourceQuotaMock(ctx, namespace, resource, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mock functions
|
||||||
|
func (c k8sClientMock) getNamespace(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Namespace, error) {
|
||||||
|
return k8sclientGetNameSpaceMock(ctx, name, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mock functions
|
||||||
|
func (c k8sClientMock) getStorageClasses(ctx context.Context, opts metav1.ListOptions) (*storagev1.StorageClassList, error) {
|
||||||
|
return k8sclientStorageClassesMock(ctx, opts)
|
||||||
|
}
|
||||||
|
|
||||||
func Test_ResourceQuota(t *testing.T) {
|
func Test_ResourceQuota(t *testing.T) {
|
||||||
mockHardResourceQuota := v1.ResourceList{
|
mockHardResourceQuota := v1.ResourceList{
|
||||||
"storage": resource.MustParse("1000"),
|
"storage": resource.MustParse("1000"),
|
||||||
|
|||||||
Reference in New Issue
Block a user