From 43bd2491aea348ecb5a46b20a8aabe35a3200545 Mon Sep 17 00:00:00 2001 From: Dario Tranchitella Date: Fri, 23 Dec 2022 10:23:29 +0100 Subject: [PATCH] refactor(api): switching to v1beta2 as storage version --- api/v1alpha1/capsuleconfiguration_webhook.go | 21 +++ api/v1alpha1/tenant_func.go | 8 -- api/v1beta1/namespace_options.go | 16 +-- api/v1beta1/tenant_webhook.go | 21 +++ api/v1beta2/capsuleconfiguration_types.go | 5 +- api/v1beta2/tenant_annotations.go | 17 +++ api/v1beta2/tenant_conversion_hub.go | 31 ++--- controllers/servicelabels/abstract.go | 10 +- controllers/tenant/limitranges.go | 8 +- controllers/tenant/manager.go | 14 +- controllers/tenant/namespaces.go | 31 ++--- controllers/tenant/networkpolicies.go | 8 +- controllers/tenant/resourcequotas.go | 14 +- controllers/tenant/resourcequotas_quota.go | 10 +- controllers/tenant/rolebindings.go | 18 +-- controllers/tenant/utils.go | 4 +- main.go | 12 +- .../api/annotations.go | 15 +-- pkg/configuration/client.go | 126 ++++-------------- pkg/configuration/configuration.go | 11 +- pkg/indexer/indexer.go | 2 - pkg/indexer/namespace/namespaces.go | 4 +- pkg/indexer/tenant/owner.go | 8 +- pkg/utils/node_selector.go | 4 +- pkg/utils/owner.go | 4 +- pkg/webhook/ingress/utils.go | 6 +- pkg/webhook/ingress/validate_class.go | 8 +- pkg/webhook/ingress/validate_collision.go | 10 +- pkg/webhook/ingress/validate_hostnames.go | 8 +- pkg/webhook/ingress/validate_wildcard.go | 7 +- pkg/webhook/namespace/errors.go | 12 +- pkg/webhook/namespace/freezed.go | 14 +- pkg/webhook/namespace/patch.go | 8 +- pkg/webhook/namespace/prefix.go | 4 +- pkg/webhook/namespace/quota.go | 4 +- pkg/webhook/namespace/user_metadata.go | 38 +++--- pkg/webhook/networkpolicy/validating.go | 10 +- pkg/webhook/node/errors.go | 12 +- pkg/webhook/ownerreference/patching.go | 22 +-- pkg/webhook/pod/containerregistry.go | 4 +- pkg/webhook/pod/imagepullpolicy.go | 4 +- pkg/webhook/pod/imagepullpolicy_pullpolicy.go | 4 +- pkg/webhook/pod/priorityclass.go | 4 +- pkg/webhook/pvc/validating.go | 4 +- pkg/webhook/route/tenants.go | 2 +- pkg/webhook/service/validating.go | 4 +- pkg/webhook/tenant/containerregistry_regex.go | 4 +- pkg/webhook/tenant/cordoning.go | 6 +- pkg/webhook/tenant/custom_resource_quota.go | 22 +-- .../tenant/forbidden_annotations_regex.go | 19 +-- pkg/webhook/tenant/freezed_emitter.go | 10 +- pkg/webhook/tenant/hostname_regex.go | 4 +- pkg/webhook/tenant/ingressclass_regex.go | 4 +- pkg/webhook/tenant/name.go | 4 +- pkg/webhook/tenant/protected.go | 9 +- pkg/webhook/tenant/rolebindings_regex.go | 4 +- pkg/webhook/tenant/serviceaccount_format.go | 4 +- pkg/webhook/tenant/storageclass_regex.go | 4 +- pkg/webhook/utils/is_capsule_user.go | 4 +- pkg/webhook/utils/is_tenant_owner.go | 8 +- 60 files changed, 344 insertions(+), 373 deletions(-) create mode 100644 api/v1alpha1/capsuleconfiguration_webhook.go create mode 100644 api/v1beta1/tenant_webhook.go create mode 100644 api/v1beta2/tenant_annotations.go rename api/v1beta1/tenant_annotations.go => pkg/api/annotations.go (63%) diff --git a/api/v1alpha1/capsuleconfiguration_webhook.go b/api/v1alpha1/capsuleconfiguration_webhook.go new file mode 100644 index 00000000..45a4221d --- /dev/null +++ b/api/v1alpha1/capsuleconfiguration_webhook.go @@ -0,0 +1,21 @@ +// Copyright 2020-2021 Clastix Labs +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + "os" + + ctrl "sigs.k8s.io/controller-runtime" +) + +func (in *CapsuleConfiguration) SetupWebhookWithManager(mgr ctrl.Manager) error { + certData, _ := os.ReadFile("/tmp/k8s-webhook-server/serving-certs/tls.crt") + if len(certData) == 0 { + return nil + } + + return ctrl.NewWebhookManagedBy(mgr). + For(in). + Complete() +} diff --git a/api/v1alpha1/tenant_func.go b/api/v1alpha1/tenant_func.go index 6342f2d1..b00147b7 100644 --- a/api/v1alpha1/tenant_func.go +++ b/api/v1alpha1/tenant_func.go @@ -9,14 +9,6 @@ import ( corev1 "k8s.io/api/core/v1" ) -func (in *Tenant) IsCordoned() bool { - if v, ok := in.Labels["capsule.clastix.io/cordon"]; ok && v == "enabled" { - return true - } - - return false -} - func (in *Tenant) IsFull() bool { // we don't have limits on assigned Namespaces if in.Spec.NamespaceQuota == nil { diff --git a/api/v1beta1/namespace_options.go b/api/v1beta1/namespace_options.go index 0d7a564a..c4a2aed5 100644 --- a/api/v1beta1/namespace_options.go +++ b/api/v1beta1/namespace_options.go @@ -18,11 +18,11 @@ type NamespaceOptions struct { } func (in *Tenant) hasForbiddenNamespaceLabelsAnnotations() bool { - if _, ok := in.Annotations[ForbiddenNamespaceLabelsAnnotation]; ok { + if _, ok := in.Annotations[api.ForbiddenNamespaceLabelsAnnotation]; ok { return true } - if _, ok := in.Annotations[ForbiddenNamespaceLabelsRegexpAnnotation]; ok { + if _, ok := in.Annotations[api.ForbiddenNamespaceLabelsRegexpAnnotation]; ok { return true } @@ -30,11 +30,11 @@ func (in *Tenant) hasForbiddenNamespaceLabelsAnnotations() bool { } func (in *Tenant) hasForbiddenNamespaceAnnotationsAnnotations() bool { - if _, ok := in.Annotations[ForbiddenNamespaceAnnotationsAnnotation]; ok { + if _, ok := in.Annotations[api.ForbiddenNamespaceAnnotationsAnnotation]; ok { return true } - if _, ok := in.Annotations[ForbiddenNamespaceAnnotationsRegexpAnnotation]; ok { + if _, ok := in.Annotations[api.ForbiddenNamespaceAnnotationsRegexpAnnotation]; ok { return true } @@ -47,8 +47,8 @@ func (in *Tenant) ForbiddenUserNamespaceLabels() *api.ForbiddenListSpec { } return &api.ForbiddenListSpec{ - Exact: strings.Split(in.Annotations[ForbiddenNamespaceLabelsAnnotation], ","), - Regex: in.Annotations[ForbiddenNamespaceLabelsRegexpAnnotation], + Exact: strings.Split(in.Annotations[api.ForbiddenNamespaceLabelsAnnotation], ","), + Regex: in.Annotations[api.ForbiddenNamespaceLabelsRegexpAnnotation], } } @@ -58,7 +58,7 @@ func (in *Tenant) ForbiddenUserNamespaceAnnotations() *api.ForbiddenListSpec { } return &api.ForbiddenListSpec{ - Exact: strings.Split(in.Annotations[ForbiddenNamespaceAnnotationsAnnotation], ","), - Regex: in.Annotations[ForbiddenNamespaceAnnotationsRegexpAnnotation], + Exact: strings.Split(in.Annotations[api.ForbiddenNamespaceAnnotationsAnnotation], ","), + Regex: in.Annotations[api.ForbiddenNamespaceAnnotationsRegexpAnnotation], } } diff --git a/api/v1beta1/tenant_webhook.go b/api/v1beta1/tenant_webhook.go new file mode 100644 index 00000000..58ffec85 --- /dev/null +++ b/api/v1beta1/tenant_webhook.go @@ -0,0 +1,21 @@ +// Copyright 2020-2021 Clastix Labs +// SPDX-License-Identifier: Apache-2.0 + +package v1beta1 + +import ( + "os" + + ctrl "sigs.k8s.io/controller-runtime" +) + +func (in *Tenant) SetupWebhookWithManager(mgr ctrl.Manager) error { + certData, _ := os.ReadFile("/tmp/k8s-webhook-server/serving-certs/tls.crt") + if len(certData) == 0 { + return nil + } + + return ctrl.NewWebhookManagedBy(mgr). + For(in). + Complete() +} diff --git a/api/v1beta2/capsuleconfiguration_types.go b/api/v1beta2/capsuleconfiguration_types.go index a45f2ea4..a5854b51 100644 --- a/api/v1beta2/capsuleconfiguration_types.go +++ b/api/v1beta2/capsuleconfiguration_types.go @@ -22,10 +22,11 @@ type CapsuleConfigurationSpec struct { ProtectedNamespaceRegexpString string `json:"protectedNamespaceRegex,omitempty"` // Allows to set different name rather than the canonical one for the Capsule configuration objects, // such as webhook secret or configurations. - CapsuleResources CapsuleResources `json:"overrides"` + // +kubebuilder:default={TLSSecretName:"capsule-tls",mutatingWebhookConfigurationName:"capsule-mutating-webhook-configuration",validatingWebhookConfigurationName:"capsule-validating-webhook-configuration"} + CapsuleResources CapsuleResources `json:"overrides,omitempty"` // Allows to set the forbidden metadata for the worker nodes that could be patched by a Tenant. // This applies only if the Tenant has an active NodeSelector, and the Owner have right to patch their nodes. - NodeMetadata *NodeMetadata `json:"nodeMetadata"` + NodeMetadata *NodeMetadata `json:"nodeMetadata,omitempty"` // Toggles the TLS reconciler, the controller that is able to generate CA and certificates for the webhooks // when not using an already provided CA and certificate, or when these are managed externally with Vault, or cert-manager. // +kubebuilder:default=true diff --git a/api/v1beta2/tenant_annotations.go b/api/v1beta2/tenant_annotations.go new file mode 100644 index 00000000..4f02bdf6 --- /dev/null +++ b/api/v1beta2/tenant_annotations.go @@ -0,0 +1,17 @@ +// Copyright 2020-2021 Clastix Labs +// SPDX-License-Identifier: Apache-2.0 + +package v1beta2 + +import ( + "fmt" + "strings" +) + +func UsedQuotaFor(resource fmt.Stringer) string { + return "quota.capsule.clastix.io/used-" + strings.ReplaceAll(resource.String(), "/", "_") +} + +func HardQuotaFor(resource fmt.Stringer) string { + return "quota.capsule.clastix.io/hard-" + strings.ReplaceAll(resource.String(), "/", "_") +} diff --git a/api/v1beta2/tenant_conversion_hub.go b/api/v1beta2/tenant_conversion_hub.go index de3dfb3a..4256e252 100644 --- a/api/v1beta2/tenant_conversion_hub.go +++ b/api/v1beta2/tenant_conversion_hub.go @@ -11,6 +11,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/conversion" capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + "github.com/clastix/capsule/pkg/api" ) func (in *Tenant) ConvertFrom(raw conversion.Hub) error { @@ -58,28 +59,28 @@ func (in *Tenant) ConvertFrom(raw conversion.Hub) error { in.Spec.NamespaceOptions.AdditionalMetadata = nsOpts.AdditionalMetadata - if value, found := annotations[capsulev1beta1.ForbiddenNamespaceLabelsAnnotation]; found { + if value, found := annotations[api.ForbiddenNamespaceLabelsAnnotation]; found { in.Spec.NamespaceOptions.ForbiddenLabels.Exact = strings.Split(value, ",") - delete(annotations, capsulev1beta1.ForbiddenNamespaceLabelsAnnotation) + delete(annotations, api.ForbiddenNamespaceLabelsAnnotation) } - if value, found := annotations[capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation]; found { + if value, found := annotations[api.ForbiddenNamespaceLabelsRegexpAnnotation]; found { in.Spec.NamespaceOptions.ForbiddenLabels.Regex = value - delete(annotations, capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation) + delete(annotations, api.ForbiddenNamespaceLabelsRegexpAnnotation) } - if value, found := annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsAnnotation]; found { + if value, found := annotations[api.ForbiddenNamespaceAnnotationsAnnotation]; found { in.Spec.NamespaceOptions.ForbiddenAnnotations.Exact = strings.Split(value, ",") - delete(annotations, capsulev1beta1.ForbiddenNamespaceAnnotationsAnnotation) + delete(annotations, api.ForbiddenNamespaceAnnotationsAnnotation) } - if value, found := annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation]; found { + if value, found := annotations[api.ForbiddenNamespaceAnnotationsRegexpAnnotation]; found { in.Spec.NamespaceOptions.ForbiddenAnnotations.Regex = value - delete(annotations, capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation) + delete(annotations, api.ForbiddenNamespaceAnnotationsRegexpAnnotation) } } @@ -126,10 +127,10 @@ func (in *Tenant) ConvertFrom(raw conversion.Hub) error { in.Spec.Cordoned = value } - if _, found := annotations[capsulev1beta1.ProtectedTenantAnnotation]; found { + if _, found := annotations[api.ProtectedTenantAnnotation]; found { in.Spec.PreventDeletion = true - delete(annotations, capsulev1beta1.ProtectedTenantAnnotation) + delete(annotations, api.ProtectedTenantAnnotation) } in.SetAnnotations(annotations) @@ -189,19 +190,19 @@ func (in *Tenant) ConvertTo(raw conversion.Hub) error { dst.Spec.NamespaceOptions.AdditionalMetadata = nsOpts.AdditionalMetadata if exact := nsOpts.ForbiddenAnnotations.Exact; len(exact) > 0 { - annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsAnnotation] = strings.Join(exact, ",") + annotations[api.ForbiddenNamespaceAnnotationsAnnotation] = strings.Join(exact, ",") } if regex := nsOpts.ForbiddenAnnotations.Regex; len(regex) > 0 { - annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation] = regex + annotations[api.ForbiddenNamespaceAnnotationsRegexpAnnotation] = regex } if exact := nsOpts.ForbiddenLabels.Exact; len(exact) > 0 { - annotations[capsulev1beta1.ForbiddenNamespaceLabelsAnnotation] = strings.Join(exact, ",") + annotations[api.ForbiddenNamespaceLabelsAnnotation] = strings.Join(exact, ",") } if regex := nsOpts.ForbiddenLabels.Regex; len(regex) > 0 { - annotations[capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation] = regex + annotations[api.ForbiddenNamespaceLabelsRegexpAnnotation] = regex } } @@ -233,7 +234,7 @@ func (in *Tenant) ConvertTo(raw conversion.Hub) error { dst.Spec.PriorityClasses = in.Spec.PriorityClasses if in.Spec.PreventDeletion { - annotations[capsulev1beta1.ProtectedTenantAnnotation] = "true" //nolint:goconst + annotations[api.ProtectedTenantAnnotation] = "true" //nolint:goconst } if in.Spec.Cordoned { diff --git a/controllers/servicelabels/abstract.go b/controllers/servicelabels/abstract.go index 54dd2dfb..c0a8c189 100644 --- a/controllers/servicelabels/abstract.go +++ b/controllers/servicelabels/abstract.go @@ -20,7 +20,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/utils" ) @@ -70,15 +70,15 @@ func (r *abstractServiceLabelsReconciler) Reconcile(ctx context.Context, request return reconcile.Result{}, err } -func (r *abstractServiceLabelsReconciler) getTenant(ctx context.Context, namespacedName types.NamespacedName, client client.Client) (*capsulev1beta1.Tenant, error) { +func (r *abstractServiceLabelsReconciler) getTenant(ctx context.Context, namespacedName types.NamespacedName, client client.Client) (*capsulev1beta2.Tenant, error) { ns := &corev1.Namespace{} - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := client.Get(ctx, types.NamespacedName{Name: namespacedName.Namespace}, ns); err != nil { return nil, err } - capsuleLabel, _ := utils.GetTypeLabel(&capsulev1beta1.Tenant{}) + capsuleLabel, _ := utils.GetTypeLabel(&capsulev1beta2.Tenant{}) if _, ok := ns.GetLabels()[capsuleLabel]; !ok { return nil, NewNonTenantObject(namespacedName.Name) } @@ -117,7 +117,7 @@ func (r *abstractServiceLabelsReconciler) forOptionPerInstanceName(ctx context.C } func (r *abstractServiceLabelsReconciler) IsNamespaceInTenant(ctx context.Context, namespace string) bool { - tl := &capsulev1beta1.TenantList{} + tl := &capsulev1beta2.TenantList{} if err := r.client.List(ctx, tl, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", namespace), }); err != nil { diff --git a/controllers/tenant/limitranges.go b/controllers/tenant/limitranges.go index 59e4e152..bfa049ff 100644 --- a/controllers/tenant/limitranges.go +++ b/controllers/tenant/limitranges.go @@ -13,13 +13,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/utils" ) // nolint:dupl // Ensuring all the LimitRange are applied to each Namespace handled by the Tenant. -func (r *Manager) syncLimitRanges(ctx context.Context, tenant *capsulev1beta1.Tenant) error { +func (r *Manager) syncLimitRanges(ctx context.Context, tenant *capsulev1beta2.Tenant) error { // getting requested LimitRange keys keys := make([]string, 0, len(tenant.Spec.LimitRanges.Items)) @@ -40,11 +40,11 @@ func (r *Manager) syncLimitRanges(ctx context.Context, tenant *capsulev1beta1.Te return group.Wait() } -func (r *Manager) syncLimitRange(ctx context.Context, tenant *capsulev1beta1.Tenant, namespace string, keys []string) (err error) { +func (r *Manager) syncLimitRange(ctx context.Context, tenant *capsulev1beta2.Tenant, namespace string, keys []string) (err error) { // getting LimitRange labels for the mutateFn var tenantLabel, limitRangeLabel string - if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta1.Tenant{}); err != nil { + if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta2.Tenant{}); err != nil { return err } diff --git a/controllers/tenant/manager.go b/controllers/tenant/manager.go index 1ea17a12..c89c6cf9 100644 --- a/controllers/tenant/manager.go +++ b/controllers/tenant/manager.go @@ -18,7 +18,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) type Manager struct { @@ -30,7 +30,7 @@ type Manager struct { func (r *Manager) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&capsulev1beta1.Tenant{}). + For(&capsulev1beta2.Tenant{}). Owns(&corev1.Namespace{}). Owns(&networkingv1.NetworkPolicy{}). Owns(&corev1.LimitRange{}). @@ -42,7 +42,7 @@ func (r *Manager) SetupWithManager(mgr ctrl.Manager) error { func (r Manager) Reconcile(ctx context.Context, request ctrl.Request) (result ctrl.Result, err error) { r.Log = r.Log.WithValues("Request.Name", request.Name) // Fetch the Tenant instance - instance := &capsulev1beta1.Tenant{} + instance := &capsulev1beta2.Tenant{} if err = r.Get(ctx, request.NamespacedName, instance); err != nil { if apierrors.IsNotFound(err) { r.Log.Info("Request object not found, could have been deleted after reconcile request") @@ -130,12 +130,12 @@ func (r Manager) Reconcile(ctx context.Context, request ctrl.Request) (result ct return ctrl.Result{}, err } -func (r *Manager) updateTenantStatus(ctx context.Context, tnt *capsulev1beta1.Tenant) error { +func (r *Manager) updateTenantStatus(ctx context.Context, tnt *capsulev1beta2.Tenant) error { return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { - if tnt.IsCordoned() { - tnt.Status.State = capsulev1beta1.TenantStateCordoned + if tnt.Spec.Cordoned { + tnt.Status.State = capsulev1beta2.TenantStateCordoned } else { - tnt.Status.State = capsulev1beta1.TenantStateActive + tnt.Status.State = capsulev1beta2.TenantStateActive } return r.Client.Status().Update(ctx, tnt) diff --git a/controllers/tenant/namespaces.go b/controllers/tenant/namespaces.go index 53a9aca9..e0ec2795 100644 --- a/controllers/tenant/namespaces.go +++ b/controllers/tenant/namespaces.go @@ -16,12 +16,13 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" + "github.com/clastix/capsule/pkg/api" "github.com/clastix/capsule/pkg/utils" ) // Ensuring all annotations are applied to each Namespace handled by the Tenant. -func (r *Manager) syncNamespaces(ctx context.Context, tenant *capsulev1beta1.Tenant) (err error) { +func (r *Manager) syncNamespaces(ctx context.Context, tenant *capsulev1beta2.Tenant) (err error) { group := new(errgroup.Group) for _, item := range tenant.Status.Namespaces { @@ -42,7 +43,7 @@ func (r *Manager) syncNamespaces(ctx context.Context, tenant *capsulev1beta1.Ten } // nolint:gocognit -func (r *Manager) syncNamespaceMetadata(ctx context.Context, namespace string, tnt *capsulev1beta1.Tenant) (err error) { +func (r *Manager) syncNamespaceMetadata(ctx context.Context, namespace string, tnt *capsulev1beta2.Tenant) (err error) { var res controllerutil.OperationResult err = retry.RetryOnConflict(retry.DefaultBackoff, func() (conflictErr error) { @@ -51,7 +52,7 @@ func (r *Manager) syncNamespaceMetadata(ctx context.Context, namespace string, t return } - capsuleLabel, _ := utils.GetTypeLabel(&capsulev1beta1.Tenant{}) + capsuleLabel, _ := utils.GetTypeLabel(&capsulev1beta2.Tenant{}) res, conflictErr = controllerutil.CreateOrUpdate(ctx, r.Client, ns, func() error { annotations := make(map[string]string) @@ -103,20 +104,20 @@ func (r *Manager) syncNamespaceMetadata(ctx context.Context, namespace string, t } } - if value, ok := tnt.Annotations[capsulev1beta1.ForbiddenNamespaceLabelsAnnotation]; ok { - annotations[capsulev1beta1.ForbiddenNamespaceLabelsAnnotation] = value + if value, ok := tnt.Annotations[api.ForbiddenNamespaceLabelsAnnotation]; ok { + annotations[api.ForbiddenNamespaceLabelsAnnotation] = value } - if value, ok := tnt.Annotations[capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation]; ok { - annotations[capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation] = value + if value, ok := tnt.Annotations[api.ForbiddenNamespaceLabelsRegexpAnnotation]; ok { + annotations[api.ForbiddenNamespaceLabelsRegexpAnnotation] = value } - if value, ok := tnt.Annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsAnnotation]; ok { - annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsAnnotation] = value + if value, ok := tnt.Annotations[api.ForbiddenNamespaceAnnotationsAnnotation]; ok { + annotations[api.ForbiddenNamespaceAnnotationsAnnotation] = value } - if value, ok := tnt.Annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation]; ok { - annotations[capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation] = value + if value, ok := tnt.Annotations[api.ForbiddenNamespaceAnnotationsRegexpAnnotation]; ok { + annotations[api.ForbiddenNamespaceAnnotationsRegexpAnnotation] = value } if ns.Annotations == nil { @@ -146,11 +147,11 @@ func (r *Manager) syncNamespaceMetadata(ctx context.Context, namespace string, t return err } -func (r *Manager) ensureNamespaceCount(ctx context.Context, tenant *capsulev1beta1.Tenant) error { +func (r *Manager) ensureNamespaceCount(ctx context.Context, tenant *capsulev1beta2.Tenant) error { return retry.RetryOnConflict(retry.DefaultBackoff, func() error { tenant.Status.Size = uint(len(tenant.Status.Namespaces)) - found := &capsulev1beta1.Tenant{} + found := &capsulev1beta2.Tenant{} if err := r.Client.Get(ctx, types.NamespacedName{Name: tenant.GetName()}, found); err != nil { return err } @@ -161,7 +162,7 @@ func (r *Manager) ensureNamespaceCount(ctx context.Context, tenant *capsulev1bet }) } -func (r *Manager) collectNamespaces(ctx context.Context, tenant *capsulev1beta1.Tenant) error { +func (r *Manager) collectNamespaces(ctx context.Context, tenant *capsulev1beta2.Tenant) error { return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { list := &corev1.NamespaceList{} err = r.Client.List(ctx, list, client.MatchingFieldsSelector{ diff --git a/controllers/tenant/networkpolicies.go b/controllers/tenant/networkpolicies.go index 90f0379d..4d155fad 100644 --- a/controllers/tenant/networkpolicies.go +++ b/controllers/tenant/networkpolicies.go @@ -13,13 +13,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/utils" ) // nolint:dupl // Ensuring all the NetworkPolicies are applied to each Namespace handled by the Tenant. -func (r *Manager) syncNetworkPolicies(ctx context.Context, tenant *capsulev1beta1.Tenant) error { +func (r *Manager) syncNetworkPolicies(ctx context.Context, tenant *capsulev1beta2.Tenant) error { // getting requested NetworkPolicy keys keys := make([]string, 0, len(tenant.Spec.NetworkPolicies.Items)) @@ -40,14 +40,14 @@ func (r *Manager) syncNetworkPolicies(ctx context.Context, tenant *capsulev1beta return group.Wait() } -func (r *Manager) syncNetworkPolicy(ctx context.Context, tenant *capsulev1beta1.Tenant, namespace string, keys []string) (err error) { +func (r *Manager) syncNetworkPolicy(ctx context.Context, tenant *capsulev1beta2.Tenant, namespace string, keys []string) (err error) { if err = r.pruningResources(ctx, namespace, keys, &networkingv1.NetworkPolicy{}); err != nil { return err } // getting NetworkPolicy labels for the mutateFn var tenantLabel, networkPolicyLabel string - if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta1.Tenant{}); err != nil { + if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta2.Tenant{}); err != nil { return err } diff --git a/controllers/tenant/resourcequotas.go b/controllers/tenant/resourcequotas.go index 348877fc..0f740040 100644 --- a/controllers/tenant/resourcequotas.go +++ b/controllers/tenant/resourcequotas.go @@ -19,7 +19,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/api" "github.com/clastix/capsule/pkg/utils" ) @@ -37,11 +37,11 @@ import ( // // In case of Namespace-scoped Resource Budget, we're just replicating the resources across all registered Namespaces. // nolint:gocognit -func (r *Manager) syncResourceQuotas(ctx context.Context, tenant *capsulev1beta1.Tenant) (err error) { +func (r *Manager) syncResourceQuotas(ctx context.Context, tenant *capsulev1beta2.Tenant) (err error) { // getting ResourceQuota labels for the mutateFn var tenantLabel, typeLabel string - if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta1.Tenant{}); err != nil { + if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta2.Tenant{}); err != nil { return err } @@ -158,11 +158,11 @@ func (r *Manager) syncResourceQuotas(ctx context.Context, tenant *capsulev1beta1 return group.Wait() } -func (r *Manager) syncResourceQuota(ctx context.Context, tenant *capsulev1beta1.Tenant, namespace string, keys []string) (err error) { +func (r *Manager) syncResourceQuota(ctx context.Context, tenant *capsulev1beta2.Tenant, namespace string, keys []string) (err error) { // getting ResourceQuota labels for the mutateFn var tenantLabel, typeLabel string - if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta1.Tenant{}); err != nil { + if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta2.Tenant{}); err != nil { return err } @@ -238,8 +238,8 @@ func (r *Manager) resourceQuotasUpdate(ctx context.Context, resourceName corev1. found.Annotations = make(map[string]string) } found.Labels = rq.Labels - found.Annotations[capsulev1beta1.UsedQuotaFor(resourceName)] = actual.String() - found.Annotations[capsulev1beta1.HardQuotaFor(resourceName)] = limit.String() + found.Annotations[capsulev1beta2.UsedQuotaFor(resourceName)] = actual.String() + found.Annotations[capsulev1beta2.HardQuotaFor(resourceName)] = limit.String() // Updating the Resource according to the actual.Cmp result found.Spec.Hard = rq.Spec.Hard diff --git a/controllers/tenant/resourcequotas_quota.go b/controllers/tenant/resourcequotas_quota.go index c20be18f..ac370a2a 100644 --- a/controllers/tenant/resourcequotas_quota.go +++ b/controllers/tenant/resourcequotas_quota.go @@ -16,10 +16,10 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/util/retry" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) -func (r *Manager) syncCustomResourceQuotaUsages(ctx context.Context, tenant *capsulev1beta1.Tenant) error { +func (r *Manager) syncCustomResourceQuotaUsages(ctx context.Context, tenant *capsulev1beta2.Tenant) error { type resource struct { kind string group string @@ -29,7 +29,7 @@ func (r *Manager) syncCustomResourceQuotaUsages(ctx context.Context, tenant *cap var resourceList []resource for k := range tenant.GetAnnotations() { - if !strings.HasPrefix(k, capsulev1beta1.ResourceQuotaAnnotationPrefix) { + if !strings.HasPrefix(k, capsulev1beta2.ResourceQuotaAnnotationPrefix) { continue } @@ -69,7 +69,7 @@ func (r *Manager) syncCustomResourceQuotaUsages(ctx context.Context, tenant *cap defer func() { for gvk, used := range usedMap { err := retry.RetryOnConflict(retry.DefaultBackoff, func() (retryErr error) { - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} if retryErr = r.Client.Get(ctx, types.NamespacedName{Name: tenant.GetName()}, tnt); retryErr != nil { return } @@ -78,7 +78,7 @@ func (r *Manager) syncCustomResourceQuotaUsages(ctx context.Context, tenant *cap tnt.Annotations = make(map[string]string) } - tnt.Annotations[capsulev1beta1.UsedAnnotationForResource(gvk)] = fmt.Sprintf("%d", used) + tnt.Annotations[capsulev1beta2.UsedAnnotationForResource(gvk)] = fmt.Sprintf("%d", used) return r.Client.Update(ctx, tnt) }) diff --git a/controllers/tenant/rolebindings.go b/controllers/tenant/rolebindings.go index a1d0126d..236bfec7 100644 --- a/controllers/tenant/rolebindings.go +++ b/controllers/tenant/rolebindings.go @@ -14,14 +14,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/api" "github.com/clastix/capsule/pkg/utils" ) // ownerClusterRoleBindings generates a Capsule AdditionalRoleBinding object for the Owner dynamic clusterrole in order // to take advantage of the additional role binding feature. -func (r *Manager) ownerClusterRoleBindings(owner capsulev1beta1.OwnerSpec, clusterRole string) api.AdditionalRoleBindingsSpec { +func (r *Manager) ownerClusterRoleBindings(owner capsulev1beta2.OwnerSpec, clusterRole string) api.AdditionalRoleBindingsSpec { var subject rbacv1.Subject if owner.Kind == "ServiceAccount" { @@ -50,7 +50,7 @@ func (r *Manager) ownerClusterRoleBindings(owner capsulev1beta1.OwnerSpec, clust // Sync the dynamic Tenant Owner specific cluster-roles and additional Role Bindings, which can be used in many ways: // applying Pod Security Policies or giving access to CRDs or specific API groups. -func (r *Manager) syncRoleBindings(ctx context.Context, tenant *capsulev1beta1.Tenant) (err error) { +func (r *Manager) syncRoleBindings(ctx context.Context, tenant *capsulev1beta2.Tenant) (err error) { // hashing the RoleBinding name due to DNS RFC-1123 applied to Kubernetes labels hashFn := func(binding api.AdditionalRoleBindingsSpec) string { h := fnv.New64a() @@ -66,8 +66,8 @@ func (r *Manager) syncRoleBindings(ctx context.Context, tenant *capsulev1beta1.T // getting requested Role Binding keys keys := make([]string, 0, len(tenant.Spec.Owners)) // Generating for dynamic tenant owners cluster roles - for index, owner := range tenant.Spec.Owners { - for _, clusterRoleName := range owner.GetRoles(*tenant, index) { + for _, owner := range tenant.Spec.Owners { + for _, clusterRoleName := range owner.ClusterRoles { cr := r.ownerClusterRoleBindings(owner, clusterRoleName) keys = append(keys, hashFn(cr)) @@ -91,10 +91,10 @@ func (r *Manager) syncRoleBindings(ctx context.Context, tenant *capsulev1beta1.T return group.Wait() } -func (r *Manager) syncAdditionalRoleBinding(ctx context.Context, tenant *capsulev1beta1.Tenant, ns string, keys []string, hashFn func(binding api.AdditionalRoleBindingsSpec) string) (err error) { +func (r *Manager) syncAdditionalRoleBinding(ctx context.Context, tenant *capsulev1beta2.Tenant, ns string, keys []string, hashFn func(binding api.AdditionalRoleBindingsSpec) string) (err error) { var tenantLabel, roleBindingLabel string - if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta1.Tenant{}); err != nil { + if tenantLabel, err = utils.GetTypeLabel(&capsulev1beta2.Tenant{}); err != nil { return } @@ -108,8 +108,8 @@ func (r *Manager) syncAdditionalRoleBinding(ctx context.Context, tenant *capsule var roleBindings []api.AdditionalRoleBindingsSpec - for index, owner := range tenant.Spec.Owners { - for _, clusterRoleName := range owner.GetRoles(*tenant, index) { + for _, owner := range tenant.Spec.Owners { + for _, clusterRoleName := range owner.ClusterRoles { roleBindings = append(roleBindings, r.ownerClusterRoleBindings(owner, clusterRoleName)) } } diff --git a/controllers/tenant/utils.go b/controllers/tenant/utils.go index bca8b446..5adf7ac4 100644 --- a/controllers/tenant/utils.go +++ b/controllers/tenant/utils.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - capsulev1beta1 "github.com/clastix/capsule/pkg/utils" + capsulev1beta2 "github.com/clastix/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 = capsulev1beta1.GetTypeLabel(obj); err != nil { + if capsuleLabel, err = capsulev1beta2.GetTypeLabel(obj); err != nil { return } diff --git a/main.go b/main.go index fd713ac3..41bf4efb 100644 --- a/main.go +++ b/main.go @@ -206,7 +206,17 @@ func main() { } if err = (&capsulev1alpha1.Tenant{}).SetupWebhookWithManager(manager); err != nil { - setupLog.Error(err, "unable to create conversion webhook", "webhook", "Tenant") + setupLog.Error(err, "unable to create conversion webhook", "webhook", "capsulev1alpha1.Tenant") + os.Exit(1) + } + + if err = (&capsulev1alpha1.CapsuleConfiguration{}).SetupWebhookWithManager(manager); err != nil { + setupLog.Error(err, "unable to create conversion webhook", "webhook", "capsulev1alpha1.CapsuleConfiguration") + os.Exit(1) + } + + if err = (&capsulev1beta1.Tenant{}).SetupWebhookWithManager(manager); err != nil { + setupLog.Error(err, "unable to create conversion webhook", "webhook", "capsulev1beta1.Tenant") os.Exit(1) } diff --git a/api/v1beta1/tenant_annotations.go b/pkg/api/annotations.go similarity index 63% rename from api/v1beta1/tenant_annotations.go rename to pkg/api/annotations.go index 8c21e925..37753567 100644 --- a/api/v1beta1/tenant_annotations.go +++ b/pkg/api/annotations.go @@ -1,12 +1,7 @@ // Copyright 2020-2021 Clastix Labs // SPDX-License-Identifier: Apache-2.0 -package v1beta1 - -import ( - "fmt" - "strings" -) +package api const ( ForbiddenNamespaceLabelsAnnotation = "capsule.clastix.io/forbidden-namespace-labels" @@ -15,11 +10,3 @@ const ( ForbiddenNamespaceAnnotationsRegexpAnnotation = "capsule.clastix.io/forbidden-namespace-annotations-regexp" ProtectedTenantAnnotation = "capsule.clastix.io/protected" ) - -func UsedQuotaFor(resource fmt.Stringer) string { - return "quota.capsule.clastix.io/used-" + strings.ReplaceAll(resource.String(), "/", "_") -} - -func HardQuotaFor(resource fmt.Stringer) string { - return "quota.capsule.clastix.io/hard-" + strings.ReplaceAll(resource.String(), "/", "_") -} diff --git a/pkg/configuration/client.go b/pkg/configuration/client.go index 951bde20..75ca1aa5 100644 --- a/pkg/configuration/client.go +++ b/pkg/configuration/client.go @@ -6,32 +6,30 @@ package configuration import ( "context" "regexp" - "strconv" - "strings" "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1" - capsulev1beta1 "github.com/clastix/capsule/pkg/api" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" + capsuleapi "github.com/clastix/capsule/pkg/api" ) // capsuleConfiguration is the Capsule Configuration retrieval mode // using a closure that provides the desired configuration. type capsuleConfiguration struct { - retrievalFn func() *capsulev1alpha1.CapsuleConfiguration + retrievalFn func() *capsulev1beta2.CapsuleConfiguration } func NewCapsuleConfiguration(ctx context.Context, client client.Client, name string) Configuration { - return &capsuleConfiguration{retrievalFn: func() *capsulev1alpha1.CapsuleConfiguration { - config := &capsulev1alpha1.CapsuleConfiguration{} + return &capsuleConfiguration{retrievalFn: func() *capsulev1beta2.CapsuleConfiguration { + config := &capsulev1beta2.CapsuleConfiguration{} if err := client.Get(ctx, types.NamespacedName{Name: name}, config); err != nil { if apierrors.IsNotFound(err) { - return &capsulev1alpha1.CapsuleConfiguration{ - Spec: capsulev1alpha1.CapsuleConfigurationSpec{ + return &capsulev1beta2.CapsuleConfiguration{ + Spec: capsulev1beta2.CapsuleConfigurationSpec{ UserGroups: []string{"capsule.clastix.io"}, ForceTenantPrefix: false, ProtectedNamespaceRegexpString: "", @@ -45,7 +43,7 @@ func NewCapsuleConfiguration(ctx context.Context, client client.Client, name str }} } -func (c capsuleConfiguration) ProtectedNamespaceRegexp() (*regexp.Regexp, error) { +func (c *capsuleConfiguration) ProtectedNamespaceRegexp() (*regexp.Regexp, error) { expr := c.retrievalFn().Spec.ProtectedNamespaceRegexpString if len(expr) == 0 { return nil, nil // nolint:nilnil @@ -59,120 +57,46 @@ func (c capsuleConfiguration) ProtectedNamespaceRegexp() (*regexp.Regexp, error) return r, nil } -func (c capsuleConfiguration) ForceTenantPrefix() bool { +func (c *capsuleConfiguration) ForceTenantPrefix() bool { return c.retrievalFn().Spec.ForceTenantPrefix } -func (c capsuleConfiguration) TLSSecretName() (name string) { - name = TLSSecretName - - if c.retrievalFn().Annotations == nil { - return - } - - v, ok := c.retrievalFn().Annotations[capsulev1alpha1.TLSSecretNameAnnotation] - if ok { - return v - } - - return +func (c *capsuleConfiguration) TLSSecretName() (name string) { + return c.retrievalFn().Spec.CapsuleResources.TLSSecretName } -func (c capsuleConfiguration) EnableTLSConfiguration() bool { - annotationValue, ok := c.retrievalFn().Annotations[capsulev1alpha1.EnableTLSConfigurationAnnotationName] - - if ok { - value, err := strconv.ParseBool(annotationValue) - if err != nil { - return false - } - - return value - } - - return false +func (c *capsuleConfiguration) EnableTLSConfiguration() bool { + return c.retrievalFn().Spec.EnableTLSReconciler } -func (c capsuleConfiguration) MutatingWebhookConfigurationName() (name string) { - name = MutatingWebhookConfigurationName - - if c.retrievalFn().Annotations == nil { - return - } - - v, ok := c.retrievalFn().Annotations[capsulev1alpha1.MutatingWebhookConfigurationName] - if ok { - return v - } - - return +func (c *capsuleConfiguration) MutatingWebhookConfigurationName() (name string) { + return c.retrievalFn().Spec.CapsuleResources.MutatingWebhookConfigurationName } -func (c capsuleConfiguration) TenantCRDName() string { +func (c *capsuleConfiguration) TenantCRDName() string { return TenantCRDName } -func (c capsuleConfiguration) ValidatingWebhookConfigurationName() (name string) { - name = ValidatingWebhookConfigurationName - - if c.retrievalFn().Annotations == nil { - return - } - - v, ok := c.retrievalFn().Annotations[capsulev1alpha1.ValidatingWebhookConfigurationName] - if ok { - return v - } - - return +func (c *capsuleConfiguration) ValidatingWebhookConfigurationName() (name string) { + return c.retrievalFn().Spec.CapsuleResources.ValidatingWebhookConfigurationName } -func (c capsuleConfiguration) UserGroups() []string { +func (c *capsuleConfiguration) UserGroups() []string { return c.retrievalFn().Spec.UserGroups } -func (c capsuleConfiguration) hasForbiddenNodeLabelsAnnotations() bool { - if _, ok := c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeLabelsAnnotation]; ok { - return true - } - - if _, ok := c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeLabelsRegexpAnnotation]; ok { - return true - } - - return false -} - -func (c capsuleConfiguration) hasForbiddenNodeAnnotationsAnnotations() bool { - if _, ok := c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeAnnotationsAnnotation]; ok { - return true - } - - if _, ok := c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeAnnotationsRegexpAnnotation]; ok { - return true - } - - return false -} - -func (c *capsuleConfiguration) ForbiddenUserNodeLabels() *capsulev1beta1.ForbiddenListSpec { - if !c.hasForbiddenNodeLabelsAnnotations() { +func (c *capsuleConfiguration) ForbiddenUserNodeLabels() *capsuleapi.ForbiddenListSpec { + if c.retrievalFn().Spec.NodeMetadata == nil { return nil } - return &capsulev1beta1.ForbiddenListSpec{ - Exact: strings.Split(c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeLabelsAnnotation], ","), - Regex: c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeLabelsRegexpAnnotation], - } + return &c.retrievalFn().Spec.NodeMetadata.ForbiddenLabels } -func (c *capsuleConfiguration) ForbiddenUserNodeAnnotations() *capsulev1beta1.ForbiddenListSpec { - if !c.hasForbiddenNodeAnnotationsAnnotations() { +func (c *capsuleConfiguration) ForbiddenUserNodeAnnotations() *capsuleapi.ForbiddenListSpec { + if c.retrievalFn().Spec.NodeMetadata == nil { return nil } - return &capsulev1beta1.ForbiddenListSpec{ - Exact: strings.Split(c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeAnnotationsAnnotation], ","), - Regex: c.retrievalFn().Annotations[capsulev1alpha1.ForbiddenNodeAnnotationsRegexpAnnotation], - } + return &c.retrievalFn().Spec.NodeMetadata.ForbiddenAnnotations } diff --git a/pkg/configuration/configuration.go b/pkg/configuration/configuration.go index f36ec723..68ad6416 100644 --- a/pkg/configuration/configuration.go +++ b/pkg/configuration/configuration.go @@ -6,14 +6,11 @@ package configuration import ( "regexp" - capsulev1beta1 "github.com/clastix/capsule/pkg/api" + capsuleapi "github.com/clastix/capsule/pkg/api" ) const ( - TLSSecretName = "capsule-tls" - MutatingWebhookConfigurationName = "capsule-mutating-webhook-configuration" - ValidatingWebhookConfigurationName = "capsule-validating-webhook-configuration" - TenantCRDName = "tenants.capsule.clastix.io" + TenantCRDName = "tenants.capsule.clastix.io" ) type Configuration interface { @@ -27,6 +24,6 @@ type Configuration interface { ValidatingWebhookConfigurationName() string TenantCRDName() string UserGroups() []string - ForbiddenUserNodeLabels() *capsulev1beta1.ForbiddenListSpec - ForbiddenUserNodeAnnotations() *capsulev1beta1.ForbiddenListSpec + ForbiddenUserNodeLabels() *capsuleapi.ForbiddenListSpec + ForbiddenUserNodeAnnotations() *capsuleapi.ForbiddenListSpec } diff --git a/pkg/indexer/indexer.go b/pkg/indexer/indexer.go index a80c7497..4dde3501 100644 --- a/pkg/indexer/indexer.go +++ b/pkg/indexer/indexer.go @@ -16,7 +16,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/indexer/ingress" "github.com/clastix/capsule/pkg/indexer/namespace" @@ -31,7 +30,6 @@ type CustomIndexer interface { func AddToManager(ctx context.Context, log logr.Logger, mgr manager.Manager) error { indexers := []CustomIndexer{ - tenant.NamespacesReference{Obj: &capsulev1beta1.Tenant{}}, tenant.NamespacesReference{Obj: &capsulev1beta2.Tenant{}}, tenant.OwnerReference{}, namespace.OwnerReference{}, diff --git a/pkg/indexer/namespace/namespaces.go b/pkg/indexer/namespace/namespaces.go index 52f9aa4d..87ea803b 100644 --- a/pkg/indexer/namespace/namespaces.go +++ b/pkg/indexer/namespace/namespaces.go @@ -9,7 +9,7 @@ import ( corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) type OwnerReference struct{} @@ -32,7 +32,7 @@ func (o OwnerReference) Func() client.IndexerFunc { } for _, or := range ns.OwnerReferences { - if or.APIVersion == capsulev1beta1.GroupVersion.String() { + if or.APIVersion == capsulev1beta2.GroupVersion.String() { res = append(res, or.Name) } } diff --git a/pkg/indexer/tenant/owner.go b/pkg/indexer/tenant/owner.go index f947d66d..46dc3c69 100644 --- a/pkg/indexer/tenant/owner.go +++ b/pkg/indexer/tenant/owner.go @@ -8,14 +8,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/utils" ) type OwnerReference struct{} func (o OwnerReference) Object() client.Object { - return &capsulev1beta1.Tenant{} + return &capsulev1beta2.Tenant{} } func (o OwnerReference) Field() string { @@ -24,9 +24,9 @@ func (o OwnerReference) Field() string { func (o OwnerReference) Func() client.IndexerFunc { return func(object client.Object) []string { - tenant, ok := object.(*capsulev1beta1.Tenant) + tenant, ok := object.(*capsulev1beta2.Tenant) if !ok { - panic(fmt.Errorf("expected type *capsulev1beta1.Tenant, got %T", tenant)) + panic(fmt.Errorf("expected type *capsulev1beta2.Tenant, got %T", tenant)) } return utils.GetOwnersWithKinds(tenant) diff --git a/pkg/utils/node_selector.go b/pkg/utils/node_selector.go index d7160e87..94f3b785 100644 --- a/pkg/utils/node_selector.go +++ b/pkg/utils/node_selector.go @@ -8,14 +8,14 @@ import ( "sort" "strings" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) const ( NodeSelectorAnnotation = "scheduler.alpha.kubernetes.io/node-selector" ) -func BuildNodeSelector(tnt *capsulev1beta1.Tenant, nsAnnotations map[string]string) map[string]string { +func BuildNodeSelector(tnt *capsulev1beta2.Tenant, nsAnnotations map[string]string) map[string]string { if nsAnnotations == nil { nsAnnotations = make(map[string]string) } diff --git a/pkg/utils/owner.go b/pkg/utils/owner.go index 6ec97f90..fad2c695 100644 --- a/pkg/utils/owner.go +++ b/pkg/utils/owner.go @@ -6,10 +6,10 @@ package utils import ( "fmt" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) -func GetOwnersWithKinds(tenant *capsulev1beta1.Tenant) (owners []string) { +func GetOwnersWithKinds(tenant *capsulev1beta2.Tenant) (owners []string) { for _, owner := range tenant.Spec.Owners { owners = append(owners, fmt.Sprintf("%s:%s", owner.Kind.String(), owner.Name)) } diff --git a/pkg/webhook/ingress/utils.go b/pkg/webhook/ingress/utils.go index 52850a81..c9185b93 100644 --- a/pkg/webhook/ingress/utils.go +++ b/pkg/webhook/ingress/utils.go @@ -14,11 +14,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) -func tenantFromIngress(ctx context.Context, c client.Client, ingress Ingress) (*capsulev1beta1.Tenant, error) { - tenantList := &capsulev1beta1.TenantList{} +func tenantFromIngress(ctx context.Context, c client.Client, ingress Ingress) (*capsulev1beta2.Tenant, error) { + tenantList := &capsulev1beta2.TenantList{} if err := c.List(ctx, tenantList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", ingress.Namespace()), }); err != nil { diff --git a/pkg/webhook/ingress/validate_class.go b/pkg/webhook/ingress/validate_class.go index c7f67c68..34f79fed 100644 --- a/pkg/webhook/ingress/validate_class.go +++ b/pkg/webhook/ingress/validate_class.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/configuration" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" @@ -34,7 +34,7 @@ func (r *class) OnCreate(client client.Client, decoder *admission.Decoder, recor return utils.ErroredResponse(err) } - var tenant *capsulev1beta1.Tenant + var tenant *capsulev1beta2.Tenant tenant, err = tenantFromIngress(ctx, client, ingress) if err != nil { @@ -75,7 +75,7 @@ func (r *class) OnUpdate(client client.Client, decoder *admission.Decoder, recor return utils.ErroredResponse(err) } - var tenant *capsulev1beta1.Tenant + var tenant *capsulev1beta2.Tenant tenant, err = tenantFromIngress(ctx, client, ingress) if err != nil { @@ -114,7 +114,7 @@ func (r *class) OnDelete(client.Client, *admission.Decoder, record.EventRecorder } } -func (r *class) validateClass(tenant capsulev1beta1.Tenant, ingressClass *string) error { +func (r *class) validateClass(tenant capsulev1beta2.Tenant, ingressClass *string) error { if tenant.Spec.IngressOptions.AllowedClasses == nil { return nil } diff --git a/pkg/webhook/ingress/validate_collision.go b/pkg/webhook/ingress/validate_collision.go index f7c508d4..dd9a73b6 100644 --- a/pkg/webhook/ingress/validate_collision.go +++ b/pkg/webhook/ingress/validate_collision.go @@ -18,7 +18,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/api" "github.com/clastix/capsule/pkg/configuration" "github.com/clastix/capsule/pkg/indexer/ingress" @@ -42,7 +42,7 @@ func (r *collision) OnCreate(client client.Client, decoder *admission.Decoder, r return utils.ErroredResponse(err) } - var tenant *capsulev1beta1.Tenant + var tenant *capsulev1beta2.Tenant tenant, err = tenantFromIngress(ctx, client, ing) if err != nil { @@ -77,7 +77,7 @@ func (r *collision) OnUpdate(client client.Client, decoder *admission.Decoder, r return utils.ErroredResponse(err) } - var tenant *capsulev1beta1.Tenant + var tenant *capsulev1beta2.Tenant tenant, err = tenantFromIngress(ctx, client, ing) if err != nil { @@ -129,7 +129,7 @@ func (r *collision) validateCollision(ctx context.Context, clt client.Client, in // nolint:exhaustive switch scope { case api.HostnameCollisionScopeCluster: - tenantList := &capsulev1beta1.TenantList{} + tenantList := &capsulev1beta2.TenantList{} if err := clt.List(ctx, tenantList); err != nil { return err } @@ -140,7 +140,7 @@ func (r *collision) validateCollision(ctx context.Context, clt client.Client, in case api.HostnameCollisionScopeTenant: selector := client.MatchingFieldsSelector{Selector: fields.OneTermEqualSelector(".status.namespaces", ing.Namespace())} - tenantList := &capsulev1beta1.TenantList{} + tenantList := &capsulev1beta2.TenantList{} if err := clt.List(ctx, tenantList, selector); err != nil { return err } diff --git a/pkg/webhook/ingress/validate_hostnames.go b/pkg/webhook/ingress/validate_hostnames.go index 77df4865..84c69af5 100644 --- a/pkg/webhook/ingress/validate_hostnames.go +++ b/pkg/webhook/ingress/validate_hostnames.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/configuration" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" @@ -35,7 +35,7 @@ func (r *hostnames) OnCreate(c client.Client, decoder *admission.Decoder, record return utils.ErroredResponse(err) } - var tenant *capsulev1beta1.Tenant + var tenant *capsulev1beta2.Tenant tenant, err = tenantFromIngress(ctx, c, ingress) if err != nil { @@ -76,7 +76,7 @@ func (r *hostnames) OnUpdate(c client.Client, decoder *admission.Decoder, record return utils.ErroredResponse(err) } - var tenant *capsulev1beta1.Tenant + var tenant *capsulev1beta2.Tenant tenant, err = tenantFromIngress(ctx, c, ingress) if err != nil { @@ -116,7 +116,7 @@ func (r *hostnames) OnDelete(client.Client, *admission.Decoder, record.EventReco } } -func (r *hostnames) validateHostnames(tenant capsulev1beta1.Tenant, hostnames sets.String) error { +func (r *hostnames) validateHostnames(tenant capsulev1beta2.Tenant, hostnames sets.String) error { if tenant.Spec.IngressOptions.AllowedHostnames == nil { return nil } diff --git a/pkg/webhook/ingress/validate_wildcard.go b/pkg/webhook/ingress/validate_wildcard.go index a865ae77..1cc9a4a3 100644 --- a/pkg/webhook/ingress/validate_wildcard.go +++ b/pkg/webhook/ingress/validate_wildcard.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -44,7 +44,7 @@ func (h *wildcard) OnUpdate(client client.Client, decoder *admission.Decoder, re } func (h *wildcard) wildcardHandler(ctx context.Context, clt client.Client, req admission.Request, recorder record.EventRecorder, decoder *admission.Decoder) *admission.Response { - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := clt.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", req.Namespace), @@ -59,8 +59,7 @@ func (h *wildcard) wildcardHandler(ctx context.Context, clt client.Client, req a tnt := tntList.Items[0] - // Check if Annotation in manifest has value "capsule.clastix.io/deny-wildcard" set to "true". - if tnt.IsWildcardDenied() { + if !tnt.Spec.IngressOptions.AllowWildcardHostnames { // Retrieve ingress resource from request. ingress, err := ingressFromRequest(req, decoder) if err != nil { diff --git a/pkg/webhook/namespace/errors.go b/pkg/webhook/namespace/errors.go index 04e87804..e28812e0 100644 --- a/pkg/webhook/namespace/errors.go +++ b/pkg/webhook/namespace/errors.go @@ -7,11 +7,11 @@ import ( "fmt" "strings" - capsulev1beta1 "github.com/clastix/capsule/pkg/api" + capsuleapi "github.com/clastix/capsule/pkg/api" ) // nolint:predeclared -func appendForbiddenError(spec *capsulev1beta1.ForbiddenListSpec) (append string) { +func appendForbiddenError(spec *capsuleapi.ForbiddenListSpec) (append string) { append += "Forbidden are " if len(spec.Exact) > 0 { append += fmt.Sprintf("one of the following (%s)", strings.Join(spec.Exact, ", ")) @@ -39,10 +39,10 @@ func (namespaceQuotaExceededError) Error() string { type namespaceLabelForbiddenError struct { label string - spec *capsulev1beta1.ForbiddenListSpec + spec *capsuleapi.ForbiddenListSpec } -func NewNamespaceLabelForbiddenError(label string, forbiddenSpec *capsulev1beta1.ForbiddenListSpec) error { +func NewNamespaceLabelForbiddenError(label string, forbiddenSpec *capsuleapi.ForbiddenListSpec) error { return &namespaceLabelForbiddenError{ label: label, spec: forbiddenSpec, @@ -55,10 +55,10 @@ func (f namespaceLabelForbiddenError) Error() string { type namespaceAnnotationForbiddenError struct { annotation string - spec *capsulev1beta1.ForbiddenListSpec + spec *capsuleapi.ForbiddenListSpec } -func NewNamespaceAnnotationForbiddenError(annotation string, forbiddenSpec *capsulev1beta1.ForbiddenListSpec) error { +func NewNamespaceAnnotationForbiddenError(annotation string, forbiddenSpec *capsuleapi.ForbiddenListSpec) error { return &namespaceAnnotationForbiddenError{ annotation: annotation, spec: forbiddenSpec, diff --git a/pkg/webhook/namespace/freezed.go b/pkg/webhook/namespace/freezed.go index 290217a4..a9a1234d 100644 --- a/pkg/webhook/namespace/freezed.go +++ b/pkg/webhook/namespace/freezed.go @@ -13,7 +13,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/configuration" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" @@ -36,12 +36,12 @@ func (r *freezedHandler) OnCreate(client client.Client, decoder *admission.Decod for _, objectRef := range ns.ObjectMeta.OwnerReferences { // retrieving the selected Tenant - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} if err := client.Get(ctx, types.NamespacedName{Name: objectRef.Name}, tnt); err != nil { return utils.ErroredResponse(err) } - if tnt.IsCordoned() { + if tnt.Spec.Cordoned { recorder.Eventf(tnt, corev1.EventTypeWarning, "TenantFreezed", "Namespace %s cannot be attached, the current Tenant is freezed", ns.GetName()) response := admission.Denied("the selected Tenant is freezed") @@ -56,7 +56,7 @@ func (r *freezedHandler) OnCreate(client client.Client, decoder *admission.Decod func (r *freezedHandler) OnDelete(c client.Client, _ *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func { return func(ctx context.Context, req admission.Request) *admission.Response { - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := c.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", req.Name), }); err != nil { @@ -69,7 +69,7 @@ func (r *freezedHandler) OnDelete(c client.Client, _ *admission.Decoder, recorde tnt := tntList.Items[0] - if tnt.IsCordoned() && utils.IsCapsuleUser(ctx, req, c, r.configuration.UserGroups()) { + if tnt.Spec.Cordoned && utils.IsCapsuleUser(ctx, req, c, r.configuration.UserGroups()) { recorder.Eventf(&tnt, corev1.EventTypeWarning, "TenantFreezed", "Namespace %s cannot be deleted, the current Tenant is freezed", req.Name) response := admission.Denied("the selected Tenant is freezed") @@ -88,7 +88,7 @@ func (r *freezedHandler) OnUpdate(c client.Client, decoder *admission.Decoder, r return utils.ErroredResponse(err) } - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := c.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", ns.Name), }); err != nil { @@ -101,7 +101,7 @@ func (r *freezedHandler) OnUpdate(c client.Client, decoder *admission.Decoder, r tnt := tntList.Items[0] - if tnt.IsCordoned() && utils.IsCapsuleUser(ctx, req, c, r.configuration.UserGroups()) { + if tnt.Spec.Cordoned && utils.IsCapsuleUser(ctx, req, c, r.configuration.UserGroups()) { recorder.Eventf(&tnt, corev1.EventTypeWarning, "TenantFreezed", "Namespace %s cannot be updated, the current Tenant is freezed", ns.GetName()) response := admission.Denied("the selected Tenant is freezed") diff --git a/pkg/webhook/namespace/patch.go b/pkg/webhook/namespace/patch.go index 23dcaeb6..18f1e972 100644 --- a/pkg/webhook/namespace/patch.go +++ b/pkg/webhook/namespace/patch.go @@ -14,8 +14,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" - utils2 "github.com/clastix/capsule/pkg/utils" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" + capsuleutils "github.com/clastix/capsule/pkg/utils" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -47,7 +47,7 @@ func (r *patchHandler) OnUpdate(c client.Client, decoder *admission.Decoder, rec } // Get Tenant Label - ln, err := utils2.GetTypeLabel(&capsulev1beta1.Tenant{}) + ln, err := capsuleutils.GetTypeLabel(&capsulev1beta2.Tenant{}) if err != nil { response := admission.Errored(http.StatusBadRequest, err) @@ -59,7 +59,7 @@ func (r *patchHandler) OnUpdate(c client.Client, decoder *admission.Decoder, rec if label, ok := ns.ObjectMeta.Labels[ln]; ok { // retrieving the selected Tenant - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} if err = c.Get(ctx, types.NamespacedName{Name: label}, tnt); err != nil { response := admission.Errored(http.StatusBadRequest, err) diff --git a/pkg/webhook/namespace/prefix.go b/pkg/webhook/namespace/prefix.go index 14cf74d2..7c998ba6 100644 --- a/pkg/webhook/namespace/prefix.go +++ b/pkg/webhook/namespace/prefix.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/configuration" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" @@ -46,7 +46,7 @@ func (r *prefixHandler) OnCreate(clt client.Client, decoder *admission.Decoder, } if r.configuration.ForceTenantPrefix() { - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} for _, or := range ns.ObjectMeta.OwnerReferences { // retrieving the selected Tenant diff --git a/pkg/webhook/namespace/quota.go b/pkg/webhook/namespace/quota.go index 0517c7e9..86010e86 100644 --- a/pkg/webhook/namespace/quota.go +++ b/pkg/webhook/namespace/quota.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -32,7 +32,7 @@ func (r *quotaHandler) OnCreate(client client.Client, decoder *admission.Decoder for _, objectRef := range ns.ObjectMeta.OwnerReferences { // retrieving the selected Tenant - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} if err := client.Get(ctx, types.NamespacedName{Name: objectRef.Name}, tnt); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/namespace/user_metadata.go b/pkg/webhook/namespace/user_metadata.go index b4dc3489..2a90df1e 100644 --- a/pkg/webhook/namespace/user_metadata.go +++ b/pkg/webhook/namespace/user_metadata.go @@ -13,7 +13,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -24,9 +24,9 @@ func UserMetadataHandler() capsulewebhook.Handler { return &userMetadataHandler{} } -func (r *userMetadataHandler) validateUserMetadata(tnt *capsulev1beta1.Tenant, recorder record.EventRecorder, labels map[string]string, annotations map[string]string) *admission.Response { - if tnt.ForbiddenUserNamespaceLabels() != nil { - forbiddenLabels := tnt.ForbiddenUserNamespaceLabels() +func (r *userMetadataHandler) validateUserMetadata(tnt *capsulev1beta2.Tenant, recorder record.EventRecorder, labels map[string]string, annotations map[string]string) *admission.Response { + if tnt.Spec.NamespaceOptions != nil { + forbiddenLabels := tnt.Spec.NamespaceOptions.ForbiddenLabels for label := range labels { var forbidden, matched bool @@ -36,28 +36,30 @@ func (r *userMetadataHandler) validateUserMetadata(tnt *capsulev1beta1.Tenant, r if forbidden || matched { recorder.Eventf(tnt, corev1.EventTypeWarning, "ForbiddenNamespaceLabel", fmt.Sprintf("Label %s is forbidden for a namespaces of the current Tenant ", label)) - response := admission.Denied(NewNamespaceLabelForbiddenError(label, forbiddenLabels).Error()) + response := admission.Denied(NewNamespaceLabelForbiddenError(label, &forbiddenLabels).Error()) return &response } } } - if tnt.ForbiddenUserNamespaceAnnotations() != nil { - forbiddenAnnotations := tnt.ForbiddenUserNamespaceLabels() + if tnt.Spec.NamespaceOptions == nil { + return nil + } - for annotation := range annotations { - var forbidden, matched bool - forbidden = forbiddenAnnotations.ExactMatch(annotation) - matched = forbiddenAnnotations.RegexMatch(annotation) + forbiddenAnnotations := tnt.Spec.NamespaceOptions.ForbiddenLabels - if forbidden || matched { - recorder.Eventf(tnt, corev1.EventTypeWarning, "ForbiddenNamespaceAnnotation", fmt.Sprintf("Annotation %s is forbidden for a namespaces of the current Tenant ", annotation)) + for annotation := range annotations { + var forbidden, matched bool + forbidden = forbiddenAnnotations.ExactMatch(annotation) + matched = forbiddenAnnotations.RegexMatch(annotation) - response := admission.Denied(NewNamespaceAnnotationForbiddenError(annotation, forbiddenAnnotations).Error()) + if forbidden || matched { + recorder.Eventf(tnt, corev1.EventTypeWarning, "ForbiddenNamespaceAnnotation", fmt.Sprintf("Annotation %s is forbidden for a namespaces of the current Tenant ", annotation)) - return &response - } + response := admission.Denied(NewNamespaceAnnotationForbiddenError(annotation, &forbiddenAnnotations).Error()) + + return &response } } @@ -71,7 +73,7 @@ func (r *userMetadataHandler) OnCreate(client client.Client, decoder *admission. return utils.ErroredResponse(err) } - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} for _, objectRef := range ns.ObjectMeta.OwnerReferences { // retrieving the selected Tenant if err := client.Get(ctx, types.NamespacedName{Name: objectRef.Name}, tnt); err != nil { @@ -104,7 +106,7 @@ func (r *userMetadataHandler) OnUpdate(client client.Client, decoder *admission. return utils.ErroredResponse(err) } - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} for _, objectRef := range newNs.ObjectMeta.OwnerReferences { // retrieving the selected Tenant if err := client.Get(ctx, types.NamespacedName{Name: objectRef.Name}, tnt); err != nil { diff --git a/pkg/webhook/networkpolicy/validating.go b/pkg/webhook/networkpolicy/validating.go index 35d01507..c63d65ed 100644 --- a/pkg/webhook/networkpolicy/validating.go +++ b/pkg/webhook/networkpolicy/validating.go @@ -13,8 +13,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" - utils2 "github.com/clastix/capsule/pkg/utils" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" + capsuleutils "github.com/clastix/capsule/pkg/utils" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -31,7 +31,7 @@ func (r *handler) OnCreate(client.Client, *admission.Decoder, record.EventRecord } } -func (r *handler) generic(ctx context.Context, req admission.Request, client client.Client, _ *admission.Decoder) (*capsulev1beta1.Tenant, error) { +func (r *handler) generic(ctx context.Context, req admission.Request, client client.Client, _ *admission.Decoder) (*capsulev1beta2.Tenant, error) { var err error np := &networkingv1.NetworkPolicy{} @@ -39,9 +39,9 @@ func (r *handler) generic(ctx context.Context, req admission.Request, client cli return nil, err } - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} - l, _ := utils2.GetTypeLabel(&capsulev1beta1.Tenant{}) + l, _ := capsuleutils.GetTypeLabel(&capsulev1beta2.Tenant{}) if v, ok := np.GetLabels()[l]; ok { if err = client.Get(ctx, types.NamespacedName{Name: v}, tnt); err != nil { return nil, err diff --git a/pkg/webhook/node/errors.go b/pkg/webhook/node/errors.go index e8435a78..2bd22a85 100644 --- a/pkg/webhook/node/errors.go +++ b/pkg/webhook/node/errors.go @@ -7,11 +7,11 @@ import ( "fmt" "strings" - capsulev1beta1 "github.com/clastix/capsule/pkg/api" + capsulev1beta2 "github.com/clastix/capsule/pkg/api" ) // nolint:predeclared -func appendForbiddenError(spec *capsulev1beta1.ForbiddenListSpec) (append string) { +func appendForbiddenError(spec *capsulev1beta2.ForbiddenListSpec) (append string) { append += "Forbidden are " if len(spec.Exact) > 0 { append += fmt.Sprintf("one of the following (%s)", strings.Join(spec.Exact, ", ")) @@ -28,10 +28,10 @@ func appendForbiddenError(spec *capsulev1beta1.ForbiddenListSpec) (append string } type nodeLabelForbiddenError struct { - spec *capsulev1beta1.ForbiddenListSpec + spec *capsulev1beta2.ForbiddenListSpec } -func NewNodeLabelForbiddenError(forbiddenSpec *capsulev1beta1.ForbiddenListSpec) error { +func NewNodeLabelForbiddenError(forbiddenSpec *capsulev1beta2.ForbiddenListSpec) error { return &nodeLabelForbiddenError{ spec: forbiddenSpec, } @@ -42,10 +42,10 @@ func (f nodeLabelForbiddenError) Error() string { } type nodeAnnotationForbiddenError struct { - spec *capsulev1beta1.ForbiddenListSpec + spec *capsulev1beta2.ForbiddenListSpec } -func NewNodeAnnotationForbiddenError(forbiddenSpec *capsulev1beta1.ForbiddenListSpec) error { +func NewNodeAnnotationForbiddenError(forbiddenSpec *capsulev1beta2.ForbiddenListSpec) error { return &nodeAnnotationForbiddenError{ spec: forbiddenSpec, } diff --git a/pkg/webhook/ownerreference/patching.go b/pkg/webhook/ownerreference/patching.go index 2a39aba7..fb950cba 100644 --- a/pkg/webhook/ownerreference/patching.go +++ b/pkg/webhook/ownerreference/patching.go @@ -19,9 +19,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/configuration" - utils2 "github.com/clastix/capsule/pkg/utils" + capsuleutils "github.com/clastix/capsule/pkg/utils" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -62,7 +62,7 @@ func (h *handler) setOwnerRef(ctx context.Context, req admission.Request, client return &response } - ln, err := utils2.GetTypeLabel(&capsulev1beta1.Tenant{}) + ln, err := capsuleutils.GetTypeLabel(&capsulev1beta2.Tenant{}) if err != nil { response := admission.Errored(http.StatusBadRequest, err) @@ -71,7 +71,7 @@ func (h *handler) setOwnerRef(ctx context.Context, req admission.Request, client // If we already had TenantName label on NS -> assign to it if label, ok := ns.ObjectMeta.Labels[ln]; ok { // retrieving the selected Tenant - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} if err = client.Get(ctx, types.NamespacedName{Name: label}, tnt); err != nil { response := admission.Errored(http.StatusBadRequest, err) @@ -96,7 +96,7 @@ func (h *handler) setOwnerRef(ctx context.Context, req admission.Request, client // Find tenants belonging to user (it can be regular user or ServiceAccount) if strings.HasPrefix(req.UserInfo.Username, "system:serviceaccount:") { - var tntList *capsulev1beta1.TenantList + var tntList *capsulev1beta2.TenantList if tntList, err = h.listTenantsForOwnerKind(ctx, "ServiceAccount", req.UserInfo.Username, client); err != nil { response := admission.Errored(http.StatusBadRequest, err) @@ -108,7 +108,7 @@ func (h *handler) setOwnerRef(ctx context.Context, req admission.Request, client tenants = append(tenants, tnt) } } else { - var tntList *capsulev1beta1.TenantList + var tntList *capsulev1beta2.TenantList if tntList, err = h.listTenantsForOwnerKind(ctx, "User", req.UserInfo.Username, client); err != nil { response := admission.Errored(http.StatusBadRequest, err) @@ -170,9 +170,9 @@ func (h *handler) setOwnerRef(ctx context.Context, req admission.Request, client return &response } -func (h *handler) patchResponseForOwnerRef(tenant *capsulev1beta1.Tenant, ns *corev1.Namespace, recorder record.EventRecorder) admission.Response { +func (h *handler) patchResponseForOwnerRef(tenant *capsulev1beta2.Tenant, ns *corev1.Namespace, recorder record.EventRecorder) admission.Response { scheme := runtime.NewScheme() - _ = capsulev1beta1.AddToScheme(scheme) + _ = capsulev1beta2.AddToScheme(scheme) _ = corev1.AddToScheme(scheme) o, err := json.Marshal(ns.DeepCopy()) @@ -196,8 +196,8 @@ func (h *handler) patchResponseForOwnerRef(tenant *capsulev1beta1.Tenant, ns *co return admission.PatchResponseFromRaw(o, c) } -func (h *handler) listTenantsForOwnerKind(ctx context.Context, ownerKind string, ownerName string, clt client.Client) (*capsulev1beta1.TenantList, error) { - tntList := &capsulev1beta1.TenantList{} +func (h *handler) listTenantsForOwnerKind(ctx context.Context, ownerKind string, ownerName string, clt client.Client) (*capsulev1beta2.TenantList, error) { + tntList := &capsulev1beta2.TenantList{} fields := client.MatchingFields{ ".spec.owner.ownerkind": fmt.Sprintf("%s:%s", ownerKind, ownerName), } @@ -206,7 +206,7 @@ func (h *handler) listTenantsForOwnerKind(ctx context.Context, ownerKind string, return tntList, err } -type sortedTenants []capsulev1beta1.Tenant +type sortedTenants []capsulev1beta2.Tenant func (s sortedTenants) Len() int { return len(s) diff --git a/pkg/webhook/pod/containerregistry.go b/pkg/webhook/pod/containerregistry.go index fbb11af8..9f576a94 100644 --- a/pkg/webhook/pod/containerregistry.go +++ b/pkg/webhook/pod/containerregistry.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -30,7 +30,7 @@ func (h *containerRegistryHandler) OnCreate(c client.Client, decoder *admission. return utils.ErroredResponse(err) } - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := c.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", pod.Namespace), }); err != nil { diff --git a/pkg/webhook/pod/imagepullpolicy.go b/pkg/webhook/pod/imagepullpolicy.go index f1ed80d4..3b160b20 100644 --- a/pkg/webhook/pod/imagepullpolicy.go +++ b/pkg/webhook/pod/imagepullpolicy.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -30,7 +30,7 @@ func (r *imagePullPolicy) OnCreate(c client.Client, decoder *admission.Decoder, return utils.ErroredResponse(err) } - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := c.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", pod.Namespace), }); err != nil { diff --git a/pkg/webhook/pod/imagepullpolicy_pullpolicy.go b/pkg/webhook/pod/imagepullpolicy_pullpolicy.go index 884c250f..ccafe549 100644 --- a/pkg/webhook/pod/imagepullpolicy_pullpolicy.go +++ b/pkg/webhook/pod/imagepullpolicy_pullpolicy.go @@ -6,7 +6,7 @@ package pod import ( "strings" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) type PullPolicy interface { @@ -32,7 +32,7 @@ func (i imagePullPolicyValidator) AllowedPullPolicies() []string { return i.allowedPolicies } -func NewPullPolicy(tenant *capsulev1beta1.Tenant) PullPolicy { +func NewPullPolicy(tenant *capsulev1beta2.Tenant) PullPolicy { // the Tenant doesn't enforce the allowed image pull policy, returning nil if len(tenant.Spec.ImagePullPolicies) == 0 { return nil diff --git a/pkg/webhook/pod/priorityclass.go b/pkg/webhook/pod/priorityclass.go index 3bd7bd5e..7a2515d0 100644 --- a/pkg/webhook/pod/priorityclass.go +++ b/pkg/webhook/pod/priorityclass.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -30,7 +30,7 @@ func (h *priorityClass) OnCreate(c client.Client, decoder *admission.Decoder, re return utils.ErroredResponse(err) } - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := c.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", pod.Namespace), diff --git a/pkg/webhook/pvc/validating.go b/pkg/webhook/pvc/validating.go index 579a47f8..8a54bfa8 100644 --- a/pkg/webhook/pvc/validating.go +++ b/pkg/webhook/pvc/validating.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -32,7 +32,7 @@ func (h *handler) OnCreate(c client.Client, decoder *admission.Decoder, recorder return utils.ErroredResponse(err) } - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := c.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", pvc.Namespace), }); err != nil { diff --git a/pkg/webhook/route/tenants.go b/pkg/webhook/route/tenants.go index 63552ffe..8059c8f7 100644 --- a/pkg/webhook/route/tenants.go +++ b/pkg/webhook/route/tenants.go @@ -7,7 +7,7 @@ import ( capsulewebhook "github.com/clastix/capsule/pkg/webhook" ) -// +kubebuilder:webhook:path=/tenants,mutating=false,sideEffects=None,admissionReviewVersions=v1,failurePolicy=fail,groups="capsule.clastix.io",resources=tenants,verbs=create;update;delete,versions=v1beta1,name=tenants.capsule.clastix.io +// +kubebuilder:webhook:path=/tenants,mutating=false,sideEffects=None,admissionReviewVersions=v1,failurePolicy=fail,groups="capsule.clastix.io",resources=tenants,verbs=create;update;delete,versions=v1beta2,name=tenants.capsule.clastix.io type tenant struct { handlers []capsulewebhook.Handler diff --git a/pkg/webhook/service/validating.go b/pkg/webhook/service/validating.go index 1de66e2e..3dda98bb 100644 --- a/pkg/webhook/service/validating.go +++ b/pkg/webhook/service/validating.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -31,7 +31,7 @@ func (r *handler) handleService(ctx context.Context, clt client.Client, decoder return utils.ErroredResponse(err) } - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := clt.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", svc.GetNamespace()), }); err != nil { diff --git a/pkg/webhook/tenant/containerregistry_regex.go b/pkg/webhook/tenant/containerregistry_regex.go index 41e490e7..2445e896 100644 --- a/pkg/webhook/tenant/containerregistry_regex.go +++ b/pkg/webhook/tenant/containerregistry_regex.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -24,7 +24,7 @@ func ContainerRegistryRegexHandler() capsulewebhook.Handler { } func (h *containerRegistryRegexHandler) validate(decoder *admission.Decoder, req admission.Request) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/tenant/cordoning.go b/pkg/webhook/tenant/cordoning.go index cc024ac7..13b6a3f8 100644 --- a/pkg/webhook/tenant/cordoning.go +++ b/pkg/webhook/tenant/cordoning.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/configuration" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" @@ -31,7 +31,7 @@ func CordoningHandler(configuration configuration.Configuration) capsulewebhook. } func (h *cordoningHandler) cordonHandler(ctx context.Context, clt client.Client, req admission.Request, recorder record.EventRecorder) *admission.Response { - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := clt.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", req.Namespace), @@ -44,7 +44,7 @@ func (h *cordoningHandler) cordonHandler(ctx context.Context, clt client.Client, } tnt := tntList.Items[0] - if tnt.IsCordoned() && utils.IsCapsuleUser(ctx, req, clt, h.configuration.UserGroups()) { + if tnt.Spec.Cordoned && utils.IsCapsuleUser(ctx, req, clt, h.configuration.UserGroups()) { recorder.Eventf(&tnt, corev1.EventTypeWarning, "TenantFreezed", "%s %s/%s cannot be %sd, current Tenant is freezed", req.Kind.String(), req.Namespace, req.Name, strings.ToLower(string(req.Operation))) response := admission.Denied(fmt.Sprintf("tenant %s is freezed: please, reach out to the system administrator", tnt.GetName())) diff --git a/pkg/webhook/tenant/custom_resource_quota.go b/pkg/webhook/tenant/custom_resource_quota.go index e997e1de..d8cbd7cc 100644 --- a/pkg/webhook/tenant/custom_resource_quota.go +++ b/pkg/webhook/tenant/custom_resource_quota.go @@ -16,7 +16,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -36,7 +36,7 @@ func ResourceCounterHandler() capsulewebhook.Handler { } func (r *resourceCounterHandler) getTenantName(ctx context.Context, clt client.Client, req admission.Request) (string, error) { - tntList := &capsulev1beta1.TenantList{} + tntList := &capsulev1beta2.TenantList{} if err := clt.List(ctx, tntList, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", req.Namespace), @@ -67,7 +67,7 @@ func (r *resourceCounterHandler) OnCreate(clt client.Client, decoder *admission. kgv := fmt.Sprintf("%s.%s_%s", req.Resource.Resource, req.Resource.Group, req.Resource.Version) - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} var limit int64 @@ -76,20 +76,20 @@ func (r *resourceCounterHandler) OnCreate(clt client.Client, decoder *admission. return retryErr } - if limit, retryErr = capsulev1beta1.GetLimitResourceFromTenant(*tnt, kgv); retryErr != nil { - if errors.As(err, &capsulev1beta1.NonLimitedResourceError{}) { + if limit, retryErr = capsulev1beta2.GetLimitResourceFromTenant(*tnt, kgv); retryErr != nil { + if errors.As(err, &capsulev1beta2.NonLimitedResourceError{}) { return nil } return err } - used, _ := capsulev1beta1.GetUsedResourceFromTenant(*tnt, kgv) + used, _ := capsulev1beta2.GetUsedResourceFromTenant(*tnt, kgv) if used >= limit { return NewCustomResourceQuotaError(kgv, limit) } - tnt.Annotations[capsulev1beta1.UsedAnnotationForResource(kgv)] = fmt.Sprintf("%d", used+1) + tnt.Annotations[capsulev1beta2.UsedAnnotationForResource(kgv)] = fmt.Sprintf("%d", used+1) return clt.Update(ctx, tnt) }) @@ -122,7 +122,7 @@ func (r *resourceCounterHandler) OnDelete(clt client.Client, decoder *admission. kgv := fmt.Sprintf("%s.%s_%s", req.Resource.Resource, req.Resource.Group, req.Resource.Version) err = retry.RetryOnConflict(retry.DefaultRetry, func() (retryErr error) { - tnt := &capsulev1beta1.Tenant{} + tnt := &capsulev1beta2.Tenant{} if retryErr = clt.Get(ctx, types.NamespacedName{Name: tntName}, tnt); err != nil { return } @@ -131,13 +131,13 @@ func (r *resourceCounterHandler) OnDelete(clt client.Client, decoder *admission. return } - if _, ok := tnt.Annotations[capsulev1beta1.UsedAnnotationForResource(kgv)]; !ok { + if _, ok := tnt.Annotations[capsulev1beta2.UsedAnnotationForResource(kgv)]; !ok { return } - used, _ := capsulev1beta1.GetUsedResourceFromTenant(*tnt, kgv) + used, _ := capsulev1beta2.GetUsedResourceFromTenant(*tnt, kgv) - tnt.Annotations[capsulev1beta1.UsedAnnotationForResource(kgv)] = fmt.Sprintf("%d", used-1) + tnt.Annotations[capsulev1beta2.UsedAnnotationForResource(kgv)] = fmt.Sprintf("%d", used-1) return clt.Update(ctx, tnt) }) diff --git a/pkg/webhook/tenant/forbidden_annotations_regex.go b/pkg/webhook/tenant/forbidden_annotations_regex.go index 61f47c2e..3cfb79f2 100644 --- a/pkg/webhook/tenant/forbidden_annotations_regex.go +++ b/pkg/webhook/tenant/forbidden_annotations_regex.go @@ -5,13 +5,14 @@ package tenant import ( "context" + "fmt" "regexp" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -23,23 +24,23 @@ func ForbiddenAnnotationsRegexHandler() capsulewebhook.Handler { } func (h *forbiddenAnnotationsRegexHandler) validate(decoder *admission.Decoder, req admission.Request) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } - if tenant.Annotations == nil { + if tenant.Spec.NamespaceOptions == nil { return nil } - annotationsToCheck := []string{ - capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation, - capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation, + annotationsToCheck := map[string]string{ + "labels": tenant.Spec.NamespaceOptions.ForbiddenLabels.Regex, + "annotations": tenant.Spec.NamespaceOptions.ForbiddenAnnotations.Regex, } - for _, annotation := range annotationsToCheck { - if _, err := regexp.Compile(tenant.Annotations[annotation]); err != nil { - response := admission.Denied("unable to compile " + annotation + " regex annotation") + for scope, annotation := range annotationsToCheck { + if _, err := regexp.Compile(tenant.Spec.NamespaceOptions.ForbiddenLabels.Regex); err != nil { + response := admission.Denied(fmt.Sprintf("unable to compile %s regex for forbidden %s", annotation, scope)) return &response } diff --git a/pkg/webhook/tenant/freezed_emitter.go b/pkg/webhook/tenant/freezed_emitter.go index 7a7a627e..a4c2d228 100644 --- a/pkg/webhook/tenant/freezed_emitter.go +++ b/pkg/webhook/tenant/freezed_emitter.go @@ -11,7 +11,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -36,20 +36,20 @@ func (h *freezedEmitterHandler) OnDelete(client.Client, *admission.Decoder, reco func (h *freezedEmitterHandler) OnUpdate(_ client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func { return func(ctx context.Context, req admission.Request) *admission.Response { - oldTnt := &capsulev1beta1.Tenant{} + oldTnt := &capsulev1beta2.Tenant{} if err := decoder.DecodeRaw(req.OldObject, oldTnt); err != nil { return utils.ErroredResponse(err) } - newTnt := &capsulev1beta1.Tenant{} + newTnt := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, newTnt); err != nil { return utils.ErroredResponse(err) } switch { - case !oldTnt.IsCordoned() && newTnt.IsCordoned(): + case !oldTnt.Spec.Cordoned && newTnt.Spec.Cordoned: recorder.Eventf(newTnt, corev1.EventTypeNormal, "TenantCordoned", "Tenant has been cordoned") - case oldTnt.IsCordoned() && !newTnt.IsCordoned(): + case oldTnt.Spec.Cordoned && !newTnt.Spec.Cordoned: recorder.Eventf(newTnt, corev1.EventTypeNormal, "TenantUncordoned", "Tenant has been uncordoned") } diff --git a/pkg/webhook/tenant/hostname_regex.go b/pkg/webhook/tenant/hostname_regex.go index f1184bf3..23c68dc5 100644 --- a/pkg/webhook/tenant/hostname_regex.go +++ b/pkg/webhook/tenant/hostname_regex.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -24,7 +24,7 @@ func HostnameRegexHandler() capsulewebhook.Handler { } func (h *hostnameRegexHandler) validate(decoder *admission.Decoder, req admission.Request) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/tenant/ingressclass_regex.go b/pkg/webhook/tenant/ingressclass_regex.go index c9e91523..e3349338 100644 --- a/pkg/webhook/tenant/ingressclass_regex.go +++ b/pkg/webhook/tenant/ingressclass_regex.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -24,7 +24,7 @@ func IngressClassRegexHandler() capsulewebhook.Handler { } func (h *ingressClassRegexHandler) validate(decoder *admission.Decoder, req admission.Request) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/tenant/name.go b/pkg/webhook/tenant/name.go index 0e44a4bb..96ab98b3 100644 --- a/pkg/webhook/tenant/name.go +++ b/pkg/webhook/tenant/name.go @@ -11,7 +11,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -24,7 +24,7 @@ func NameHandler() capsulewebhook.Handler { func (h *nameHandler) OnCreate(_ client.Client, decoder *admission.Decoder, _ record.EventRecorder) capsulewebhook.Func { return func(ctx context.Context, req admission.Request) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/tenant/protected.go b/pkg/webhook/tenant/protected.go index b5a5a18d..72d3612f 100644 --- a/pkg/webhook/tenant/protected.go +++ b/pkg/webhook/tenant/protected.go @@ -5,14 +5,13 @@ package tenant import ( "context" - "fmt" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -31,14 +30,14 @@ func (h *protectedHandler) OnCreate(client.Client, *admission.Decoder, record.Ev func (h *protectedHandler) OnDelete(clt client.Client, decoder *admission.Decoder, _ record.EventRecorder) capsulewebhook.Func { return func(ctx context.Context, req admission.Request) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := clt.Get(ctx, types.NamespacedName{Name: req.AdmissionRequest.Name}, tenant); err != nil { return utils.ErroredResponse(err) } - if _, protected := tenant.Annotations[capsulev1beta1.ProtectedTenantAnnotation]; protected { - response := admission.Denied(fmt.Sprintf("tenant is protected and cannot be deleted, remove %s annotation before proceeding", capsulev1beta1.ProtectedTenantAnnotation)) + if tenant.Spec.PreventDeletion { + response := admission.Denied("tenant is protected and cannot be deleted") return &response } diff --git a/pkg/webhook/tenant/rolebindings_regex.go b/pkg/webhook/tenant/rolebindings_regex.go index 63ba86df..cb7a655c 100644 --- a/pkg/webhook/tenant/rolebindings_regex.go +++ b/pkg/webhook/tenant/rolebindings_regex.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -26,7 +26,7 @@ func RoleBindingRegexHandler() capsulewebhook.Handler { } func (h *rbRegexHandler) validate(req admission.Request, decoder *admission.Decoder) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/tenant/serviceaccount_format.go b/pkg/webhook/tenant/serviceaccount_format.go index 96da0066..6a394b15 100644 --- a/pkg/webhook/tenant/serviceaccount_format.go +++ b/pkg/webhook/tenant/serviceaccount_format.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -24,7 +24,7 @@ func ServiceAccountNameHandler() capsulewebhook.Handler { } func (h *saNameHandler) validateServiceAccountName(req admission.Request, decoder *admission.Decoder) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/tenant/storageclass_regex.go b/pkg/webhook/tenant/storageclass_regex.go index 93ac9f31..9719ea6a 100644 --- a/pkg/webhook/tenant/storageclass_regex.go +++ b/pkg/webhook/tenant/storageclass_regex.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" capsulewebhook "github.com/clastix/capsule/pkg/webhook" "github.com/clastix/capsule/pkg/webhook/utils" ) @@ -24,7 +24,7 @@ func StorageClassRegexHandler() capsulewebhook.Handler { } func (h *storageClassRegexHandler) validate(decoder *admission.Decoder, req admission.Request) *admission.Response { - tenant := &capsulev1beta1.Tenant{} + tenant := &capsulev1beta2.Tenant{} if err := decoder.Decode(req, tenant); err != nil { return utils.ErroredResponse(err) } diff --git a/pkg/webhook/utils/is_capsule_user.go b/pkg/webhook/utils/is_capsule_user.go index fd933ea4..aeb37476 100644 --- a/pkg/webhook/utils/is_capsule_user.go +++ b/pkg/webhook/utils/is_capsule_user.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" "github.com/clastix/capsule/pkg/utils" ) @@ -31,7 +31,7 @@ func IsCapsuleUser(ctx context.Context, req admission.Request, clt client.Client targetNamespace := parts[2] if len(targetNamespace) > 0 { - tl := &capsulev1beta1.TenantList{} + tl := &capsulev1beta2.TenantList{} if err := clt.List(ctx, tl, client.MatchingFieldsSelector{Selector: fields.OneTermEqualSelector(".status.namespaces", targetNamespace)}); err != nil { return false } diff --git a/pkg/webhook/utils/is_tenant_owner.go b/pkg/webhook/utils/is_tenant_owner.go index 0d6f39b3..bd14f9a4 100644 --- a/pkg/webhook/utils/is_tenant_owner.go +++ b/pkg/webhook/utils/is_tenant_owner.go @@ -6,17 +6,17 @@ package utils import ( authenticationv1 "k8s.io/api/authentication/v1" - capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulev1beta2 "github.com/clastix/capsule/api/v1beta2" ) -func IsTenantOwner(owners capsulev1beta1.OwnerListSpec, userInfo authenticationv1.UserInfo) bool { +func IsTenantOwner(owners capsulev1beta2.OwnerListSpec, userInfo authenticationv1.UserInfo) bool { for _, owner := range owners { switch owner.Kind { - case capsulev1beta1.UserOwner, capsulev1beta1.ServiceAccountOwner: + case capsulev1beta2.UserOwner, capsulev1beta2.ServiceAccountOwner: if userInfo.Username == owner.Name { return true } - case capsulev1beta1.GroupOwner: + case capsulev1beta2.GroupOwner: for _, group := range userInfo.Groups { if group == owner.Name { return true