Merge pull request #24247 from sdminonne/service_loadbalancer_quotas
Automatic merge from submit-queue Adding loadBalancer services to quota system @derekwaynecarr follow up to #22154.
This commit is contained in:
		@@ -153,6 +153,7 @@ var standardQuotaResources = sets.NewString(
 | 
				
			|||||||
	string(ResourcePersistentVolumeClaims),
 | 
						string(ResourcePersistentVolumeClaims),
 | 
				
			||||||
	string(ResourceConfigMaps),
 | 
						string(ResourceConfigMaps),
 | 
				
			||||||
	string(ResourceServicesNodePorts),
 | 
						string(ResourceServicesNodePorts),
 | 
				
			||||||
 | 
						string(ResourceServicesLoadBalancers),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsStandardQuotaResourceName returns true if the resource is known to
 | 
					// IsStandardQuotaResourceName returns true if the resource is known to
 | 
				
			||||||
@@ -192,6 +193,7 @@ var integerResources = sets.NewString(
 | 
				
			|||||||
	string(ResourceConfigMaps),
 | 
						string(ResourceConfigMaps),
 | 
				
			||||||
	string(ResourcePersistentVolumeClaims),
 | 
						string(ResourcePersistentVolumeClaims),
 | 
				
			||||||
	string(ResourceServicesNodePorts),
 | 
						string(ResourceServicesNodePorts),
 | 
				
			||||||
 | 
						string(ResourceServicesLoadBalancers),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsIntegerResourceName returns true if the resource is measured in integer values
 | 
					// IsIntegerResourceName returns true if the resource is measured in integer values
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2218,6 +2218,8 @@ const (
 | 
				
			|||||||
	ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims"
 | 
						ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims"
 | 
				
			||||||
	// ResourceServicesNodePorts, number
 | 
						// ResourceServicesNodePorts, number
 | 
				
			||||||
	ResourceServicesNodePorts ResourceName = "services.nodeports"
 | 
						ResourceServicesNodePorts ResourceName = "services.nodeports"
 | 
				
			||||||
 | 
						// ResourceServicesLoadBalancers, number
 | 
				
			||||||
 | 
						ResourceServicesLoadBalancers ResourceName = "services.loadbalancers"
 | 
				
			||||||
	// CPU request, in cores. (500m = .5 cores)
 | 
						// CPU request, in cores. (500m = .5 cores)
 | 
				
			||||||
	ResourceRequestsCPU ResourceName = "requests.cpu"
 | 
						ResourceRequestsCPU ResourceName = "requests.cpu"
 | 
				
			||||||
	// Memory request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
 | 
						// Memory request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2676,6 +2676,8 @@ const (
 | 
				
			|||||||
	ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims"
 | 
						ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims"
 | 
				
			||||||
	// ResourceServicesNodePorts, number
 | 
						// ResourceServicesNodePorts, number
 | 
				
			||||||
	ResourceServicesNodePorts ResourceName = "services.nodeports"
 | 
						ResourceServicesNodePorts ResourceName = "services.nodeports"
 | 
				
			||||||
 | 
						// ResourceServicesLoadBalancers, number
 | 
				
			||||||
 | 
						ResourceServicesLoadBalancers ResourceName = "services.loadbalancers"
 | 
				
			||||||
	// CPU request, in cores. (500m = .5 cores)
 | 
						// CPU request, in cores. (500m = .5 cores)
 | 
				
			||||||
	ResourceCPURequest ResourceName = "cpu.request"
 | 
						ResourceCPURequest ResourceName = "cpu.request"
 | 
				
			||||||
	// CPU limit, in cores. (500m = .5 cores)
 | 
						// CPU limit, in cores. (500m = .5 cores)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -215,7 +215,7 @@ func ServiceReplenishmentUpdateFunc(options *ReplenishmentControllerOptions) fun
 | 
				
			|||||||
	return func(oldObj, newObj interface{}) {
 | 
						return func(oldObj, newObj interface{}) {
 | 
				
			||||||
		oldService := oldObj.(*api.Service)
 | 
							oldService := oldObj.(*api.Service)
 | 
				
			||||||
		newService := newObj.(*api.Service)
 | 
							newService := newObj.(*api.Service)
 | 
				
			||||||
		if core.QuotaServiceType(oldService) && !core.QuotaServiceType(newService) {
 | 
							if core.QuotaServiceType(oldService) || core.QuotaServiceType(newService) {
 | 
				
			||||||
			options.ReplenishmentFunc(options.GroupKind, newService.Namespace, newService)
 | 
								options.ReplenishmentFunc(options.GroupKind, newService.Namespace, newService)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,7 @@ func NewServiceEvaluator(kubeClient clientset.Interface) quota.Evaluator {
 | 
				
			|||||||
	allResources := []api.ResourceName{
 | 
						allResources := []api.ResourceName{
 | 
				
			||||||
		api.ResourceServices,
 | 
							api.ResourceServices,
 | 
				
			||||||
		api.ResourceServicesNodePorts,
 | 
							api.ResourceServicesNodePorts,
 | 
				
			||||||
 | 
							api.ResourceServicesLoadBalancers,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &generic.GenericEvaluator{
 | 
						return &generic.GenericEvaluator{
 | 
				
			||||||
		Name:              "Evaluator.Service",
 | 
							Name:              "Evaluator.Service",
 | 
				
			||||||
@@ -56,6 +57,8 @@ func ServiceUsageFunc(object runtime.Object) api.ResourceList {
 | 
				
			|||||||
		switch service.Spec.Type {
 | 
							switch service.Spec.Type {
 | 
				
			||||||
		case api.ServiceTypeNodePort:
 | 
							case api.ServiceTypeNodePort:
 | 
				
			||||||
			result[api.ResourceServicesNodePorts] = resource.MustParse("1")
 | 
								result[api.ResourceServicesNodePorts] = resource.MustParse("1")
 | 
				
			||||||
 | 
							case api.ServiceTypeLoadBalancer:
 | 
				
			||||||
 | 
								result[api.ResourceServicesLoadBalancers] = resource.MustParse("1")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
@@ -64,7 +67,7 @@ func ServiceUsageFunc(object runtime.Object) api.ResourceList {
 | 
				
			|||||||
// QuotaServiceType returns true if the service type is eligible to track against a quota
 | 
					// QuotaServiceType returns true if the service type is eligible to track against a quota
 | 
				
			||||||
func QuotaServiceType(service *api.Service) bool {
 | 
					func QuotaServiceType(service *api.Service) bool {
 | 
				
			||||||
	switch service.Spec.Type {
 | 
						switch service.Spec.Type {
 | 
				
			||||||
	case api.ServiceTypeNodePort:
 | 
						case api.ServiceTypeNodePort, api.ServiceTypeLoadBalancer:
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -220,6 +220,96 @@ var _ = framework.KubeDescribe("ResourceQuota", func() {
 | 
				
			|||||||
		Expect(err).NotTo(HaveOccurred())
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						It("should create a ResourceQuota and capture the life of a loadBalancer service.", func() {
 | 
				
			||||||
 | 
							By("Creating a ResourceQuota")
 | 
				
			||||||
 | 
							quotaName := "test-quota"
 | 
				
			||||||
 | 
							resourceQuota := newTestResourceQuota(quotaName)
 | 
				
			||||||
 | 
							resourceQuota, err := createResourceQuota(f.Client, f.Namespace.Name, resourceQuota)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Ensuring resource quota status is calculated")
 | 
				
			||||||
 | 
							usedResources := api.ResourceList{}
 | 
				
			||||||
 | 
							usedResources[api.ResourceQuotas] = resource.MustParse("1")
 | 
				
			||||||
 | 
							err = waitForResourceQuota(f.Client, f.Namespace.Name, quotaName, usedResources)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Creating a loadBalancer type Service")
 | 
				
			||||||
 | 
							service := newTestServiceForQuota("test-service", api.ServiceTypeLoadBalancer)
 | 
				
			||||||
 | 
							service, err = f.Client.Services(f.Namespace.Name).Create(service)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Ensuring resource quota status captures service creation")
 | 
				
			||||||
 | 
							usedResources = api.ResourceList{}
 | 
				
			||||||
 | 
							usedResources[api.ResourceQuotas] = resource.MustParse("1")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServices] = resource.MustParse("1")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServicesLoadBalancers] = resource.MustParse("1")
 | 
				
			||||||
 | 
							err = waitForResourceQuota(f.Client, f.Namespace.Name, quotaName, usedResources)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Deleting a Service")
 | 
				
			||||||
 | 
							err = f.Client.Services(f.Namespace.Name).Delete(service.Name)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Ensuring resource quota status released usage")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServices] = resource.MustParse("0")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServicesLoadBalancers] = resource.MustParse("0")
 | 
				
			||||||
 | 
							err = waitForResourceQuota(f.Client, f.Namespace.Name, quotaName, usedResources)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						It("should create a ResourceQuota and capture the life of a nodePort service updated to loadBalancer.", func() {
 | 
				
			||||||
 | 
							By("Creating a ResourceQuota")
 | 
				
			||||||
 | 
							quotaName := "test-quota"
 | 
				
			||||||
 | 
							resourceQuota := newTestResourceQuota(quotaName)
 | 
				
			||||||
 | 
							resourceQuota, err := createResourceQuota(f.Client, f.Namespace.Name, resourceQuota)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Ensuring resource quota status is calculated")
 | 
				
			||||||
 | 
							usedResources := api.ResourceList{}
 | 
				
			||||||
 | 
							usedResources[api.ResourceQuotas] = resource.MustParse("1")
 | 
				
			||||||
 | 
							err = waitForResourceQuota(f.Client, f.Namespace.Name, quotaName, usedResources)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Creating a nodePort type Service")
 | 
				
			||||||
 | 
							service := newTestServiceForQuota("test-service", api.ServiceTypeNodePort)
 | 
				
			||||||
 | 
							service, err = f.Client.Services(f.Namespace.Name).Create(service)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Ensuring resource quota status captures service creation")
 | 
				
			||||||
 | 
							usedResources = api.ResourceList{}
 | 
				
			||||||
 | 
							usedResources[api.ResourceQuotas] = resource.MustParse("1")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServices] = resource.MustParse("1")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServicesLoadBalancers] = resource.MustParse("0")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServicesNodePorts] = resource.MustParse("1")
 | 
				
			||||||
 | 
							err = waitForResourceQuota(f.Client, f.Namespace.Name, quotaName, usedResources)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Updating the service type to loadBalancer")
 | 
				
			||||||
 | 
							service.Spec.Type = api.ServiceTypeLoadBalancer
 | 
				
			||||||
 | 
							service.Spec.Ports[0].NodePort = 0
 | 
				
			||||||
 | 
							_, err = f.Client.Services(f.Namespace.Name).Update(service)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Checking resource quota status capture service update")
 | 
				
			||||||
 | 
							usedResources = api.ResourceList{}
 | 
				
			||||||
 | 
							usedResources[api.ResourceQuotas] = resource.MustParse("1")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServices] = resource.MustParse("1")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServicesLoadBalancers] = resource.MustParse("1")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServicesNodePorts] = resource.MustParse("0")
 | 
				
			||||||
 | 
							err = waitForResourceQuota(f.Client, f.Namespace.Name, quotaName, usedResources)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Deleting a Service")
 | 
				
			||||||
 | 
							err = f.Client.Services(f.Namespace.Name).Delete(service.Name)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							By("Ensuring resource quota status released usage")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServices] = resource.MustParse("0")
 | 
				
			||||||
 | 
							usedResources[api.ResourceServicesLoadBalancers] = resource.MustParse("0")
 | 
				
			||||||
 | 
							err = waitForResourceQuota(f.Client, f.Namespace.Name, quotaName, usedResources)
 | 
				
			||||||
 | 
							Expect(err).NotTo(HaveOccurred())
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	It("should create a ResourceQuota and capture the life of a pod.", func() {
 | 
						It("should create a ResourceQuota and capture the life of a pod.", func() {
 | 
				
			||||||
		By("Creating a ResourceQuota")
 | 
							By("Creating a ResourceQuota")
 | 
				
			||||||
		quotaName := "test-quota"
 | 
							quotaName := "test-quota"
 | 
				
			||||||
@@ -578,6 +668,7 @@ func newTestResourceQuota(name string) *api.ResourceQuota {
 | 
				
			|||||||
	hard[api.ResourcePods] = resource.MustParse("5")
 | 
						hard[api.ResourcePods] = resource.MustParse("5")
 | 
				
			||||||
	hard[api.ResourceServices] = resource.MustParse("10")
 | 
						hard[api.ResourceServices] = resource.MustParse("10")
 | 
				
			||||||
	hard[api.ResourceServicesNodePorts] = resource.MustParse("1")
 | 
						hard[api.ResourceServicesNodePorts] = resource.MustParse("1")
 | 
				
			||||||
 | 
						hard[api.ResourceServicesLoadBalancers] = resource.MustParse("1")
 | 
				
			||||||
	hard[api.ResourceReplicationControllers] = resource.MustParse("10")
 | 
						hard[api.ResourceReplicationControllers] = resource.MustParse("10")
 | 
				
			||||||
	hard[api.ResourceQuotas] = resource.MustParse("1")
 | 
						hard[api.ResourceQuotas] = resource.MustParse("1")
 | 
				
			||||||
	hard[api.ResourceCPU] = resource.MustParse("1")
 | 
						hard[api.ResourceCPU] = resource.MustParse("1")
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user