From 06eb45fb75b81473027128a2f81a4b68bee26a04 Mon Sep 17 00:00:00 2001 From: derekwaynecarr Date: Wed, 8 Apr 2015 17:03:56 -0400 Subject: [PATCH] ResourceQuota add object count support for secret and volume claims --- docs/resource_quota_admin.md | 2 + examples/resourcequota/resource-quota.json | 4 +- .../resourcequota/v1beta3/resource-quota.json | 4 +- pkg/api/helpers.go | 2 + pkg/api/types.go | 4 ++ pkg/api/v1beta1/types.go | 4 ++ pkg/api/v1beta2/types.go | 4 ++ pkg/api/v1beta3/types.go | 4 ++ .../resource_quota_controller.go | 13 ++++++ .../pkg/admission/resourcequota/admission.go | 2 + .../admission/resourcequota/admission_test.go | 44 +++++++++++++++++++ 11 files changed, 85 insertions(+), 2 deletions(-) diff --git a/docs/resource_quota_admin.md b/docs/resource_quota_admin.md index 7e87b152486..def166c5c83 100644 --- a/docs/resource_quota_admin.md +++ b/docs/resource_quota_admin.md @@ -25,6 +25,8 @@ are supported: | services | Total number of services | | replicationcontrollers | Total number of replication controllers | | resourcequotas | Total number of resource quotas | +| secrets | Total number of secrets | +| persistentvolumeclaims | Total number of persistent volume claims | For example, `pods` quota counts and enforces a maximum on the number of `pods` created in a single namespace. diff --git a/examples/resourcequota/resource-quota.json b/examples/resourcequota/resource-quota.json index 7d0c40aefb9..ea7394ce748 100644 --- a/examples/resourcequota/resource-quota.json +++ b/examples/resourcequota/resource-quota.json @@ -10,6 +10,8 @@ "services": "5", "replicationcontrollers":"20", "resourcequotas":"1", - }, + "secrets":"10", + "persistentvolumeclaims":"10" + } } } diff --git a/examples/resourcequota/v1beta3/resource-quota.json b/examples/resourcequota/v1beta3/resource-quota.json index d4b0cb1b76c..c062eb82e6f 100644 --- a/examples/resourcequota/v1beta3/resource-quota.json +++ b/examples/resourcequota/v1beta3/resource-quota.json @@ -11,7 +11,9 @@ "pods": "10", "services": "5", "replicationcontrollers":"20", - "resourcequotas":"1" + "resourcequotas":"1", + "secrets":"10", + "persistentvolumeclaims":"10" } } } diff --git a/pkg/api/helpers.go b/pkg/api/helpers.go index 06e3e785f6e..1c64fb02a1c 100644 --- a/pkg/api/helpers.go +++ b/pkg/api/helpers.go @@ -80,6 +80,8 @@ var standardResources = util.NewStringSet( string(ResourceQuotas), string(ResourceServices), string(ResourceReplicationControllers), + string(ResourceSecrets), + string(ResourcePersistentVolumeClaims), string(ResourceStorage)) func IsStandardResourceName(str string) bool { diff --git a/pkg/api/types.go b/pkg/api/types.go index d1852bb7e25..6dc455f7bb3 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -1705,6 +1705,10 @@ const ( ResourceReplicationControllers ResourceName = "replicationcontrollers" // ResourceQuotas, number ResourceQuotas ResourceName = "resourcequotas" + // ResourceSecrets, number + ResourceSecrets ResourceName = "secrets" + // ResourcePersistentVolumeClaims, number + ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims" ) // ResourceQuotaSpec defines the desired hard limits to enforce for Quota diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index 5a69bb9ae09..493d59eedeb 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -1503,6 +1503,10 @@ const ( ResourceReplicationControllers ResourceName = "replicationcontrollers" // ResourceQuotas, number ResourceQuotas ResourceName = "resourcequotas" + // ResourceSecrets, number + ResourceSecrets ResourceName = "secrets" + // ResourcePersistentVolumeClaims, number + ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims" ) // ResourceQuotaSpec defines the desired hard limits to enforce for Quota diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index 1a6f9ad0428..14fab56566e 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -1578,6 +1578,10 @@ const ( ResourceReplicationControllers ResourceName = "replicationcontrollers" // ResourceQuotas, number ResourceQuotas ResourceName = "resourcequotas" + // ResourceSecrets, number + ResourceSecrets ResourceName = "secrets" + // ResourcePersistentVolumeClaims, number + ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims" ) // ResourceQuotaSpec defines the desired hard limits to enforce for Quota diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index bca59d206b3..f9ecda57586 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -1606,6 +1606,10 @@ const ( ResourceReplicationControllers ResourceName = "replicationcontrollers" // ResourceQuotas, number ResourceQuotas ResourceName = "resourcequotas" + // ResourceSecrets, number + ResourceSecrets ResourceName = "secrets" + // ResourcePersistentVolumeClaims, number + ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims" ) // ResourceQuotaSpec defines the desired hard limits to enforce for Quota diff --git a/pkg/resourcequota/resource_quota_controller.go b/pkg/resourcequota/resource_quota_controller.go index fb4189848e8..8998773bb15 100644 --- a/pkg/resourcequota/resource_quota_controller.go +++ b/pkg/resourcequota/resource_quota_controller.go @@ -23,6 +23,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/golang/glog" @@ -199,6 +200,18 @@ func (rm *ResourceQuotaManager) syncResourceQuota(quota api.ResourceQuota) (err return err } value = resource.NewQuantity(int64(len(items.Items)), resource.DecimalSI) + case api.ResourceSecrets: + items, err := rm.kubeClient.Secrets(usage.Namespace).List(labels.Everything(), fields.Everything()) + if err != nil { + return err + } + value = resource.NewQuantity(int64(len(items.Items)), resource.DecimalSI) + case api.ResourcePersistentVolumeClaims: + items, err := rm.kubeClient.PersistentVolumeClaims(usage.Namespace).List(labels.Everything(), fields.Everything()) + if err != nil { + return err + } + value = resource.NewQuantity(int64(len(items.Items)), resource.DecimalSI) } // ignore fields we do not understand (assume another controller is tracking it) diff --git a/plugin/pkg/admission/resourcequota/admission.go b/plugin/pkg/admission/resourcequota/admission.go index 092832e15a7..2b2808df693 100644 --- a/plugin/pkg/admission/resourcequota/admission.go +++ b/plugin/pkg/admission/resourcequota/admission.go @@ -62,6 +62,8 @@ var resourceToResourceName = map[string]api.ResourceName{ "services": api.ResourceServices, "replicationControllers": api.ResourceReplicationControllers, "resourceQuotas": api.ResourceQuotas, + "secrets": api.ResourceSecrets, + "persistentVolumeClaims": api.ResourcePersistentVolumeClaims, } func (q *quota) Admit(a admission.Attributes) (err error) { diff --git a/plugin/pkg/admission/resourcequota/admission_test.go b/plugin/pkg/admission/resourcequota/admission_test.go index 2b8e9e881c0..29265fc6867 100644 --- a/plugin/pkg/admission/resourcequota/admission_test.go +++ b/plugin/pkg/admission/resourcequota/admission_test.go @@ -355,3 +355,47 @@ func TestExceedUsageReplicationControllers(t *testing.T) { t.Errorf("Expected error for exceeding hard limits") } } + +func TestExceedUsageSecrets(t *testing.T) { + namespace := "default" + client := testclient.NewSimpleFake(&api.SecretList{ + Items: []api.Secret{ + { + ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace}, + }, + }, + }) + status := &api.ResourceQuotaStatus{ + Hard: api.ResourceList{}, + Used: api.ResourceList{}, + } + r := api.ResourceSecrets + status.Hard[r] = resource.MustParse("1") + status.Used[r] = resource.MustParse("1") + _, err := IncrementUsage(admission.NewAttributesRecord(&api.Secret{}, "Secret", namespace, "secrets", "CREATE"), status, client) + if err == nil { + t.Errorf("Expected error for exceeding hard limits") + } +} + +func TestExceedUsagePersistentVolumeClaims(t *testing.T) { + namespace := "default" + client := testclient.NewSimpleFake(&api.PersistentVolumeClaimList{ + Items: []api.PersistentVolumeClaim{ + { + ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace}, + }, + }, + }) + status := &api.ResourceQuotaStatus{ + Hard: api.ResourceList{}, + Used: api.ResourceList{}, + } + r := api.ResourcePersistentVolumeClaims + status.Hard[r] = resource.MustParse("1") + status.Used[r] = resource.MustParse("1") + _, err := IncrementUsage(admission.NewAttributesRecord(&api.PersistentVolumeClaim{}, "PersistentVolumeClaim", namespace, "persistentVolumeClaims", "CREATE"), status, client) + if err == nil { + t.Errorf("Expected error for exceeding hard limits") + } +}