feat(controller): add controllwr concurrency (#1722)

* feat(controllers): add concurrency

* feat(controller): add workers flag

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore(deps): update actions/upload-artifact action to v5 (#1721)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore(deps): update github/codeql-action action to v4.31.0 (#1720)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: satisfy linter

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: use serviceaccount parsing

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* fix(deps): update module github.com/onsi/ginkgo/v2 to v2.27.1 (#1714)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore(deps): update github/codeql-action digest to ae78991 (#1719)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: use serviceaccount parsing

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: use serviceaccount parsing

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

---------

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
Oliver Bähler
2025-10-26 14:32:35 +01:00
committed by GitHub
co-authored by lnx01 lnx01 lnx01 lnx01 lnx01
parent 1267602a1b
commit 634ed49694
31 changed files with 144 additions and 65 deletions
+1 -1
View File
@@ -378,7 +378,7 @@ ko:
$(call go-install-tool,$(KO),github.com/$(KO_LOOKUP)@$(KO_VERSION))
NWA := $(LOCALBIN)/nwa
NWA_VERSION := v0.7.7
NWA_VERSION := v0.7.6
NWA_LOOKUP := B1NARY-GR0UP/nwa
nwa:
@test -s $(NWA) && $(NWA) -h | grep -q $(NWA_VERSION) || \
+2
View File
@@ -116,6 +116,7 @@ The following Values have changed key or Value:
| manager.options.annotations | object | `{}` | Additional annotations to add to the CapsuleConfiguration resource |
| manager.options.capsuleConfiguration | string | `"default"` | Change the default name of the capsule configuration name |
| manager.options.capsuleUserGroups | list | `["projectcapsule.dev"]` | Names of the groups considered as Capsule users. |
| manager.options.createConfiguration | bool | `true` | Create Configuration |
| manager.options.forceTenantPrefix | bool | `false` | Boolean, enforces the Tenant owner, during Namespace creation, to name it using the selected Tenant name as prefix, separated by a dash |
| manager.options.generateCertificates | bool | `true` | Specifies whether capsule webhooks certificates should be generated by capsule operator |
| manager.options.ignoreUserWithGroups | list | `[]` | Define groups which when found in the request of a user will be ignored by the Capsule this might be useful if you have one group where all the users are in, but you want to separate administrators from normal users with additional groups. |
@@ -124,6 +125,7 @@ The following Values have changed key or Value:
| manager.options.nodeMetadata | object | `{"forbiddenAnnotations":{"denied":[],"deniedRegex":""},"forbiddenLabels":{"denied":[],"deniedRegex":""}}` | Allows to set the forbidden metadata for the worker nodes that could be patched by a Tenant |
| manager.options.protectedNamespaceRegex | string | `""` | If specified, disallows creation of namespaces matching the passed regexp |
| manager.options.userNames | list | `[]` | Names of the users considered as Capsule users. |
| manager.options.workers | int | `1` | Workers (MaxConcurrentReconciles) is the maximum number of concurrent Reconciles which can be run (ALPHA). |
| manager.rbac.create | bool | `true` | Specifies whether RBAC resources should be created. |
| manager.rbac.existingClusterRoles | list | `[]` | Specifies further cluster roles to be added to the Capsule manager service account. |
| manager.rbac.existingRoles | list | `[]` | Specifies further cluster roles to be added to the Capsule manager service account. |
+9
View File
@@ -53,6 +53,15 @@ app.kubernetes.io/name: {{ include "capsule.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Release Annotations
*/}}
{{- define "capsule.releaseAnnotations" -}}
meta.helm.sh/release-name: {{ $.Release.Name }}
meta.helm.sh/release-namespace: {{ .Release.Namespace }}
{{- end }}
{{/*
ServiceAccount annotations
*/}}
+5
View File
@@ -64,6 +64,7 @@ spec:
- --webhook-port={{ .Values.manager.webhookPort }}
- --zap-log-level={{ default 4 .Values.manager.options.logLevel }}
- --configuration-name={{ .Values.manager.options.capsuleConfiguration }}
- --workers={{ .Values.manager.options.workers }}
{{- with .Values.manager.extraArgs }}
{{- toYaml . | nindent 8 }}
{{- end }}
@@ -74,6 +75,10 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
{{- with .Values.manager.env }}
{{- toYaml . | nindent 6 }}
{{- end }}
@@ -4,6 +4,7 @@ apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: {{ include "capsule.fullname" . }}-webhook-selfsigned
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.customAnnotations }}
@@ -17,6 +18,7 @@ apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ include "capsule.fullname" . }}-webhook-cert
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.customAnnotations }}
+1
View File
@@ -3,6 +3,7 @@
apiVersion: v1
kind: Secret
metadata:
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.customAnnotations }}
@@ -1,8 +1,9 @@
{{- if or (not $.Values.crds.exclusive) ($.Values.crds.createConfig) }}
{{- if $.Values.manager.options.createConfiguration }}
apiVersion: capsule.clastix.io/v1beta2
kind: CapsuleConfiguration
metadata:
name: default
name: {{ .Values.manager.options.capsuleConfiguration }}
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.manager.options.labels }}
@@ -14,7 +14,7 @@
{{/* Add Common Lables */}}
{{- $_ := set $p.metadata "annotations" (mergeOverwrite (default dict (get $p.metadata "annotations")) (default dict $.Values.crds.annotations)) -}}
{{- $_ := set $p.metadata "annotations" (mergeOverwrite (default dict (get $p.metadata "annotations")) (default dict $.Values.crds.annotations) (fromYaml (include "capsule.releaseAnnotations" $))) -}}
{{/* Add Keep annotation to CRDs */}}
{{- if $.Values.crds.keep }}
+1
View File
@@ -4,6 +4,7 @@ apiVersion: apps/v1
kind: DaemonSet
metadata:
name: {{ include "capsule.controllerName" . }}
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.customAnnotations }}
+1
View File
@@ -4,6 +4,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "capsule.controllerName" . }}
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.customAnnotations }}
@@ -3,6 +3,7 @@ apiVersion: v1
kind: Service
metadata:
name: {{ include "capsule.fullname" . }}-controller-manager-metrics-service
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.customAnnotations }}
@@ -6,6 +6,7 @@ apiVersion: batch/v1
kind: Job
metadata:
name: "{{ include "capsule.post-install.name" . }}"
namespace: {{ $.Release.Namespace }}
labels:
app.kubernetes.io/component: {{ include "capsule.post-install.component" . | quote }}
{{- include "capsule.labels" . | nindent 4 }}
@@ -6,6 +6,7 @@ apiVersion: batch/v1
kind: Job
metadata:
name: "{{ include "capsule.pre-delete.name" $ }}"
namespace: {{ $.Release.Namespace }}
labels:
app.kubernetes.io/component: {{ include "capsule.pre-delete.component" . | quote }}
{{- include "capsule.labels" . | nindent 4 }}
+1
View File
@@ -47,6 +47,7 @@ kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "capsule.fullname" $ }}-{{ $nr }}
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" $ | nindent 4 }}
{{- with $.Values.customAnnotations }}
@@ -4,6 +4,7 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "capsule.serviceAccountName" . }}
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- if or (.Values.serviceAccount.annotations) (.Values.customAnnotations) }}
@@ -3,6 +3,7 @@ apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: {{ include "capsule.fullname" . }}-validating-webhook-configuration
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
annotations:
@@ -3,6 +3,7 @@ apiVersion: v1
kind: Service
metadata:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ $.Release.Namespace }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.customAnnotations }}
+8
View File
@@ -338,6 +338,10 @@
"type": "string"
}
},
"createConfiguration": {
"description": "Create Configuration",
"type": "boolean"
},
"forceTenantPrefix": {
"description": "Boolean, enforces the Tenant owner, during Namespace creation, to name it using the selected Tenant name as prefix, separated by a dash",
"type": "boolean"
@@ -393,6 +397,10 @@
"userNames": {
"description": "Names of the users considered as Capsule users.",
"type": "array"
},
"workers": {
"description": "Workers (MaxConcurrentReconciles) is the maximum number of concurrent Reconciles which can be run (ALPHA).",
"type": "integer"
}
}
},
+6 -2
View File
@@ -166,12 +166,16 @@ manager:
# Additional Capsule Controller Options
options:
# -- Create Configuration
createConfiguration: true
# -- Change the default name of the capsule configuration name
capsuleConfiguration: default
# -- Additional labels to add to the CapsuleConfiguration resource
labels: {}
# -- Additional annotations to add to the CapsuleConfiguration resource
annotations: {}
# -- Change the default name of the capsule configuration name
capsuleConfiguration: default
# -- Workers (MaxConcurrentReconciles) is the maximum number of concurrent Reconciles which can be run (ALPHA).
workers: 1
# -- Set the log verbosity of the capsule with a value from 1 to 5
logLevel: '3'
# -- Names of the users considered as Capsule users.
+9 -4
View File
@@ -40,6 +40,7 @@ import (
servicelabelscontroller "github.com/projectcapsule/capsule/controllers/servicelabels"
tenantcontroller "github.com/projectcapsule/capsule/controllers/tenant"
tlscontroller "github.com/projectcapsule/capsule/controllers/tls"
utilscontroller "github.com/projectcapsule/capsule/controllers/utils"
"github.com/projectcapsule/capsule/pkg/configuration"
"github.com/projectcapsule/capsule/pkg/indexer"
"github.com/projectcapsule/capsule/pkg/metrics"
@@ -87,6 +88,8 @@ func printVersion() {
//nolint:maintidx
func main() {
controllerConfig := utilscontroller.ControllerOptions{}
var enableLeaderElection, version bool
var metricsAddr, namespace, configurationName string
@@ -95,6 +98,7 @@ func main() {
var goFlagSet goflag.FlagSet
flag.IntVar(&controllerConfig.MaxConcurrentReconciles, "workers", 1, "MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run.")
flag.IntVar(&webhookPort, "webhook-port", 9443, "The port the webhook server binds to.")
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
@@ -203,7 +207,7 @@ func main() {
Metrics: metrics.MustMakeTenantRecorder(),
Log: ctrl.Log.WithName("controllers").WithName("Tenant"),
Recorder: manager.GetEventRecorderFor("tenant-controller"),
}).SetupWithManager(manager); err != nil {
}).SetupWithManager(manager, controllerConfig); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Tenant")
os.Exit(1)
}
@@ -294,7 +298,7 @@ func main() {
os.Exit(1)
}
if err = (&pv.Controller{}).SetupWithManager(manager); err != nil {
if err = (&pv.Controller{}).SetupWithManager(manager, controllerConfig); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PersistentVolume")
os.Exit(1)
}
@@ -306,12 +310,12 @@ func main() {
os.Exit(1)
}
if err = (&resources.Global{}).SetupWithManager(manager); err != nil {
if err = (&resources.Global{}).SetupWithManager(manager, controllerConfig); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "resources.Global")
os.Exit(1)
}
if err = (&resources.Namespaced{}).SetupWithManager(manager); err != nil {
if err = (&resources.Namespaced{}).SetupWithManager(manager, controllerConfig); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "resources.Namespaced")
os.Exit(1)
}
@@ -320,6 +324,7 @@ func main() {
ctrl.Log.WithName("controllers").WithName("ResourcePools"),
manager,
manager.GetEventRecorderFor("pools-ctrl"),
controllerConfig,
); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "resourcepools")
os.Exit(1)
+31 -28
View File
@@ -12,11 +12,13 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
log2 "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/controllers/utils"
capsuleutils "github.com/projectcapsule/capsule/pkg/utils"
webhookutils "github.com/projectcapsule/capsule/pkg/webhook/utils"
)
@@ -26,6 +28,35 @@ type Controller struct {
label string
}
func (c *Controller) SetupWithManager(mgr ctrl.Manager, cfg utils.ControllerOptions) error {
label, err := capsuleutils.GetTypeLabel(&capsulev1beta2.Tenant{})
if err != nil {
return err
}
c.client = mgr.GetClient()
c.label = label
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.PersistentVolume{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
pv, ok := object.(*corev1.PersistentVolume)
if !ok {
return false
}
if pv.Spec.ClaimRef == nil {
return false
}
labels := object.GetLabels()
_, ok = labels[c.label]
return !ok
}))).
WithOptions(controller.Options{MaxConcurrentReconciles: cfg.MaxConcurrentReconciles}).
Complete(c)
}
func (c *Controller) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
log := log2.FromContext(ctx)
@@ -87,31 +118,3 @@ func (c *Controller) Reconcile(ctx context.Context, request reconcile.Request) (
return reconcile.Result{}, nil
}
func (c *Controller) SetupWithManager(mgr ctrl.Manager) error {
label, err := capsuleutils.GetTypeLabel(&capsulev1beta2.Tenant{})
if err != nil {
return err
}
c.client = mgr.GetClient()
c.label = label
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.PersistentVolume{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
pv, ok := object.(*corev1.PersistentVolume)
if !ok {
return false
}
if pv.Spec.ClaimRef == nil {
return false
}
labels := object.GetLabels()
_, ok = labels[c.label]
return !ok
}))).
Complete(c)
}
@@ -17,11 +17,13 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/controllers/utils"
"github.com/projectcapsule/capsule/pkg/api"
"github.com/projectcapsule/capsule/pkg/meta"
"github.com/projectcapsule/capsule/pkg/metrics"
@@ -35,7 +37,7 @@ type resourceClaimController struct {
recorder record.EventRecorder
}
func (r *resourceClaimController) SetupWithManager(mgr ctrl.Manager) error {
func (r *resourceClaimController) SetupWithManager(mgr ctrl.Manager, cfg utils.ControllerOptions) error {
return ctrl.NewControllerManagedBy(mgr).
For(&capsulev1beta2.ResourcePoolClaim{}).
Watches(
@@ -43,6 +45,7 @@ func (r *resourceClaimController) SetupWithManager(mgr ctrl.Manager) error {
handler.EnqueueRequestsFromMapFunc(r.claimsWithoutPoolFromNamespaces),
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
).
WithOptions(controller.Options{MaxConcurrentReconciles: cfg.MaxConcurrentReconciles}).
Complete(r)
}
+4 -2
View File
@@ -10,6 +10,7 @@ import (
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/manager"
"github.com/projectcapsule/capsule/controllers/utils"
"github.com/projectcapsule/capsule/pkg/metrics"
)
@@ -17,13 +18,14 @@ func Add(
log logr.Logger,
mgr manager.Manager,
recorder record.EventRecorder,
cfg utils.ControllerOptions,
) (err error) {
if err = (&resourcePoolController{
Client: mgr.GetClient(),
log: log.WithName("Pools"),
recorder: recorder,
metrics: metrics.MustMakeResourcePoolRecorder(),
}).SetupWithManager(mgr); err != nil {
}).SetupWithManager(mgr, cfg); err != nil {
return fmt.Errorf("unable to create pool controller: %w", err)
}
@@ -32,7 +34,7 @@ func Add(
log: log.WithName("Claims"),
recorder: recorder,
metrics: metrics.MustMakeClaimRecorder(),
}).SetupWithManager(mgr); err != nil {
}).SetupWithManager(mgr, cfg); err != nil {
return fmt.Errorf("unable to create claim controller: %w", err)
}
+4 -1
View File
@@ -20,11 +20,13 @@ import (
"k8s.io/client-go/util/retry"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
ctrlutils "github.com/projectcapsule/capsule/controllers/utils"
"github.com/projectcapsule/capsule/pkg/api"
"github.com/projectcapsule/capsule/pkg/meta"
"github.com/projectcapsule/capsule/pkg/metrics"
@@ -39,7 +41,7 @@ type resourcePoolController struct {
recorder record.EventRecorder
}
func (r *resourcePoolController) SetupWithManager(mgr ctrl.Manager) error {
func (r *resourcePoolController) SetupWithManager(mgr ctrl.Manager, cfg ctrlutils.ControllerOptions) error {
return ctrl.NewControllerManagedBy(mgr).
For(&capsulev1beta2.ResourcePool{}).
Owns(&corev1.ResourceQuota{}).
@@ -67,6 +69,7 @@ func (r *resourcePoolController) SetupWithManager(mgr ctrl.Manager) error {
return requests
}),
).
WithOptions(controller.Options{MaxConcurrentReconciles: cfg.MaxConcurrentReconciles}).
Complete(r)
}
+4 -1
View File
@@ -16,12 +16,14 @@ import (
"sigs.k8s.io/cluster-api/util/patch"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/controllers/utils"
)
type Global struct {
@@ -29,7 +31,7 @@ type Global struct {
processor Processor
}
func (r *Global) SetupWithManager(mgr ctrl.Manager) error {
func (r *Global) SetupWithManager(mgr ctrl.Manager, cfg utils.ControllerOptions) error {
r.client = mgr.GetClient()
r.processor = Processor{
client: mgr.GetClient(),
@@ -38,6 +40,7 @@ func (r *Global) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&capsulev1beta2.GlobalTenantResource{}).
Watches(&capsulev1beta2.Tenant{}, handler.EnqueueRequestsFromMapFunc(r.enqueueRequestFromTenant)).
WithOptions(controller.Options{MaxConcurrentReconciles: cfg.MaxConcurrentReconciles}).
Complete(r)
}
+4 -1
View File
@@ -14,11 +14,13 @@ import (
"sigs.k8s.io/cluster-api/util/patch"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/controllers/utils"
)
type Namespaced struct {
@@ -26,7 +28,7 @@ type Namespaced struct {
processor Processor
}
func (r *Namespaced) SetupWithManager(mgr ctrl.Manager) error {
func (r *Namespaced) SetupWithManager(mgr ctrl.Manager, cfg utils.ControllerOptions) error {
r.client = mgr.GetClient()
r.processor = Processor{
client: mgr.GetClient(),
@@ -34,6 +36,7 @@ func (r *Namespaced) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&capsulev1beta2.TenantResource{}).
WithOptions(controller.Options{MaxConcurrentReconciles: cfg.MaxConcurrentReconciles}).
Complete(r)
}
+11 -3
View File
@@ -19,11 +19,13 @@ import (
"k8s.io/client-go/util/retry"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/meta"
"github.com/projectcapsule/capsule/controllers/utils"
meta "github.com/projectcapsule/capsule/pkg/meta"
"github.com/projectcapsule/capsule/pkg/metrics"
)
@@ -36,7 +38,7 @@ type Manager struct {
RESTConfig *rest.Config
}
func (r *Manager) SetupWithManager(mgr ctrl.Manager) error {
func (r *Manager) SetupWithManager(mgr ctrl.Manager, cfg utils.ControllerOptions) error {
return ctrl.NewControllerManagedBy(mgr).
For(&capsulev1beta2.Tenant{}).
Owns(&networkingv1.NetworkPolicy{}).
@@ -44,6 +46,7 @@ func (r *Manager) SetupWithManager(mgr ctrl.Manager) error {
Owns(&corev1.ResourceQuota{}).
Owns(&rbacv1.RoleBinding{}).
Watches(&corev1.Namespace{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &capsulev1beta2.Tenant{})).
WithOptions(controller.Options{MaxConcurrentReconciles: cfg.MaxConcurrentReconciles}).
Complete(r)
}
@@ -77,12 +80,17 @@ func (r Manager) Reconcile(ctx context.Context, request ctrl.Request) (result ct
}()
// Ensuring Metadata.
if err = r.ensureMetadata(ctx, instance); err != nil {
err, updated := r.ensureMetadata(ctx, instance)
if err != nil {
err = fmt.Errorf("cannot ensure metadata: %w", err)
return result, err
}
if updated {
return result, nil
}
// Ensuring ResourceQuota
r.Log.V(4).Info("Ensuring limit resources count is updated")
+8 -10
View File
@@ -6,26 +6,24 @@ package tenant
import (
"context"
"k8s.io/apimachinery/pkg/types"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
capsuleapi "github.com/projectcapsule/capsule/pkg/api"
)
// Sets a label on the Tenant object with it's name.
func (r *Manager) ensureMetadata(ctx context.Context, tnt *capsulev1beta2.Tenant) (err error) {
func (r *Manager) ensureMetadata(ctx context.Context, tnt *capsulev1beta2.Tenant) (err error, changed bool) {
// Assign Labels
if tnt.Labels == nil {
tnt.Labels = make(map[string]string)
}
if v, ok := tnt.Labels[capsuleapi.TenantNameLabel]; ok && v == tnt.Name {
return err
if v, ok := tnt.Labels[capsuleapi.TenantNameLabel]; !ok || v != tnt.Name {
if err := r.Update(ctx, tnt); err != nil {
return err, false
}
return nil, true
}
if err := r.Update(ctx, tnt); err != nil {
return err
}
return r.Get(ctx, types.NamespacedName{Name: tnt.GetName()}, tnt)
return nil, false
}
+2 -2
View File
@@ -14,7 +14,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
capsulev1beta2 "github.com/projectcapsule/capsule/pkg/utils"
"github.com/projectcapsule/capsule/pkg/utils"
)
// pruningResources is taking care of removing the no more requested sub-resources as LimitRange, ResourceQuota or
@@ -22,7 +22,7 @@ import (
func (r *Manager) pruningResources(ctx context.Context, ns string, keys []string, obj client.Object) (err error) {
var capsuleLabel string
if capsuleLabel, err = capsulev1beta2.GetTypeLabel(obj); err != nil {
if capsuleLabel, err = utils.GetTypeLabel(obj); err != nil {
return err
}
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2020-2025 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package utils
type ControllerOptions struct {
MaxConcurrentReconciles int
}
+8 -6
View File
@@ -5,10 +5,11 @@ package utils
import (
"context"
"strings"
"os"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/authentication/serviceaccount"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -27,13 +28,14 @@ func IsCapsuleUser(ctx context.Context, req admission.Request, clt client.Client
//nolint:nestif
if sets.NewString(req.UserInfo.Groups...).Has("system:serviceaccounts") {
parts := strings.Split(req.UserInfo.Username, ":")
if len(parts) == 4 {
targetNamespace := parts[2]
namespace, name, err := serviceaccount.SplitUsername(req.UserInfo.Username)
if err == nil {
if namespace == os.Getenv("NAMESPACE") && name == os.Getenv("SERVICE_ACCOUNT") {
return false
}
tl := &capsulev1beta2.TenantList{}
if err := clt.List(ctx, tl, client.MatchingFieldsSelector{Selector: fields.OneTermEqualSelector(".status.namespaces", targetNamespace)}); err != nil {
if err := clt.List(ctx, tl, client.MatchingFieldsSelector{Selector: fields.OneTermEqualSelector(".status.namespaces", namespace)}); err != nil {
return false
}