Skip to content
This repository was archived by the owner on Apr 17, 2025. It is now read-only.

Commit cbc9fda

Browse files
committed
Import HRQ into HNC (disabled by default)
This implementation of Hierarchical Resource Quotas (HRQs) is based on the implementation from the GKE Hierarchy Controller. It's not a straight import since the GKE version was deployed as a separate workload, but I've made minimal adaptations to get it to fit into HNC. Tested: This has only been _very_ lightly tested in HNC so far. I've imported all the integ tests and E2E tests, and they all pass, but I certainly wouldn't recommend that anyone use it just yet (all existing e2e tests pass too). The default manifest includes the HRQ CRD and permissions but nothing else (notably, the HRQ webhooks), and one feature - the periodic resync of HRQ usages - is not yet implemented (I'll do that in a followup PR).
1 parent c566204 commit cbc9fda

30 files changed

+4124
-18
lines changed

Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ manifests: controller-gen
173173
${KUSTOMIZE} edit add resource ../config/crd
174174
${KUSTOMIZE} build manifests/ -o manifests/crds.yaml
175175
@cd manifests && \
176-
for variant in default-cc default-cm nowebhooks-cc ha-webhooks-cc ; do \
176+
for variant in default-cc default-cm nowebhooks-cc ha-webhooks-cc hrq ; do \
177177
echo "Building $${variant} manifest"; \
178178
rm kustomization.yaml; \
179179
touch kustomization.yaml && \
@@ -242,9 +242,13 @@ deploy-ha: docker-push kubectl manifests
242242
-kubectl -n hnc-system delete deployment --all
243243
kubectl apply -f manifests/ha.yaml
244244

245-
ha-deploy-watch-ha:
245+
deploy-watch-ha:
246246
kubectl logs -n hnc-system --follow deployment/hnc-controller-manager-ha manager
247247

248+
deploy-hrq: docker-push kubectl manifests
249+
-kubectl -n hnc-system delete deployment --all
250+
kubectl apply -f manifests/hrq.yaml
251+
248252
# No need to delete the HA configuration here - everything "extra" that it
249253
# installs is in hnc-system, which gets deleted by the default manifest.
250254
undeploy: manifests
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package v1alpha2
2+
3+
import (
4+
corev1 "k8s.io/api/core/v1"
5+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6+
)
7+
8+
const (
9+
// HRQLabelCleanup is added to resources created by HRQ (specifically the RQ
10+
// singletons) for easier cleanup later by a selector.
11+
HRQLabelCleanup = MetaGroup + "/hrq"
12+
13+
// NonPropagateAnnotation is added to RQ singletons so that they are not
14+
// overwritten by ancestors.
15+
NonPropagateAnnotation = AnnotationPropagatePrefix + "/none"
16+
17+
// EventCannotWriteResourceQuota is for events when the reconcilers cannot
18+
// write ResourceQuota from an HRQ. Usually it means the HRQ has invalid
19+
// resource quota types. The error message will point to the HRQ object.
20+
EventCannotWriteResourceQuota string = "CannotWriteResourceQuota"
21+
)
22+
23+
// HierarchicalResourceQuotaSpec defines the desired hard limits to enforce for
24+
// a namespace and descendant namespaces
25+
type HierarchicalResourceQuotaSpec struct {
26+
// Hard is the set of desired hard limits for each named resource
27+
// +optional
28+
Hard corev1.ResourceList `json:"hard,omitempty"`
29+
}
30+
31+
// HierarchicalResourceQuotaStatus defines the enforced hard limits and observed
32+
// use for a namespace and descendant namespaces
33+
type HierarchicalResourceQuotaStatus struct {
34+
// Hard is the set of enforced hard limits for each named resource
35+
// +optional
36+
Hard corev1.ResourceList `json:"hard,omitempty"`
37+
// Used is the current observed total usage of the resource in the namespace
38+
// and its descendant namespaces.
39+
// +optional
40+
Used corev1.ResourceList `json:"used,omitempty"`
41+
}
42+
43+
// +kubebuilder:object:root=true
44+
// +kubebuilder:resource:path=hierarchicalresourcequotas,shortName=hrq,scope=Namespaced
45+
46+
// HierarchicalResourceQuota sets aggregate quota restrictions enforced for a
47+
// namespace and descendant namespaces
48+
type HierarchicalResourceQuota struct {
49+
metav1.TypeMeta `json:",inline"`
50+
metav1.ObjectMeta `json:"metadata,omitempty"`
51+
52+
// Spec defines the desired quota
53+
Spec HierarchicalResourceQuotaSpec `json:"spec,omitempty"`
54+
// Status defines the actual enforced quota and its current usage
55+
Status HierarchicalResourceQuotaStatus `json:"status,omitempty"`
56+
}
57+
58+
// +kubebuilder:object:root=true
59+
60+
// HierarchicalResourceQuotaList contains a list of HierarchicalResourceQuota
61+
type HierarchicalResourceQuotaList struct {
62+
metav1.TypeMeta `json:",inline"`
63+
metav1.ListMeta `json:"metadata,omitempty"`
64+
Items []HierarchicalResourceQuota `json:"items"`
65+
}
66+
67+
func init() {
68+
SchemeBuilder.Register(&HierarchicalResourceQuota{}, &HierarchicalResourceQuotaList{})
69+
}

api/v1alpha2/zz_generated.deepcopy.go

Lines changed: 111 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/manager/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ var (
7373
managedNamespaceAnnots arrayArg
7474
includedNamespacesRegex string
7575
webhooksOnly bool
76+
enableHRQ bool
7677
)
7778

7879
// init preloads some global vars before main() starts. Since this is the top-level module, I'm not
@@ -149,6 +150,7 @@ func parseFlags() {
149150
flag.Var(&managedNamespaceLabels, "managed-namespace-label", "A regex indicating the labels on namespaces that are managed by HNC. These labels may only be set via the HierarchyConfiguration object. All regexes are implictly wrapped by \"^...$\". This argument can be specified multiple times. See the user guide for more information.")
150151
flag.Var(&managedNamespaceAnnots, "managed-namespace-annotation", "A regex indicating the annotations on namespaces that are managed by HNC. These annotations may only be set via the HierarchyConfiguration object. All regexes are implictly wrapped by \"^...$\". This argument can be specified multiple times. See the user guide for more information.")
151152
flag.BoolVar(&webhooksOnly, "webhooks-only", false, "Disables the controllers so HNC can be run in HA webhook mode")
153+
flag.BoolVar(&enableHRQ, "enable-hrq", false, "Enables hierarchical resource quotas")
152154
flag.Parse()
153155

154156
// Assign the array args to the configuration variables after the args are parsed.
@@ -303,6 +305,7 @@ func startControllers(mgr ctrl.Manager, certsReady chan struct{}) {
303305
NoWebhooks: noWebhooks,
304306
MaxReconciles: maxReconciles,
305307
ReadOnly: webhooksOnly,
308+
HRQ: enableHRQ,
306309
}
307310
setup.Create(setupLog, mgr, f, opts)
308311

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.8.0
7+
creationTimestamp: null
8+
name: hierarchicalresourcequotas.hnc.x-k8s.io
9+
spec:
10+
group: hnc.x-k8s.io
11+
names:
12+
kind: HierarchicalResourceQuota
13+
listKind: HierarchicalResourceQuotaList
14+
plural: hierarchicalresourcequotas
15+
shortNames:
16+
- hrq
17+
singular: hierarchicalresourcequota
18+
scope: Namespaced
19+
versions:
20+
- name: v1alpha2
21+
schema:
22+
openAPIV3Schema:
23+
description: HierarchicalResourceQuota sets aggregate quota restrictions enforced
24+
for a namespace and descendant namespaces
25+
properties:
26+
apiVersion:
27+
description: 'APIVersion defines the versioned schema of this representation
28+
of an object. Servers should convert recognized schemas to the latest
29+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
30+
type: string
31+
kind:
32+
description: 'Kind is a string value representing the REST resource this
33+
object represents. Servers may infer this from the endpoint the client
34+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
35+
type: string
36+
metadata:
37+
type: object
38+
spec:
39+
description: Spec defines the desired quota
40+
properties:
41+
hard:
42+
additionalProperties:
43+
anyOf:
44+
- type: integer
45+
- type: string
46+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
47+
x-kubernetes-int-or-string: true
48+
description: Hard is the set of desired hard limits for each named
49+
resource
50+
type: object
51+
type: object
52+
status:
53+
description: Status defines the actual enforced quota and its current
54+
usage
55+
properties:
56+
hard:
57+
additionalProperties:
58+
anyOf:
59+
- type: integer
60+
- type: string
61+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
62+
x-kubernetes-int-or-string: true
63+
description: Hard is the set of enforced hard limits for each named
64+
resource
65+
type: object
66+
used:
67+
additionalProperties:
68+
anyOf:
69+
- type: integer
70+
- type: string
71+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
72+
x-kubernetes-int-or-string: true
73+
description: Used is the current observed total usage of the resource
74+
in the namespace and its descendant namespaces.
75+
type: object
76+
type: object
77+
type: object
78+
served: true
79+
storage: true
80+
status:
81+
acceptedNames:
82+
kind: ""
83+
plural: ""
84+
conditions: []
85+
storedVersions: []

config/crd/kustomization.yaml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ resources:
55
- bases/hnc.x-k8s.io_hierarchyconfigurations.yaml
66
- bases/hnc.x-k8s.io_hncconfigurations.yaml
77
- bases/hnc.x-k8s.io_subnamespaceanchors.yaml
8+
- bases/hnc.x-k8s.io_hierarchicalresourcequotas.yaml
89
# +kubebuilder:scaffold:crdkustomizeresource
910

1011
patchesStrategicMerge:
@@ -16,11 +17,6 @@ patchesStrategicMerge:
1617
# - patches/webhook_in_subnamespaceanchors.yaml
1718
# +kubebuilder:scaffold:crdkustomizewebhookpatch
1819

19-
# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
20-
# patches here are for enabling the CA injection for each CRD
21-
#- patches/cainjection_in_hierarchies.yaml
22-
# +kubebuilder:scaffold:crdkustomizecainjectionpatch
23-
2420
# the following config is for teaching kustomize how to do kustomization for CRDs.
2521
configurations:
2622
- kustomizeconfig.yaml

config/rbac/role.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ metadata:
55
creationTimestamp: null
66
name: manager-role
77
rules:
8+
- apiGroups:
9+
- ""
10+
resources:
11+
- resourcequotas
12+
verbs:
13+
- create
14+
- delete
15+
- get
16+
- list
17+
- patch
18+
- update
19+
- watch
820
- apiGroups:
921
- '*'
1022
resources:
@@ -21,6 +33,26 @@ rules:
2133
- patch
2234
- update
2335
- watch
36+
- apiGroups:
37+
- hnc.x-k8s.io
38+
resources:
39+
- hierarchicalresourcequotas
40+
verbs:
41+
- create
42+
- delete
43+
- get
44+
- list
45+
- patch
46+
- update
47+
- watch
48+
- apiGroups:
49+
- hnc.x-k8s.io
50+
resources:
51+
- hierarchicalresourcequotas/status
52+
verbs:
53+
- get
54+
- patch
55+
- update
2456
- apiGroups:
2557
- hnc.x-k8s.io
2658
resources:

config/variants/hrq/README

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This is identical to default_cc (and should probably use that as a base in the
2+
future) except that it enables hierarchical resource quotas (HRQ).

0 commit comments

Comments
 (0)