API Resource Quota return all storage classes if no quota is set for a namespace (#560)

This commit is contained in:
Daniel Valdivia
2021-01-18 13:16:30 -08:00
committed by GitHub
parent 2305c0563a
commit 5e3f9acff9
4 changed files with 181 additions and 107 deletions

File diff suppressed because one or more lines are too long

View File

@@ -20,6 +20,7 @@ import (
"context"
v1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
@@ -29,6 +30,8 @@ import (
// that are used within this project.
type K8sClientI interface {
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)
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
@@ -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) {
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)
}

View File

@@ -18,6 +18,9 @@ package restapi
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/api/errors"
"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) {
resourceQuota, err := client.getResourceQuota(ctx, namespace, resourcequota, metav1.GetOptions{})
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
}
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)
if err != nil {
return nil, prepareError(err)
}
return resourceQuota, nil
}

View File

@@ -5,6 +5,8 @@ import (
"reflect"
"testing"
storagev1 "k8s.io/api/storage/v1"
"errors"
"github.com/minio/console/models"
@@ -16,12 +18,24 @@ import (
type k8sClientMock struct{}
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
func (c k8sClientMock) getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error) {
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) {
mockHardResourceQuota := v1.ResourceList{
"storage": resource.MustParse("1000"),