From fc70d9c9e3de6fe9138f0fc790a12b0abe676260 Mon Sep 17 00:00:00 2001 From: Jonathan King Date: Thu, 15 Feb 2024 09:56:48 -0500 Subject: [PATCH] overrides: Add resource request/limit overrides (PROJQUAY-6254) - Allow user to specify resource limits and requests per deployment --- apis/quay/v1/quayregistry_types.go | 43 ++++++++++++++++ apis/quay/v1/zz_generated.deepcopy.go | 34 +++++++++++++ bundle/manifests/quayregistries.crd.yaml | 25 ++++++++++ .../bases/quay.redhat.com_quayregistries.yaml | 25 ++++++++++ e2e/resource_overrides/00-assert.yaml | 50 +++++++++++++++++++ .../00-create-quay-registry.yaml | 36 +++++++++++++ pkg/middleware/middleware.go | 10 ++++ 7 files changed, 223 insertions(+) create mode 100644 e2e/resource_overrides/00-assert.yaml create mode 100644 e2e/resource_overrides/00-create-quay-registry.yaml diff --git a/apis/quay/v1/quayregistry_types.go b/apis/quay/v1/quayregistry_types.go index bde0d8db9..aebf69fc8 100644 --- a/apis/quay/v1/quayregistry_types.go +++ b/apis/quay/v1/quayregistry_types.go @@ -92,6 +92,14 @@ var supportsEnvOverride = []ComponentKind{ ComponentRedis, } +var supportsResourceOverrides = []ComponentKind{ + ComponentQuay, + ComponentClair, + ComponentMirror, + ComponentPostgres, + ComponentClairPostgres, +} + var supportsReplicasOverride = []ComponentKind{ ComponentClair, ComponentMirror, @@ -142,6 +150,13 @@ type Override struct { Affinity *corev1.Affinity `json:"affinity,omitempty"` Labels map[string]string `json:"labels,omitempty"` Annotations map[string]string `json:"annotations,omitempty"` + Resources *Resources `json:"resources,omitempty"` +} + +// Resources describes the resource limits and requests for a component. +type Resources struct { + Limits corev1.ResourceList `json:"limits,omitempty"` + Requests corev1.ResourceList `json:"requests,omitempty"` } type ConditionType string @@ -491,6 +506,7 @@ func ValidateOverrides(quay *QuayRegistry) error { hasaffinity := hasAffinity(component) hasvolume := component.Overrides.VolumeSize != nil hasreplicas := component.Overrides.Replicas != nil + hasresources := component.Overrides.Resources != nil hasenvvar := len(component.Overrides.Env) > 0 hasoverride := hasaffinity || hasvolume || hasenvvar || hasreplicas @@ -534,6 +550,13 @@ func ValidateOverrides(quay *QuayRegistry) error { component.Kind, ) } + + if hasresources && !ComponentSupportsOverride(component.Kind, "resources") { + return fmt.Errorf( + "component %s does not support resources overrides", + component.Kind, + ) + } } return nil @@ -713,6 +736,8 @@ func ComponentSupportsOverride(component ComponentKind, override string) bool { components = supportsReplicasOverride case "affinity": components = supportsAffinityOverride + case "resources": + components = supportsResourceOverrides } for _, cmp := range components { @@ -762,6 +787,24 @@ func GetVolumeSizeOverrideForComponent( return } +// GetResourceOverridesForComponent returns the resource overrides set by the user for the +// provided component. Returns nil if not set. +func GetResourceOverridesForComponent( + quay *QuayRegistry, kind ComponentKind, +) (resources *Resources) { + for _, component := range quay.Spec.Components { + if component.Kind != kind { + continue + } + + if component.Overrides != nil && component.Overrides.Resources != nil { + resources = component.Overrides.Resources + } + return + } + return +} + // GetAffinityForComponent returns affinity overrides for the provided component // if they are present, nil otherwise func GetAffinityForComponent(quay *QuayRegistry, kind ComponentKind) (affinity *corev1.Affinity) { diff --git a/apis/quay/v1/zz_generated.deepcopy.go b/apis/quay/v1/zz_generated.deepcopy.go index 02dfce18d..5fc31b1db 100644 --- a/apis/quay/v1/zz_generated.deepcopy.go +++ b/apis/quay/v1/zz_generated.deepcopy.go @@ -101,6 +101,11 @@ func (in *Override) DeepCopyInto(out *Override) { (*out)[key] = val } } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new(Resources) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Override. @@ -215,3 +220,32 @@ func (in *QuayRegistryStatus) DeepCopy() *QuayRegistryStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + if in.Limits != nil { + in, out := &in.Limits, &out.Limits + *out = make(corev1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Requests != nil { + in, out := &in.Requests, &out.Requests + *out = make(corev1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} diff --git a/bundle/manifests/quayregistries.crd.yaml b/bundle/manifests/quayregistries.crd.yaml index c5fdeabd4..5ba9b61da 100644 --- a/bundle/manifests/quayregistries.crd.yaml +++ b/bundle/manifests/quayregistries.crd.yaml @@ -1108,6 +1108,31 @@ spec: replicas: format: int32 type: integer + resources: + description: Resources describes the resource limits and + requests for a component. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object volumeSize: anyOf: - type: integer diff --git a/config/crd/bases/quay.redhat.com_quayregistries.yaml b/config/crd/bases/quay.redhat.com_quayregistries.yaml index c5fdeabd4..5ba9b61da 100644 --- a/config/crd/bases/quay.redhat.com_quayregistries.yaml +++ b/config/crd/bases/quay.redhat.com_quayregistries.yaml @@ -1108,6 +1108,31 @@ spec: replicas: format: int32 type: integer + resources: + description: Resources describes the resource limits and + requests for a component. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object volumeSize: anyOf: - type: integer diff --git a/e2e/resource_overrides/00-assert.yaml b/e2e/resource_overrides/00-assert.yaml new file mode 100644 index 000000000..5f8801e5d --- /dev/null +++ b/e2e/resource_overrides/00-assert.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: skynet-quay-app +spec: + template: + spec: + containers: + - name: quay-app + resources: + limits: + cpu: 100m + memory: 100Mi + requests: + cpu: 100m + memory: 100Mi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: skynet-quay-database +spec: + template: + spec: + containers: + - name: postgres + resources: + limits: + cpu: 200m + memory: 200Mi + requests: + cpu: 200m + memory: 200Mi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: skynet-clair-app +spec: + template: + spec: + containers: + - name: clair-app + resources: + limits: + cpu: 300m + memory: 300Mi + requests: + cpu: 300m + memory: 300Mi diff --git a/e2e/resource_overrides/00-create-quay-registry.yaml b/e2e/resource_overrides/00-create-quay-registry.yaml new file mode 100644 index 000000000..29f26c7b3 --- /dev/null +++ b/e2e/resource_overrides/00-create-quay-registry.yaml @@ -0,0 +1,36 @@ +apiVersion: quay.redhat.com/v1 +kind: QuayRegistry +metadata: + name: skynet +spec: + components: + - kind: quay + managed: true + overrides: + resources: + limits: + cpu: 100m + memory: 100Mi + requests: + cpu: 100m + memory: 100Mi + - kind: postgres + managed: true + overrides: + resources: + limits: + cpu: 200m + memory: 200Mi + requests: + cpu: 200m + memory: 200Mi + - kind: clair + managed: true + overrides: + resources: + limits: + cpu: 300m + memory: 300Mi + requests: + cpu: 300m + memory: 300Mi diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index 09ed3ed19..6a05a4f5e 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -156,6 +156,16 @@ func Process(quay *v1.QuayRegistry, qctx *quaycontext.QuayRegistryContext, obj c } } + if oresources := v1.GetResourceOverridesForComponent(quay, kind); oresources != nil { + ref := &dep.Spec.Template.Spec.Containers[0] + if oresources.Requests != nil { + ref.Resources.Requests = oresources.Requests + } + if oresources.Limits != nil { + ref.Resources.Limits = oresources.Limits + } + } + if oannot := v1.GetAnnotationsOverrideForComponent(quay, kind); oannot != nil { if dep.Annotations == nil { dep.Annotations = map[string]string{}