diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml
index d26d9fea..69a7b0ae 100644
--- a/.github/workflows/helm.yml
+++ b/.github/workflows/helm.yml
@@ -42,23 +42,31 @@ jobs:
else
echo -e '\033[0;32mDocumentation up to date\033[0m ✔'
fi
- # Create KIND Cluster
- - name: Create kind cluster
- uses: helm/kind-action@v1.2.0
- if: steps.list-changed.outputs.changed == 'true'
- # Install Required Operators/CRDs
- - name: Prepare Cluster Operators/CRDs
- run: |
- # Cert-Manager CRDs
- kubectl create -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.crds.yaml
-
- # Prometheus CRDs
- kubectl create -f https://github.com/prometheus-operator/prometheus-operator/releases/download/v0.58.0/bundle.yaml
- if: steps.list-changed.outputs.changed == 'true'
- # Install Charts
+
+ # ATTENTION: This is a workaround for the upcoming ApiVersion Conversions for the capsule CRDs
+ # With this workflow the current docker image is build and loaded into kind, otherwise the install fails
+ # In the future this must be removed and the chart-testing-action must be used
- name: Run chart-testing (install)
- run: ct install --debug --config ./.github/configs/ct.yaml
+ run: make helm-test
if: steps.list-changed.outputs.changed == 'true'
+
+ ## Create KIND Cluster
+ #- name: Create kind cluster
+ # uses: helm/kind-action@v1.2.0
+ # if: steps.list-changed.outputs.changed == 'true'
+ ## Install Required Operators/CRDs
+ #- name: Prepare Cluster Operators/CRDs
+ # run: |
+ # # Cert-Manager CRDs
+ # kubectl create -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.crds.yaml
+ #
+ # # Prometheus CRDs
+ # kubectl create -f https://github.com/prometheus-operator/prometheus-operator/releases/download/v0.58.0/bundle.yaml
+ # if: steps.list-changed.outputs.changed == 'true'
+ ## Install Charts
+ #- name: Run chart-testing (install)
+ # run: ct install --debug --config ./.github/configs/ct.yaml
+ # if: steps.list-changed.outputs.changed == 'true'
release:
if: startsWith(github.ref, 'refs/tags/helm-v')
runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index d7c49bbe..b9a90ae4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,3 @@ bin
**/*.key
.DS_Store
*.tgz
-
-capsule
-
diff --git a/Makefile b/Makefile
index b2d08df0..419f9664 100644
--- a/Makefile
+++ b/Makefile
@@ -86,8 +86,15 @@ helm-docs: HELMDOCS_VERSION := v1.11.0
helm-docs: docker
@docker run -v "$(SRC_ROOT):/helm-docs" jnorwood/helm-docs:$(HELMDOCS_VERSION) --chart-search-root /helm-docs
-helm-lint: docker
- @docker run -v "$(SRC_ROOT):/workdir" --entrypoint /bin/sh quay.io/helmpack/chart-testing:v3.3.1 -c "cd /workdir && ct lint --config .github/configs/ct.yaml --lint-conf .github/configs/lintconf.yaml --all --debug"
+helm-lint: ct
+ @ct lint --config $(SRC_ROOT)/.github/configs/ct.yaml --lint-conf $(SRC_ROOT)/.github/configs/lintconf.yaml --all --debug
+
+helm-test: kind ct docker-build
+ @kind create cluster --wait=60s --name capsule-charts
+ @kind load docker-image --name capsule-charts ${IMG}
+ @kubectl create ns capsule-system
+ @ct install --config $(SRC_ROOT)/.github/configs/ct.yaml --namespace=capsule-system --all --debug
+ @kind delete cluster --name capsule-charts
docker:
@hash docker 2>/dev/null || {\
@@ -172,6 +179,14 @@ GINKGO = $(shell pwd)/bin/ginkgo
ginkgo: ## Download ginkgo locally if necessary.
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/ginkgo@v1.16.5)
+CT = $(shell pwd)/bin/ct
+ct: ## Download ct locally if necessary.
+ $(call go-install-tool,$(CT),github.com/helm/chart-testing/v3/ct@v3.7.1)
+
+KIND = $(shell pwd)/bin/kind
+kind: ## Download kind locally if necessary.
+ $(call go-install-tool,$(KIND),sigs.k8s.io/kind/cmd/kind@v0.17.0)
+
KUSTOMIZE = $(shell pwd)/bin/kustomize
kustomize: ## Download kustomize locally if necessary.
$(call install-kustomize,$(KUSTOMIZE),3.8.7)
diff --git a/api/v1alpha1/capsuleconfiguration_types.go b/api/v1alpha1/capsuleconfiguration_types.go
index 147bc485..ac404a25 100644
--- a/api/v1alpha1/capsuleconfiguration_types.go
+++ b/api/v1alpha1/capsuleconfiguration_types.go
@@ -20,7 +20,6 @@ type CapsuleConfigurationSpec struct {
ProtectedNamespaceRegexpString string `json:"protectedNamespaceRegex,omitempty"`
}
-// +kubebuilder:storageversion
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Cluster
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/conversion_hub_test.go b/api/v1alpha1/conversion_hub_test.go
index 275bfc1b..f2d4e9ab 100644
--- a/api/v1alpha1/conversion_hub_test.go
+++ b/api/v1alpha1/conversion_hub_test.go
@@ -61,9 +61,11 @@ func generateTenantsSpecs() (Tenant, capsulev1beta1.Tenant) {
Allowed: []api.AllowedIP{"192.168.0.1"},
},
}
- v1beta1AllowedListSpec := &api.AllowedListSpec{
- Exact: []string{"foo", "bar"},
- Regex: "^foo*",
+ v1beta2AllowedListSpec := &api.SelectorAllowedListSpec{
+ AllowedListSpec: api.AllowedListSpec{
+ Exact: []string{"foo", "bar"},
+ Regex: "^foo*",
+ },
}
networkPolicies := []networkingv1.NetworkPolicySpec{
{
@@ -235,13 +237,13 @@ func generateTenantsSpecs() (Tenant, capsulev1beta1.Tenant) {
},
NamespaceOptions: v1beta1NamespaceOptions,
ServiceOptions: v1beta1ServiceOptions,
- StorageClasses: v1beta1AllowedListSpec,
+ StorageClasses: &v1beta2AllowedListSpec.AllowedListSpec,
IngressOptions: capsulev1beta1.IngressOptions{
HostnameCollisionScope: api.HostnameCollisionScopeDisabled,
- AllowedClasses: v1beta1AllowedListSpec,
- AllowedHostnames: v1beta1AllowedListSpec,
+ AllowedClasses: &v1beta2AllowedListSpec.AllowedListSpec,
+ AllowedHostnames: &v1beta2AllowedListSpec.AllowedListSpec,
},
- ContainerRegistries: v1beta1AllowedListSpec,
+ ContainerRegistries: &v1beta2AllowedListSpec.AllowedListSpec,
NodeSelector: nodeSelector,
NetworkPolicies: api.NetworkPolicySpec{
Items: networkPolicies,
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_types.go b/api/v1beta1/tenant_types.go
index 72fa6c89..29cfd5b4 100644
--- a/api/v1beta1/tenant_types.go
+++ b/api/v1beta1/tenant_types.go
@@ -41,7 +41,6 @@ type TenantSpec struct {
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
-// +kubebuilder:storageversion
// +kubebuilder:resource:scope=Cluster,shortName=tnt
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state",description="The actual state of the Tenant"
// +kubebuilder:printcolumn:name="Namespace quota",type="integer",JSONPath=".spec.namespaceOptions.quota",description="The max amount of Namespaces can be created"
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 d9a56424..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
@@ -54,6 +55,7 @@ type CapsuleResources struct {
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Cluster
+// +kubebuilder:storageversion
// CapsuleConfiguration is the Schema for the Capsule configuration API.
type CapsuleConfiguration struct {
diff --git a/api/v1beta2/ingress_options.go b/api/v1beta2/ingress_options.go
index 3d4cd718..9e821afc 100644
--- a/api/v1beta2/ingress_options.go
+++ b/api/v1beta2/ingress_options.go
@@ -9,7 +9,7 @@ import (
type IngressOptions struct {
// Specifies the allowed IngressClasses assigned to the Tenant. Capsule assures that all Ingress resources created in the Tenant can use only one of the allowed IngressClasses. Optional.
- AllowedClasses *api.AllowedListSpec `json:"allowedClasses,omitempty"`
+ AllowedClasses *api.SelectorAllowedListSpec `json:"allowedClasses,omitempty"`
// Defines the scope of hostname collision check performed when Tenant Owners create Ingress with allowed hostnames.
//
//
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..a3dee20a 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,33 +59,37 @@ 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)
}
}
in.Spec.ServiceOptions = src.Spec.ServiceOptions
- in.Spec.StorageClasses = src.Spec.StorageClasses
+ if src.Spec.StorageClasses != nil {
+ in.Spec.StorageClasses = &api.SelectorAllowedListSpec{
+ AllowedListSpec: *src.Spec.StorageClasses,
+ }
+ }
if scope := src.Spec.IngressOptions.HostnameCollisionScope; len(scope) > 0 {
in.Spec.IngressOptions.HostnameCollisionScope = scope
@@ -101,7 +106,9 @@ func (in *Tenant) ConvertFrom(raw conversion.Hub) error {
}
if ingressClass := src.Spec.IngressOptions.AllowedClasses; ingressClass != nil {
- in.Spec.IngressOptions.AllowedClasses = ingressClass
+ in.Spec.IngressOptions.AllowedClasses = &api.SelectorAllowedListSpec{
+ AllowedListSpec: *ingressClass,
+ }
}
if hostnames := src.Spec.IngressOptions.AllowedHostnames; hostnames != nil {
@@ -115,7 +122,12 @@ func (in *Tenant) ConvertFrom(raw conversion.Hub) error {
in.Spec.ResourceQuota = src.Spec.ResourceQuota
in.Spec.AdditionalRoleBindings = src.Spec.AdditionalRoleBindings
in.Spec.ImagePullPolicies = src.Spec.ImagePullPolicies
- in.Spec.PriorityClasses = src.Spec.PriorityClasses
+
+ if src.Spec.PriorityClasses != nil {
+ in.Spec.PriorityClasses = &api.SelectorAllowedListSpec{
+ AllowedListSpec: *src.Spec.PriorityClasses,
+ }
+ }
if v, found := annotations["capsule.clastix.io/cordon"]; found {
value, err := strconv.ParseBool(v)
@@ -126,10 +138,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,29 +201,31 @@ 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
}
}
dst.Spec.ServiceOptions = in.Spec.ServiceOptions
- dst.Spec.StorageClasses = in.Spec.StorageClasses
+ if in.Spec.StorageClasses != nil {
+ dst.Spec.StorageClasses = &in.Spec.StorageClasses.AllowedListSpec
+ }
dst.Spec.IngressOptions.HostnameCollisionScope = in.Spec.IngressOptions.HostnameCollisionScope
if allowed := in.Spec.IngressOptions.AllowedClasses; allowed != nil {
- dst.Spec.IngressOptions.AllowedClasses = allowed
+ dst.Spec.IngressOptions.AllowedClasses = &allowed.AllowedListSpec
}
if allowed := in.Spec.IngressOptions.AllowedHostnames; allowed != nil {
@@ -230,10 +244,13 @@ func (in *Tenant) ConvertTo(raw conversion.Hub) error {
dst.Spec.ResourceQuota = in.Spec.ResourceQuota
dst.Spec.AdditionalRoleBindings = in.Spec.AdditionalRoleBindings
dst.Spec.ImagePullPolicies = in.Spec.ImagePullPolicies
- dst.Spec.PriorityClasses = in.Spec.PriorityClasses
+
+ if in.Spec.PriorityClasses != nil {
+ dst.Spec.PriorityClasses = &in.Spec.PriorityClasses.AllowedListSpec
+ }
if in.Spec.PreventDeletion {
- annotations[capsulev1beta1.ProtectedTenantAnnotation] = "true" //nolint:goconst
+ annotations[api.ProtectedTenantAnnotation] = "true" //nolint:goconst
}
if in.Spec.Cordoned {
diff --git a/api/v1beta2/tenant_types.go b/api/v1beta2/tenant_types.go
index f6960412..02001ae5 100644
--- a/api/v1beta2/tenant_types.go
+++ b/api/v1beta2/tenant_types.go
@@ -18,7 +18,7 @@ type TenantSpec struct {
// Specifies options for the Service, such as additional metadata or block of certain type of Services. Optional.
ServiceOptions *api.ServiceOptions `json:"serviceOptions,omitempty"`
// Specifies the allowed StorageClasses assigned to the Tenant. Capsule assures that all PersistentVolumeClaim resources created in the Tenant can use only one of the allowed StorageClasses. Optional.
- StorageClasses *api.AllowedListSpec `json:"storageClasses,omitempty"`
+ StorageClasses *api.SelectorAllowedListSpec `json:"storageClasses,omitempty"`
// Specifies options for the Ingress resources, such as allowed hostnames and IngressClass. Optional.
IngressOptions IngressOptions `json:"ingressOptions,omitempty"`
// Specifies the trusted Image Registries assigned to the Tenant. Capsule assures that all Pods resources created in the Tenant can use only one of the allowed trusted registries. Optional.
@@ -36,7 +36,7 @@ type TenantSpec struct {
// Specify the allowed values for the imagePullPolicies option in Pod resources. Capsule assures that all Pod resources created in the Tenant can use only one of the allowed policy. Optional.
ImagePullPolicies []api.ImagePullPolicySpec `json:"imagePullPolicies,omitempty"`
// Specifies the allowed priorityClasses assigned to the Tenant. Capsule assures that all Pods resources created in the Tenant can use only one of the allowed PriorityClasses. Optional.
- PriorityClasses *api.AllowedListSpec `json:"priorityClasses,omitempty"`
+ PriorityClasses *api.SelectorAllowedListSpec `json:"priorityClasses,omitempty"`
// Toggling the Tenant resources cordoning, when enable resources cannot be deleted.
Cordoned bool `json:"cordoned,omitempty"`
// Prevent accidental deletion of the Tenant.
@@ -45,6 +45,7 @@ type TenantSpec struct {
}
// +kubebuilder:object:root=true
+// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster,shortName=tnt
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state",description="The actual state of the Tenant"
diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go
index 06023ba2..248feb8f 100644
--- a/api/v1beta2/zz_generated.deepcopy.go
+++ b/api/v1beta2/zz_generated.deepcopy.go
@@ -261,7 +261,7 @@ func (in *IngressOptions) DeepCopyInto(out *IngressOptions) {
*out = *in
if in.AllowedClasses != nil {
in, out := &in.AllowedClasses, &out.AllowedClasses
- *out = new(api.AllowedListSpec)
+ *out = new(api.SelectorAllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.AllowedHostnames != nil {
@@ -718,7 +718,7 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) {
}
if in.StorageClasses != nil {
in, out := &in.StorageClasses, &out.StorageClasses
- *out = new(api.AllowedListSpec)
+ *out = new(api.SelectorAllowedListSpec)
(*in).DeepCopyInto(*out)
}
in.IngressOptions.DeepCopyInto(&out.IngressOptions)
@@ -751,7 +751,7 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) {
}
if in.PriorityClasses != nil {
in, out := &in.PriorityClasses, &out.PriorityClasses
- *out = new(api.AllowedListSpec)
+ *out = new(api.SelectorAllowedListSpec)
(*in).DeepCopyInto(*out)
}
}
diff --git a/charts/capsule/ci/test-values.yaml b/charts/capsule/ci/test-values.yaml
new file mode 100644
index 00000000..54daa068
--- /dev/null
+++ b/charts/capsule/ci/test-values.yaml
@@ -0,0 +1,9 @@
+fullnameOverride: capsule
+manager:
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 200m
+ memory: 128Mi
diff --git a/charts/capsule/crds/capsuleconfiguration-crd.yaml b/charts/capsule/crds/capsuleconfiguration-crd.yaml
index d20fb126..78c7945e 100644
--- a/charts/capsule/crds/capsuleconfiguration-crd.yaml
+++ b/charts/capsule/crds/capsuleconfiguration-crd.yaml
@@ -60,7 +60,7 @@ spec:
type: object
type: object
served: true
- storage: true
+ storage: false
- name: v1beta2
schema:
openAPIV3Schema:
@@ -113,6 +113,10 @@ spec:
- forbiddenLabels
type: object
overrides:
+ default:
+ TLSSecretName: capsule-tls
+ mutatingWebhookConfigurationName: capsule-mutating-webhook-configuration
+ validatingWebhookConfigurationName: capsule-validating-webhook-configuration
description: Allows to set different name rather than the canonical one for the Capsule configuration objects, such as webhook secret or configurations.
properties:
TLSSecretName:
@@ -144,9 +148,7 @@ spec:
type: array
required:
- enableTLSReconciler
- - nodeMetadata
- - overrides
type: object
type: object
served: true
- storage: false
+ storage: true
diff --git a/charts/capsule/crds/tenant-crd.yaml b/charts/capsule/crds/tenant-crd.yaml
index d018eabf..ef91fc79 100644
--- a/charts/capsule/crds/tenant-crd.yaml
+++ b/charts/capsule/crds/tenant-crd.yaml
@@ -1274,7 +1274,7 @@ spec:
type: object
type: object
served: true
- storage: true
+ storage: false
subresources:
status: {}
- additionalPrinterColumns:
@@ -1385,7 +1385,34 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
allowedHostnames:
description: Specifies the allowed hostnames in Ingresses for the given Tenant. Capsule assures that all Ingress resources created in the Tenant can use only one of the allowed hostnames. Optional.
properties:
@@ -1860,7 +1887,34 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
resourceQuotas:
description: Specifies a list of ResourceQuota resources assigned to the Tenant. The assigned values are inherited by any namespace created in the Tenant. The Capsule operator aggregates ResourceQuota at Tenant level, so that the hard quota is never crossed for the given Tenant. This permits the Tenant owner to consume resources in the Tenant regardless of the namespace. Optional.
properties:
@@ -1971,7 +2025,34 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
required:
- owners
type: object
@@ -1999,6 +2080,6 @@ spec:
type: object
type: object
served: true
- storage: false
+ storage: true
subresources:
status: {}
diff --git a/charts/capsule/templates/configuration-default.yaml b/charts/capsule/templates/configuration-default.yaml
index 3cb897a1..1356fd58 100644
--- a/charts/capsule/templates/configuration-default.yaml
+++ b/charts/capsule/templates/configuration-default.yaml
@@ -1,18 +1,19 @@
-apiVersion: capsule.clastix.io/v1alpha1
+apiVersion: capsule.clastix.io/v1beta2
kind: CapsuleConfiguration
metadata:
name: default
labels:
{{- include "capsule.labels" . | nindent 4 }}
annotations:
- capsule.clastix.io/mutating-webhook-configuration-name: {{ include "capsule.fullname" . }}-mutating-webhook-configuration
- capsule.clastix.io/tls-secret-name: {{ include "capsule.secretTlsName" . }}
- capsule.clastix.io/validating-webhook-configuration-name: {{ include "capsule.fullname" . }}-validating-webhook-configuration
- capsule.clastix.io/enable-tls-configuration: "{{ .Values.tls.enableController }}"
{{- with .Values.customAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
+ enableTLSReconciler: {{ .Values.tls.enableController }}
+ overrides:
+ mutatingWebhookConfigurationName: {{ include "capsule.fullname" . }}-mutating-webhook-configuration
+ TLSSecretName: {{ include "capsule.secretTlsName" . }}
+ validatingWebhookConfigurationName: {{ include "capsule.fullname" . }}-validating-webhook-configuration
forceTenantPrefix: {{ .Values.manager.options.forceTenantPrefix }}
userGroups:
{{- range .Values.manager.options.capsuleUserGroups }}
diff --git a/charts/capsule/templates/validatingwebhookconfiguration.yaml b/charts/capsule/templates/validatingwebhookconfiguration.yaml
index e20ae09c..01e2b327 100644
--- a/charts/capsule/templates/validatingwebhookconfiguration.yaml
+++ b/charts/capsule/templates/validatingwebhookconfiguration.yaml
@@ -249,7 +249,7 @@ webhooks:
- apiGroups:
- capsule.clastix.io
apiVersions:
- - v1beta1
+ - v1beta2
operations:
- CREATE
- UPDATE
diff --git a/config/crd/bases/capsule.clastix.io_capsuleconfigurations.yaml b/config/crd/bases/capsule.clastix.io_capsuleconfigurations.yaml
index aae170bf..f2b41739 100644
--- a/config/crd/bases/capsule.clastix.io_capsuleconfigurations.yaml
+++ b/config/crd/bases/capsule.clastix.io_capsuleconfigurations.yaml
@@ -57,7 +57,7 @@ spec:
type: object
type: object
served: true
- storage: true
+ storage: false
- name: v1beta2
schema:
openAPIV3Schema:
@@ -126,6 +126,10 @@ spec:
- forbiddenLabels
type: object
overrides:
+ default:
+ TLSSecretName: capsule-tls
+ mutatingWebhookConfigurationName: capsule-mutating-webhook-configuration
+ validatingWebhookConfigurationName: capsule-validating-webhook-configuration
description: Allows to set different name rather than the canonical
one for the Capsule configuration objects, such as webhook secret
or configurations.
@@ -164,9 +168,7 @@ spec:
type: array
required:
- enableTLSReconciler
- - nodeMetadata
- - overrides
type: object
type: object
served: true
- storage: false
+ storage: true
diff --git a/config/crd/bases/capsule.clastix.io_tenants.yaml b/config/crd/bases/capsule.clastix.io_tenants.yaml
index 9db86c24..b92eaaa4 100644
--- a/config/crd/bases/capsule.clastix.io_tenants.yaml
+++ b/config/crd/bases/capsule.clastix.io_tenants.yaml
@@ -1917,7 +1917,7 @@ spec:
type: object
type: object
served: true
- storage: true
+ storage: false
subresources:
status: {}
- additionalPrinterColumns:
@@ -2056,7 +2056,48 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector
+ requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector
+ that contains values, a key, and an operator that relates
+ the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship
+ to a set of values. Valid operators are In, NotIn,
+ Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If
+ the operator is In or NotIn, the values array must
+ be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced
+ during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A
+ single {key,value} in the matchLabels map is equivalent
+ to an element of matchExpressions, whose key field is "key",
+ the operator is "In", and the values array contains only
+ "value". The requirements are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
allowedHostnames:
description: Specifies the allowed hostnames in Ingresses for
the given Tenant. Capsule assures that all Ingress resources
@@ -2835,7 +2876,48 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that
+ contains values, a key, and an operator that relates the key
+ and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to
+ a set of values. Valid operators are In, NotIn, Exists
+ and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the
+ operator is In or NotIn, the values array must be non-empty.
+ If the operator is Exists or DoesNotExist, the values
+ array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single
+ {key,value} in the matchLabels map is equivalent to an element
+ of matchExpressions, whose key field is "key", the operator
+ is "In", and the values array contains only "value". The requirements
+ are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
resourceQuotas:
description: Specifies a list of ResourceQuota resources assigned
to the Tenant. The assigned values are inherited by any namespace
@@ -2983,7 +3065,48 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that
+ contains values, a key, and an operator that relates the key
+ and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to
+ a set of values. Valid operators are In, NotIn, Exists
+ and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the
+ operator is In or NotIn, the values array must be non-empty.
+ If the operator is Exists or DoesNotExist, the values
+ array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single
+ {key,value} in the matchLabels map is equivalent to an element
+ of matchExpressions, whose key field is "key", the operator
+ is "In", and the values array contains only "value". The requirements
+ are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
required:
- owners
type: object
@@ -3012,6 +3135,6 @@ spec:
type: object
type: object
served: true
- storage: false
+ storage: true
subresources:
status: {}
diff --git a/config/install.yaml b/config/install.yaml
index d358bfa6..2c2a4eb4 100644
--- a/config/install.yaml
+++ b/config/install.yaml
@@ -65,7 +65,7 @@ spec:
type: object
type: object
served: true
- storage: true
+ storage: false
- name: v1beta2
schema:
openAPIV3Schema:
@@ -118,6 +118,10 @@ spec:
- forbiddenLabels
type: object
overrides:
+ default:
+ TLSSecretName: capsule-tls
+ mutatingWebhookConfigurationName: capsule-mutating-webhook-configuration
+ validatingWebhookConfigurationName: capsule-validating-webhook-configuration
description: Allows to set different name rather than the canonical one for the Capsule configuration objects, such as webhook secret or configurations.
properties:
TLSSecretName:
@@ -149,12 +153,10 @@ spec:
type: array
required:
- enableTLSReconciler
- - nodeMetadata
- - overrides
type: object
type: object
served: true
- storage: false
+ storage: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
@@ -1835,7 +1837,7 @@ spec:
type: object
type: object
served: true
- storage: true
+ storage: false
subresources:
status: {}
- additionalPrinterColumns:
@@ -1946,7 +1948,34 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
allowedHostnames:
description: Specifies the allowed hostnames in Ingresses for the given Tenant. Capsule assures that all Ingress resources created in the Tenant can use only one of the allowed hostnames. Optional.
properties:
@@ -2421,7 +2450,34 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
resourceQuotas:
description: Specifies a list of ResourceQuota resources assigned to the Tenant. The assigned values are inherited by any namespace created in the Tenant. The Capsule operator aggregates ResourceQuota at Tenant level, so that the hard quota is never crossed for the given Tenant. This permits the Tenant owner to consume resources in the Tenant regardless of the namespace. Optional.
properties:
@@ -2532,7 +2588,34 @@ spec:
type: array
allowedRegex:
type: string
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
type: object
+ x-kubernetes-map-type: atomic
required:
- owners
type: object
@@ -2560,7 +2643,7 @@ spec:
type: object
type: object
served: true
- storage: false
+ storage: true
subresources:
status: {}
---
@@ -2926,7 +3009,7 @@ webhooks:
- apiGroups:
- capsule.clastix.io
apiVersions:
- - v1beta1
+ - v1beta2
operations:
- CREATE
- UPDATE
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
index 768a76f0..4567309d 100644
--- a/config/webhook/manifests.yaml
+++ b/config/webhook/manifests.yaml
@@ -206,7 +206,7 @@ webhooks:
- apiGroups:
- capsule.clastix.io
apiVersions:
- - v1beta1
+ - v1beta2
operations:
- CREATE
- UPDATE
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/docs/content/general/crds-apis.md b/docs/content/general/crds-apis.md
index b6b091dd..594ac477 100644
--- a/docs/content/general/crds-apis.md
+++ b/docs/content/general/crds-apis.md
@@ -1665,27 +1665,29 @@ CapsuleConfigurationSpec defines the Capsule configuration.
Default: true
true |
+
+ forceTenantPrefix |
+ boolean |
+
+ Enforces the Tenant owner, during Namespace creation, to name it using the selected Tenant name as prefix, separated by a dash. This is useful to avoid Namespace name collision in a public CaaS environment.
+
+ Default: false
+ |
+ false |
nodeMetadata |
object |
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.
|
- true |
+ false |
overrides |
object |
Allows to set different name rather than the canonical one for the Capsule configuration objects, such as webhook secret or configurations.
- |
- true |
-
- forceTenantPrefix |
- boolean |
-
- Enforces the Tenant owner, during Namespace creation, to name it using the selected Tenant name as prefix, separated by a dash. This is useful to avoid Namespace name collision in a public CaaS environment.
- Default: false
+ Default: map[TLSSecretName:capsule-tls mutatingWebhookConfigurationName:capsule-mutating-webhook-configuration validatingWebhookConfigurationName:capsule-validating-webhook-configuration]
|
false |
@@ -3282,6 +3284,60 @@ Specifies the allowed IngressClasses assigned to the Tenant. Capsule assures tha
false |
+
+ matchExpressions |
+ []object |
+
+ matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ |
+ false |
+
+ matchLabels |
+ map[string]string |
+
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ |
+ false |
+
+
+
+
+### Tenant.spec.ingressOptions.allowedClasses.matchExpressions[index]
+
+
+
+A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ key is the label key that the selector applies to.
+ |
+ true |
+
+ operator |
+ string |
+
+ operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ |
+ true |
+
+ values |
+ []string |
+
+ values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ |
+ false |
@@ -4356,6 +4412,60 @@ Specifies the allowed priorityClasses assigned to the Tenant. Capsule assures th
false |
+
+ matchExpressions |
+ []object |
+
+ matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ |
+ false |
+
+ matchLabels |
+ map[string]string |
+
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ |
+ false |
+
+
+
+
+### Tenant.spec.priorityClasses.matchExpressions[index]
+
+
+
+A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ key is the label key that the selector applies to.
+ |
+ true |
+
+ operator |
+ string |
+
+ operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ |
+ true |
+
+ values |
+ []string |
+
+ values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ |
+ false |
@@ -4676,6 +4786,60 @@ Specifies the allowed StorageClasses assigned to the Tenant. Capsule assures tha
false |
+
+ matchExpressions |
+ []object |
+
+ matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ |
+ false |
+
+ matchLabels |
+ map[string]string |
+
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ |
+ false |
+
+
+
+
+### Tenant.spec.storageClasses.matchExpressions[index]
+
+
+
+A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ key is the label key that the selector applies to.
+ |
+ true |
+
+ operator |
+ string |
+
+ operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ |
+ true |
+
+ values |
+ []string |
+
+ values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ |
+ false |
diff --git a/e2e/additional_role_bindings_test.go b/e2e/additional_role_bindings_test.go
index ffda52fb..e207a189 100644
--- a/e2e/additional_role_bindings_test.go
+++ b/e2e/additional_role_bindings_test.go
@@ -14,17 +14,17 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating a Namespace with an additional Role Binding", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "additional-role-binding",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "dale",
Kind: "User",
diff --git a/e2e/allowed_external_ips_test.go b/e2e/allowed_external_ips_test.go
index 0842e080..62fdfa1d 100644
--- a/e2e/allowed_external_ips_test.go
+++ b/e2e/allowed_external_ips_test.go
@@ -14,17 +14,17 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("enforcing an allowed set of Service external IPs", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "allowed-external-ip",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "google",
Kind: "User",
diff --git a/e2e/container_registry_test.go b/e2e/container_registry_test.go
index 92d8ec67..77ff4483 100644
--- a/e2e/container_registry_test.go
+++ b/e2e/container_registry_test.go
@@ -14,17 +14,17 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("enforcing a Container Registry", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "container-registry",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "matt",
Kind: "User",
diff --git a/e2e/custom_capsule_group_test.go b/e2e/custom_capsule_group_test.go
index 531c97d6..d703fefb 100644
--- a/e2e/custom_capsule_group_test.go
+++ b/e2e/custom_capsule_group_test.go
@@ -12,18 +12,16 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
-
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace as Tenant owner with custom --capsule-group", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-assigned-custom-group",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "alice",
Kind: "User",
@@ -43,7 +41,7 @@ var _ = Describe("creating a Namespace as Tenant owner with custom --capsule-gro
})
It("should fail using a User non matching the capsule-user-group flag", func() {
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
configuration.Spec.UserGroups = []string{"test"}
})
@@ -52,7 +50,7 @@ var _ = Describe("creating a Namespace as Tenant owner with custom --capsule-gro
})
It("should succeed and be available in Tenant namespaces list with multiple groups", func() {
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
configuration.Spec.UserGroups = []string{"test", "alice"}
})
@@ -63,7 +61,7 @@ var _ = Describe("creating a Namespace as Tenant owner with custom --capsule-gro
})
It("should succeed and be available in Tenant namespaces list with default single group", func() {
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
configuration.Spec.UserGroups = []string{"capsule.clastix.io"}
})
diff --git a/e2e/custom_resource_quota_test.go b/e2e/custom_resource_quota_test.go
index 30c0b14c..5354f801 100644
--- a/e2e/custom_resource_quota_test.go
+++ b/e2e/custom_resource_quota_test.go
@@ -20,19 +20,19 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes/scheme"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("when Tenant limits custom Resource Quota", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "limiting-resources",
Annotations: map[string]string{
"quota.resources.capsule.clastix.io/foos.test.clastix.io_v1": "3",
},
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "resource",
Kind: "User",
diff --git a/e2e/disable_externalname_test.go b/e2e/disable_externalname_test.go
index 9d3a1e87..a8b4e6fe 100644
--- a/e2e/disable_externalname_test.go
+++ b/e2e/disable_externalname_test.go
@@ -15,17 +15,17 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating an ExternalName service when it is disabled for Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "disable-external-service",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "google",
Kind: "User",
diff --git a/e2e/disable_ingress_wildcard_test.go b/e2e/disable_ingress_wildcard_test.go
index 901a39d7..4c327f17 100644
--- a/e2e/disable_ingress_wildcard_test.go
+++ b/e2e/disable_ingress_wildcard_test.go
@@ -19,19 +19,19 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating an Ingress with a wildcard when it is denied for the Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "denied-ingress-wildcard",
Annotations: map[string]string{
"capsule.clastix.io/deny-wildcard": "true",
},
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "scott",
Kind: "User",
diff --git a/e2e/disable_loadbalancer_test.go b/e2e/disable_loadbalancer_test.go
index d94983b7..29cfdc35 100644
--- a/e2e/disable_loadbalancer_test.go
+++ b/e2e/disable_loadbalancer_test.go
@@ -15,17 +15,17 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating a LoadBalancer service when it is disabled for Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "disable-loadbalancer-service",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "amazon",
Kind: "User",
diff --git a/e2e/disable_node_ports_test.go b/e2e/disable_node_ports_test.go
index 8e5cb2d9..10f670d6 100644
--- a/e2e/disable_node_ports_test.go
+++ b/e2e/disable_node_ports_test.go
@@ -15,17 +15,17 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating a nodePort service when it is disabled for Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "disable-node-ports",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "google",
Kind: "User",
diff --git a/e2e/dynamic_tenant_owner_clusterroles_test.go b/e2e/dynamic_tenant_owner_clusterroles_test.go
index b7338875..c491b4b0 100644
--- a/e2e/dynamic_tenant_owner_clusterroles_test.go
+++ b/e2e/dynamic_tenant_owner_clusterroles_test.go
@@ -13,27 +13,25 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("defining dynamic Tenant Owner Cluster Roles", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "dynamic-tenant-owner-clusterroles",
- Annotations: map[string]string{
- "clusterrolenames.capsule.clastix.io/user.michonne": "editor,manager",
- "clusterrolenames.capsule.clastix.io/group.kingdom": "readonly",
- },
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
- Name: "michonne",
- Kind: "User",
+ Kind: "User",
+ Name: "michonne",
+ ClusterRoles: []string{"editor", "manager"},
},
{
- Name: "kingdom",
- Kind: "Group",
+ Name: "kingdom",
+ Kind: "Group",
+ ClusterRoles: []string{"readonly"},
},
},
},
diff --git a/e2e/enable_loadbalancer_test.go b/e2e/enable_loadbalancer_test.go
index e6201cc0..8990e162 100644
--- a/e2e/enable_loadbalancer_test.go
+++ b/e2e/enable_loadbalancer_test.go
@@ -15,17 +15,17 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating a LoadBalancer service when it is enabled for Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "enable-loadbalancer-service",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "netflix",
Kind: "User",
diff --git a/e2e/enable_node_ports_test.go b/e2e/enable_node_ports_test.go
index b8803f42..1c079439 100644
--- a/e2e/enable_node_ports_test.go
+++ b/e2e/enable_node_ports_test.go
@@ -14,16 +14,16 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a nodePort service when it is enabled for Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "enable-node-ports",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "google",
Kind: "User",
diff --git a/e2e/forbidden_annotations_regex_test.go b/e2e/forbidden_annotations_regex_test.go
index 74e93041..db45297a 100644
--- a/e2e/forbidden_annotations_regex_test.go
+++ b/e2e/forbidden_annotations_regex_test.go
@@ -12,72 +12,94 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
+ "github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating a tenant with various forbidden regexes", func() {
- tnt := &capsulev1beta1.Tenant{
- ObjectMeta: metav1.ObjectMeta{
- Annotations: nil,
- Name: "namespace",
- },
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
- {
- Name: "alice",
- Kind: "User",
- },
- },
- },
- }
-
- It("should succeed when there are no annotations", func() {
- EventuallyCreation(func() error {
- tnt.ObjectMeta.Annotations = nil
- tnt.ResourceVersion = ""
- return k8sClient.Create(context.TODO(), tnt)
- }).Should(Succeed())
- Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
- })
-
- annotationsToCheck := []string{
- capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation,
- capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation,
- }
-
- errorRegexes := []string{
- "(.*gitops|.*nsm).[k8s.io/((?!(resource)).*|trusted)](http://k8s.io/((?!(resource)).*%7Ctrusted))",
- }
-
- for _, annotation := range annotationsToCheck {
- for _, annotationValue := range errorRegexes {
- It("should fail using a non-valid the regex on the annotation "+annotation, func() {
- EventuallyCreation(func() error {
- tnt.ResourceVersion = ""
- tnt.ObjectMeta.Annotations = make(map[string]string)
- tnt.ObjectMeta.Annotations[annotation] = annotationValue
- return k8sClient.Create(context.TODO(), tnt)
- }).ShouldNot(Succeed())
- })
- }
- }
+ //errorRegexes := []string{
+ // "(.*gitops|.*nsm).[k8s.io/((?!(resource)).*|trusted)](http://k8s.io/((?!(resource)).*%7Ctrusted))",
+ //}
+ //
+ //for _, annotationValue := range errorRegexes {
+ // It("should fail using a non-valid the regex on the annotation", func() {
+ // tnt := &capsulev1beta2.Tenant{
+ // ObjectMeta: metav1.ObjectMeta{
+ // Name: "namespace",
+ // },
+ // Spec: capsulev1beta2.TenantSpec{
+ // Owners: capsulev1beta2.OwnerListSpec{
+ // {
+ // Name: "alice",
+ // Kind: "User",
+ // },
+ // },
+ // },
+ // }
+ //
+ // EventuallyCreation(func() error {
+ // tnt.Spec.NamespaceOptions = &capsulev1beta2.NamespaceOptions{
+ // ForbiddenLabels: api.ForbiddenListSpec{
+ // Regex: annotationValue,
+ // },
+ // }
+ // return k8sClient.Create(context.TODO(), tnt)
+ // }).ShouldNot(Succeed())
+ //
+ // EventuallyCreation(func() error {
+ // tnt.Spec.NamespaceOptions = &capsulev1beta2.NamespaceOptions{
+ // ForbiddenAnnotations: api.ForbiddenListSpec{
+ // Regex: annotationValue,
+ // },
+ // }
+ // return k8sClient.Create(context.TODO(), tnt)
+ // }).ShouldNot(Succeed())
+ // })
+ //}
successRegexes := []string{
"",
"(.*gitops|.*nsm)",
}
- for _, annotation := range annotationsToCheck {
- for _, annotationValue := range successRegexes {
- It("should succeed using a valid regex on the annotation "+annotation, func() {
- EventuallyCreation(func() error {
- tnt.ResourceVersion = ""
- tnt.ObjectMeta.Annotations = make(map[string]string)
- tnt.ObjectMeta.Annotations[annotation] = annotationValue
- return k8sClient.Create(context.TODO(), tnt)
- }).Should(Succeed())
- Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
- })
- }
- }
+ for _, annotationValue := range successRegexes {
+ It("should succeed using a valid regex on the annotation", func() {
+ tnt := &capsulev1beta2.Tenant{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "namespace",
+ },
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
+ {
+ Name: "alice",
+ Kind: "User",
+ },
+ },
+ },
+ }
+ EventuallyCreation(func() error {
+ tnt.SetResourceVersion("")
+
+ tnt.Spec.NamespaceOptions = &capsulev1beta2.NamespaceOptions{
+ ForbiddenLabels: api.ForbiddenListSpec{
+ Regex: annotationValue,
+ },
+ }
+ return k8sClient.Create(context.TODO(), tnt)
+ }).Should(Succeed())
+ Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
+
+ EventuallyCreation(func() error {
+ tnt.SetResourceVersion("")
+
+ tnt.Spec.NamespaceOptions = &capsulev1beta2.NamespaceOptions{
+ ForbiddenAnnotations: api.ForbiddenListSpec{
+ Regex: annotationValue,
+ },
+ }
+ return k8sClient.Create(context.TODO(), tnt)
+ }).Should(Succeed())
+ Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
+ })
+ }
})
diff --git a/e2e/force_tenant_prefix_test.go b/e2e/force_tenant_prefix_test.go
index 6ac706e9..488c8682 100644
--- a/e2e/force_tenant_prefix_test.go
+++ b/e2e/force_tenant_prefix_test.go
@@ -12,18 +12,16 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
-
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace with Tenant name prefix enforcement", func() {
- t1 := &capsulev1beta1.Tenant{
+ t1 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
@@ -31,12 +29,12 @@ var _ = Describe("creating a Namespace with Tenant name prefix enforcement", fun
},
},
}
- t2 := &capsulev1beta1.Tenant{
+ t2 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-tenant",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
@@ -55,7 +53,7 @@ var _ = Describe("creating a Namespace with Tenant name prefix enforcement", fun
return k8sClient.Create(context.TODO(), t2)
}).Should(Succeed())
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
configuration.Spec.ForceTenantPrefix = true
})
})
@@ -63,7 +61,7 @@ var _ = Describe("creating a Namespace with Tenant name prefix enforcement", fun
Expect(k8sClient.Delete(context.TODO(), t1)).Should(Succeed())
Expect(k8sClient.Delete(context.TODO(), t2)).Should(Succeed())
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
configuration.Spec.ForceTenantPrefix = false
})
})
diff --git a/e2e/globaltenantresource_test.go b/e2e/globaltenantresource_test.go
index 0f2c9144..b0ebf1fe 100644
--- a/e2e/globaltenantresource_test.go
+++ b/e2e/globaltenantresource_test.go
@@ -21,21 +21,20 @@ import (
"k8s.io/utils/pointer"
"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/api"
)
var _ = Describe("Creating a GlobalTenantResource object", func() {
- solar := &capsulev1beta1.Tenant{
+ solar := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "energy-solar",
Labels: map[string]string{
"replicate": "true",
},
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "solar-user",
Kind: "User",
@@ -44,15 +43,15 @@ var _ = Describe("Creating a GlobalTenantResource object", func() {
},
}
- wind := &capsulev1beta1.Tenant{
+ wind := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "energy-wind",
Labels: map[string]string{
"replicate": "true",
},
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "wind-user",
Kind: "User",
diff --git a/e2e/imagepullpolicy_multiple_test.go b/e2e/imagepullpolicy_multiple_test.go
index d725c4f6..78beaac9 100644
--- a/e2e/imagepullpolicy_multiple_test.go
+++ b/e2e/imagepullpolicy_multiple_test.go
@@ -13,17 +13,17 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("enforcing some defined ImagePullPolicy", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "image-pull-policies",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "alex",
Kind: "User",
diff --git a/e2e/imagepullpolicy_single_test.go b/e2e/imagepullpolicy_single_test.go
index 9b99e349..1d3f873b 100644
--- a/e2e/imagepullpolicy_single_test.go
+++ b/e2e/imagepullpolicy_single_test.go
@@ -13,17 +13,17 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("enforcing a defined ImagePullPolicy", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "image-pull-policy",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "axel",
Kind: "User",
diff --git a/e2e/ingress_class_extensions_test.go b/e2e/ingress_class_extensions_test.go
index deb949c2..e17b205e 100644
--- a/e2e/ingress_class_extensions_test.go
+++ b/e2e/ingress_class_extensions_test.go
@@ -18,29 +18,31 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when Tenant handles Ingress classes with extensions/v1beta1", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-class-extensions-v1beta1",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "ingress",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
- AllowedClasses: &api.AllowedListSpec{
- Exact: []string{
- "nginx",
- "haproxy",
+ IngressOptions: capsulev1beta2.IngressOptions{
+ AllowedClasses: &api.SelectorAllowedListSpec{
+ AllowedListSpec: api.AllowedListSpec{
+ Exact: []string{
+ "nginx",
+ "haproxy",
+ },
+ Regex: "^oil-.*$",
},
- Regex: "^oil-.*$",
},
},
},
diff --git a/e2e/ingress_class_networking_test.go b/e2e/ingress_class_networking_test.go
index 14a70227..0ecdd67b 100644
--- a/e2e/ingress_class_networking_test.go
+++ b/e2e/ingress_class_networking_test.go
@@ -17,29 +17,31 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when Tenant handles Ingress classes with networking.k8s.io/v1", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-class-networking-v1",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: []capsulev1beta1.OwnerSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: []capsulev1beta2.OwnerSpec{
{
Name: "ingress",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
- AllowedClasses: &api.AllowedListSpec{
- Exact: []string{
- "nginx",
- "haproxy",
+ IngressOptions: capsulev1beta2.IngressOptions{
+ AllowedClasses: &api.SelectorAllowedListSpec{
+ AllowedListSpec: api.AllowedListSpec{
+ Exact: []string{
+ "nginx",
+ "haproxy",
+ },
+ Regex: "^oil-.*$",
},
- Regex: "^oil-.*$",
},
},
},
diff --git a/e2e/ingress_hostnames_collision_cluster_scope_test.go b/e2e/ingress_hostnames_collision_cluster_scope_test.go
index de503367..fa23e49f 100644
--- a/e2e/ingress_hostnames_collision_cluster_scope_test.go
+++ b/e2e/ingress_hostnames_collision_cluster_scope_test.go
@@ -18,39 +18,39 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when handling Cluster scoped Ingress hostnames collision", func() {
- tnt1 := &capsulev1beta1.Tenant{
+ tnt1 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "hostnames-collision-cluster-one",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "ingress-tenant-one",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
+ IngressOptions: capsulev1beta2.IngressOptions{
HostnameCollisionScope: api.HostnameCollisionScopeCluster,
},
},
}
- tnt2 := &capsulev1beta1.Tenant{
+ tnt2 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "hostnames-collision-cluster-two",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "ingress-tenant-two",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
+ IngressOptions: capsulev1beta2.IngressOptions{
HostnameCollisionScope: api.HostnameCollisionScopeCluster,
},
},
diff --git a/e2e/ingress_hostnames_collision_disabled_test.go b/e2e/ingress_hostnames_collision_disabled_test.go
index 081dfc9c..e8139ec7 100644
--- a/e2e/ingress_hostnames_collision_disabled_test.go
+++ b/e2e/ingress_hostnames_collision_disabled_test.go
@@ -18,23 +18,23 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when disabling Ingress hostnames collision", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "hostnames-collision-disabled",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "ingress-disabled",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
+ IngressOptions: capsulev1beta2.IngressOptions{
HostnameCollisionScope: api.HostnameCollisionScopeDisabled,
},
},
diff --git a/e2e/ingress_hostnames_collision_namespace_scope_test.go b/e2e/ingress_hostnames_collision_namespace_scope_test.go
index bfc43b95..66b5eabf 100644
--- a/e2e/ingress_hostnames_collision_namespace_scope_test.go
+++ b/e2e/ingress_hostnames_collision_namespace_scope_test.go
@@ -18,23 +18,23 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when handling Namespace scoped Ingress hostnames collision", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "hostnames-collision-namespace",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "ingress-namespace",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
+ IngressOptions: capsulev1beta2.IngressOptions{
HostnameCollisionScope: api.HostnameCollisionScopeNamespace,
},
},
diff --git a/e2e/ingress_hostnames_collision_tenant_scope_test.go b/e2e/ingress_hostnames_collision_tenant_scope_test.go
index 6e3b67b9..7081ae02 100644
--- a/e2e/ingress_hostnames_collision_tenant_scope_test.go
+++ b/e2e/ingress_hostnames_collision_tenant_scope_test.go
@@ -18,23 +18,23 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when handling Tenant scoped Ingress hostnames collision", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "hostnames-collision-tenant",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "ingress-tenant",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
+ IngressOptions: capsulev1beta2.IngressOptions{
HostnameCollisionScope: api.HostnameCollisionScopeTenant,
},
},
diff --git a/e2e/ingress_hostnames_test.go b/e2e/ingress_hostnames_test.go
index 0c12fd80..cabf671e 100644
--- a/e2e/ingress_hostnames_test.go
+++ b/e2e/ingress_hostnames_test.go
@@ -18,23 +18,23 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when Tenant handles Ingress hostnames", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-hostnames",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "hostname",
Kind: "User",
},
},
- IngressOptions: capsulev1beta1.IngressOptions{
+ IngressOptions: capsulev1beta2.IngressOptions{
AllowedHostnames: &api.AllowedListSpec{
Exact: []string{"sigs.k8s.io", "operator.sdk", "domain.tld"},
Regex: `.*\.clastix\.io`,
diff --git a/e2e/missing_tenant_test.go b/e2e/missing_tenant_test.go
index 1ff51b66..5202bb9b 100644
--- a/e2e/missing_tenant_test.go
+++ b/e2e/missing_tenant_test.go
@@ -12,14 +12,14 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace creation with no Tenant assigned", func() {
It("should fail", func() {
- tnt := &capsulev1beta1.Tenant{
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ tnt := &capsulev1beta2.Tenant{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "missing",
Kind: "User",
diff --git a/e2e/namespace_additional_metadata_test.go b/e2e/namespace_additional_metadata_test.go
index 68452022..87e00c19 100644
--- a/e2e/namespace_additional_metadata_test.go
+++ b/e2e/namespace_additional_metadata_test.go
@@ -13,23 +13,23 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating a Namespace for a Tenant with additional metadata", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-metadata",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "gatsby",
Kind: "User",
},
},
- NamespaceOptions: &capsulev1beta1.NamespaceOptions{
+ NamespaceOptions: &capsulev1beta2.NamespaceOptions{
AdditionalMetadata: &api.AdditionalMetadataSpec{
Labels: map[string]string{
"k8s.io/custom-label": "foo",
diff --git a/e2e/namespace_capsule_label_test.go b/e2e/namespace_capsule_label_test.go
index bb223550..21ac4582 100644
--- a/e2e/namespace_capsule_label_test.go
+++ b/e2e/namespace_capsule_label_test.go
@@ -14,16 +14,16 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating several Namespaces for a Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "capsule-labels",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "charlie",
Kind: "User",
diff --git a/e2e/namespace_user_metadata_test.go b/e2e/namespace_user_metadata_test.go
index 298b5a18..b59a77c2 100644
--- a/e2e/namespace_user_metadata_test.go
+++ b/e2e/namespace_user_metadata_test.go
@@ -15,22 +15,27 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
+ "github.com/clastix/capsule/pkg/api"
)
var _ = Describe("creating a Namespace with user-specified labels and annotations", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-user-metadata-forbidden",
- Annotations: map[string]string{
- capsulev1beta1.ForbiddenNamespaceLabelsAnnotation: "foo,bar",
- capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation: "^gatsby-.*$",
- capsulev1beta1.ForbiddenNamespaceAnnotationsAnnotation: "foo,bar",
- capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation: "^gatsby-.*$",
- },
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ NamespaceOptions: &capsulev1beta2.NamespaceOptions{
+ ForbiddenLabels: api.ForbiddenListSpec{
+ Exact: []string{"foo", "bar"},
+ Regex: "^gatsby-.*$",
+ },
+ ForbiddenAnnotations: api.ForbiddenListSpec{
+ Exact: []string{"foo", "bar"},
+ Regex: "^gatsby-.*$",
+ },
+ },
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "gatsby",
Kind: "User",
diff --git a/e2e/new_namespace_test.go b/e2e/new_namespace_test.go
index a14e6c04..6d6cfc20 100644
--- a/e2e/new_namespace_test.go
+++ b/e2e/new_namespace_test.go
@@ -12,16 +12,16 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespaces as different type of Tenant owners", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-assigned",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "alice",
Kind: "User",
diff --git a/e2e/node_user_metadata_test.go b/e2e/node_user_metadata_test.go
index f898147a..1ded6b50 100644
--- a/e2e/node_user_metadata_test.go
+++ b/e2e/node_user_metadata_test.go
@@ -7,25 +7,26 @@ package e2e
import (
"context"
-
"fmt"
- capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
- "github.com/clastix/capsule/pkg/webhook/utils"
+
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
+ "github.com/clastix/capsule/pkg/api"
+ "github.com/clastix/capsule/pkg/webhook/utils"
)
var _ = Describe("modifying node labels and annotations", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-node-user-metadata-forbidden",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "gatsby",
Kind: "User",
@@ -90,17 +91,41 @@ var _ = Describe("modifying node labels and annotations", func() {
Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
Expect(k8sClient.Delete(context.TODO(), crb)).Should(Succeed())
Expect(k8sClient.Delete(context.TODO(), cr)).Should(Succeed())
+ EventuallyCreation(func() error {
+ return ModifyNode(func(node *corev1.Node) error {
+ annotations := node.GetAnnotations()
+
+ delete(annotations, "bim")
+ delete(annotations, "foo")
+ delete(annotations, "gatsby-foo")
+
+ node.SetAnnotations(annotations)
+
+ labels := node.GetLabels()
+
+ delete(labels, "bim")
+ delete(labels, "foo")
+ delete(labels, "gatsby-foo")
+
+ node.SetLabels(labels)
+
+ return k8sClient.Update(context.Background(), node)
+ })
+ }).Should(Succeed())
})
It("should allow", func() {
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
- protected := map[string]string{
- capsulev1alpha1.ForbiddenNodeLabelsAnnotation: "foo,bar",
- capsulev1alpha1.ForbiddenNodeLabelsRegexpAnnotation: "^gatsby-.*$",
- capsulev1alpha1.ForbiddenNodeAnnotationsAnnotation: "foo,bar",
- capsulev1alpha1.ForbiddenNodeAnnotationsRegexpAnnotation: "^gatsby-.*$",
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
+ configuration.Spec.NodeMetadata = &capsulev1beta2.NodeMetadata{
+ ForbiddenLabels: api.ForbiddenListSpec{
+ Exact: []string{"foo", "bar"},
+ Regex: "^gatsby-.*$",
+ },
+ ForbiddenAnnotations: api.ForbiddenListSpec{
+ Exact: []string{"foo", "bar"},
+ Regex: "^gatsby-.*$",
+ },
}
- configuration.SetAnnotations(protected)
})
By("adding non-forbidden labels", func() {
EventuallyCreation(func() error {
diff --git a/e2e/overquota_namespace_test.go b/e2e/overquota_namespace_test.go
index 986c55c5..ab064b61 100644
--- a/e2e/overquota_namespace_test.go
+++ b/e2e/overquota_namespace_test.go
@@ -13,22 +13,22 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace in over-quota of three", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "over-quota-tenant",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "bob",
Kind: "User",
},
},
- NamespaceOptions: &capsulev1beta1.NamespaceOptions{
+ NamespaceOptions: &capsulev1beta2.NamespaceOptions{
Quota: pointer.Int32Ptr(3),
},
},
diff --git a/e2e/owner_webhooks_test.go b/e2e/owner_webhooks_test.go
index 63a8fecc..b20772b6 100644
--- a/e2e/owner_webhooks_test.go
+++ b/e2e/owner_webhooks_test.go
@@ -17,26 +17,28 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when Tenant owner interacts with the webhooks", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-owner",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "ruby",
Kind: "User",
},
},
- StorageClasses: &api.AllowedListSpec{
- Exact: []string{
- "cephfs",
- "glusterfs",
+ StorageClasses: &api.SelectorAllowedListSpec{
+ AllowedListSpec: api.AllowedListSpec{
+ Exact: []string{
+ "cephfs",
+ "glusterfs",
+ },
},
},
LimitRanges: api.LimitRangesSpec{Items: []corev1.LimitRangeSpec{
diff --git a/e2e/pod_priority_class_test.go b/e2e/pod_priority_class_test.go
index 852ec00b..fd774d72 100644
--- a/e2e/pod_priority_class_test.go
+++ b/e2e/pod_priority_class_test.go
@@ -14,25 +14,27 @@ import (
v1 "k8s.io/api/scheduling/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("enforcing a Priority Class", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "priority-class",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "george",
Kind: "User",
},
},
- PriorityClasses: &api.AllowedListSpec{
- Exact: []string{"gold"},
- Regex: "pc\\-\\w+",
+ PriorityClasses: &api.SelectorAllowedListSpec{
+ AllowedListSpec: api.AllowedListSpec{
+ Exact: []string{"gold"},
+ Regex: "pc\\-\\w+",
+ },
},
},
}
diff --git a/e2e/protected_namespace_regex_test.go b/e2e/protected_namespace_regex_test.go
index 7dadb2a4..1b878cf1 100644
--- a/e2e/protected_namespace_regex_test.go
+++ b/e2e/protected_namespace_regex_test.go
@@ -12,18 +12,16 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
-
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace with a protected Namespace regex enabled", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-protected-namespace",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "alice",
Kind: "User",
@@ -43,7 +41,7 @@ var _ = Describe("creating a Namespace with a protected Namespace regex enabled"
})
It("should succeed and be available in Tenant namespaces list", func() {
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
configuration.Spec.ProtectedNamespaceRegexpString = `^.*[-.]system$`
})
@@ -57,7 +55,7 @@ var _ = Describe("creating a Namespace with a protected Namespace regex enabled"
ns := NewNamespace("test-system")
NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).ShouldNot(Succeed())
- ModifyCapsuleConfigurationOpts(func(configuration *capsulev1alpha1.CapsuleConfiguration) {
+ ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
configuration.Spec.ProtectedNamespaceRegexpString = ""
})
})
diff --git a/e2e/resource_quota_exceeded_test.go b/e2e/resource_quota_exceeded_test.go
index d8edddbd..18e359f8 100644
--- a/e2e/resource_quota_exceeded_test.go
+++ b/e2e/resource_quota_exceeded_test.go
@@ -19,16 +19,16 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("exceeding a Tenant resource quota", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-resources-changes",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "bobby",
Kind: "User",
diff --git a/e2e/sa_prevent_privilege_escalation_test.go b/e2e/sa_prevent_privilege_escalation_test.go
index 59649e58..f2bde523 100644
--- a/e2e/sa_prevent_privilege_escalation_test.go
+++ b/e2e/sa_prevent_privilege_escalation_test.go
@@ -19,16 +19,16 @@ import (
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client/config"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("trying to escalate from a Tenant Namespace ServiceAccount", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "sa-privilege-escalation",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "mario",
Kind: "User",
diff --git a/e2e/selecting_non_owned_tenant_test.go b/e2e/selecting_non_owned_tenant_test.go
index 82ec38f3..3709db27 100644
--- a/e2e/selecting_non_owned_tenant_test.go
+++ b/e2e/selecting_non_owned_tenant_test.go
@@ -14,16 +14,16 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace trying to select a third Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-non-owned",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "undefined",
Kind: "User",
@@ -45,7 +45,7 @@ var _ = Describe("creating a Namespace trying to select a third Tenant", func()
var ns *corev1.Namespace
By("assigning to the Namespace the Capsule Tenant label", func() {
- l, err := utils.GetTypeLabel(&capsulev1beta1.Tenant{})
+ l, err := utils.GetTypeLabel(&capsulev1beta2.Tenant{})
Expect(err).ToNot(HaveOccurred())
ns := NewNamespace("")
@@ -54,7 +54,7 @@ var _ = Describe("creating a Namespace trying to select a third Tenant", func()
})
})
- cs := ownerClient(capsulev1beta1.OwnerSpec{Name: "dale", Kind: "User"})
+ cs := ownerClient(capsulev1beta2.OwnerSpec{Name: "dale", Kind: "User"})
_, err := cs.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{})
Expect(err).To(HaveOccurred())
})
diff --git a/e2e/selecting_tenant_fail_test.go b/e2e/selecting_tenant_fail_test.go
index 960a98ec..6d4242b7 100644
--- a/e2e/selecting_tenant_fail_test.go
+++ b/e2e/selecting_tenant_fail_test.go
@@ -12,16 +12,16 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace without a Tenant selector when user owns multiple Tenants", func() {
- t1 := &capsulev1beta1.Tenant{
+ t1 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-one",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
@@ -29,12 +29,12 @@ var _ = Describe("creating a Namespace without a Tenant selector when user owns
},
},
}
- t2 := &capsulev1beta1.Tenant{
+ t2 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-two",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
@@ -42,12 +42,12 @@ var _ = Describe("creating a Namespace without a Tenant selector when user owns
},
},
}
- t3 := &capsulev1beta1.Tenant{
+ t3 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-three",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "Group",
@@ -55,12 +55,12 @@ var _ = Describe("creating a Namespace without a Tenant selector when user owns
},
},
}
- t4 := &capsulev1beta1.Tenant{
+ t4 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-four",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "Group",
diff --git a/e2e/selecting_tenant_with_label_test.go b/e2e/selecting_tenant_with_label_test.go
index 9f1270c7..9398852b 100644
--- a/e2e/selecting_tenant_with_label_test.go
+++ b/e2e/selecting_tenant_with_label_test.go
@@ -13,16 +13,16 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Namespace with Tenant selector when user owns multiple tenants", func() {
- t1 := &capsulev1beta1.Tenant{
+ t1 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-one",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
@@ -30,12 +30,12 @@ var _ = Describe("creating a Namespace with Tenant selector when user owns multi
},
},
}
- t2 := &capsulev1beta1.Tenant{
+ t2 := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-two",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
@@ -60,7 +60,7 @@ var _ = Describe("creating a Namespace with Tenant selector when user owns multi
It("should be assigned to the selected Tenant", func() {
ns := NewNamespace("")
By("assigning to the Namespace the Capsule Tenant label", func() {
- l, err := utils.GetTypeLabel(&capsulev1beta1.Tenant{})
+ l, err := utils.GetTypeLabel(&capsulev1beta2.Tenant{})
Expect(err).ToNot(HaveOccurred())
ns.Labels = map[string]string{
l: t2.Name,
diff --git a/e2e/service_metadata_test.go b/e2e/service_metadata_test.go
index 3f86772b..f9611dae 100644
--- a/e2e/service_metadata_test.go
+++ b/e2e/service_metadata_test.go
@@ -23,17 +23,17 @@ import (
"k8s.io/utils/pointer"
"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/api"
)
var _ = Describe("adding metadata to Service objects", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "service-metadata",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "gatsby",
Kind: "User",
diff --git a/e2e/storage_class_test.go b/e2e/storage_class_test.go
index e5a1c273..2469a871 100644
--- a/e2e/storage_class_test.go
+++ b/e2e/storage_class_test.go
@@ -15,28 +15,30 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
"github.com/clastix/capsule/pkg/api"
)
var _ = Describe("when Tenant handles Storage classes", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "storage-class",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "storage",
Kind: "User",
},
},
- StorageClasses: &api.AllowedListSpec{
- Exact: []string{
- "cephfs",
- "glusterfs",
+ StorageClasses: &api.SelectorAllowedListSpec{
+ AllowedListSpec: api.AllowedListSpec{
+ Exact: []string{
+ "cephfs",
+ "glusterfs",
+ },
+ Regex: "^oil-.*$",
},
- Regex: "^oil-.*$",
},
},
}
diff --git a/e2e/suite_test.go b/e2e/suite_test.go
index 4748f5b3..0f890d18 100644
--- a/e2e/suite_test.go
+++ b/e2e/suite_test.go
@@ -20,8 +20,6 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
- capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
@@ -58,8 +56,6 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
- Expect(capsulev1alpha1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred())
- Expect(capsulev1beta1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred())
Expect(capsulev1beta2.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred())
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
@@ -74,10 +70,10 @@ var _ = AfterSuite(func() {
Expect(testEnv.Stop()).ToNot(HaveOccurred())
})
-func ownerClient(owner capsulev1beta1.OwnerSpec) (cs kubernetes.Interface) {
+func ownerClient(owner capsulev1beta2.OwnerSpec) (cs kubernetes.Interface) {
c, err := config.GetConfig()
Expect(err).ToNot(HaveOccurred())
- c.Impersonate.Groups = []string{capsulev1beta1.GroupVersion.Group, owner.Name}
+ c.Impersonate.Groups = []string{capsulev1beta2.GroupVersion.Group, owner.Name}
c.Impersonate.UserName = owner.Name
cs, err = kubernetes.NewForConfig(c)
Expect(err).ToNot(HaveOccurred())
diff --git a/e2e/tenant_cordoning_test.go b/e2e/tenant_cordoning_test.go
index 4ece4159..069275fb 100644
--- a/e2e/tenant_cordoning_test.go
+++ b/e2e/tenant_cordoning_test.go
@@ -15,16 +15,16 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("cordoning a Tenant", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-cordoning",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "jim",
Kind: "User",
@@ -75,9 +75,7 @@ var _ = Describe("cordoning a Tenant", func() {
By("cordoning the Tenant deletion must be blocked", func() {
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: tnt.Name}, tnt)).Should(Succeed())
- tnt.Labels = map[string]string{
- "capsule.clastix.io/cordon": "enabled",
- }
+ tnt.Spec.Cordoned = true
Expect(k8sClient.Update(context.TODO(), tnt)).Should(Succeed())
@@ -89,7 +87,7 @@ var _ = Describe("cordoning a Tenant", func() {
By("uncordoning the Tenant deletion must be allowed", func() {
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: tnt.Name}, tnt)).Should(Succeed())
- tnt.Labels = map[string]string{}
+ tnt.Spec.Cordoned = false
Expect(k8sClient.Update(context.TODO(), tnt)).Should(Succeed())
diff --git a/e2e/tenant_name_webhook_test.go b/e2e/tenant_name_webhook_test.go
index d6d2ae80..d555bf29 100644
--- a/e2e/tenant_name_webhook_test.go
+++ b/e2e/tenant_name_webhook_test.go
@@ -12,16 +12,16 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating a Tenant with wrong name", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "non_rfc_dns_1123",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
diff --git a/e2e/tenant_protected_webhook_test.go b/e2e/tenant_protected_webhook_test.go
index 108f35e5..fcf78842 100644
--- a/e2e/tenant_protected_webhook_test.go
+++ b/e2e/tenant_protected_webhook_test.go
@@ -13,19 +13,17 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("Deleting a tenant with protected annotation", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "protected-tenant",
- Annotations: map[string]string{
- capsulev1beta1.ProtectedTenantAnnotation: "",
- },
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ PreventDeletion: true,
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
@@ -36,7 +34,7 @@ var _ = Describe("Deleting a tenant with protected annotation", func() {
JustAfterEach(func() {
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: tnt.GetName()}, tnt)).Should(Succeed())
- tnt.SetAnnotations(map[string]string{})
+ tnt.Spec.PreventDeletion = false
Expect(k8sClient.Update(context.TODO(), tnt)).Should(Succeed())
Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
})
diff --git a/e2e/tenant_resources_changes_test.go b/e2e/tenant_resources_changes_test.go
index 5cd2d0dd..4eb08757 100644
--- a/e2e/tenant_resources_changes_test.go
+++ b/e2e/tenant_resources_changes_test.go
@@ -19,16 +19,16 @@ import (
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("changing Tenant managed Kubernetes resources", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-resources-changes",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "laura",
Kind: "User",
diff --git a/e2e/tenant_resources_test.go b/e2e/tenant_resources_test.go
index 80742b8d..c8f6805d 100644
--- a/e2e/tenant_resources_test.go
+++ b/e2e/tenant_resources_test.go
@@ -19,16 +19,16 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
var _ = Describe("creating namespaces within a Tenant with resources", func() {
- tnt := &capsulev1beta1.Tenant{
+ tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-resources",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "john",
Kind: "User",
diff --git a/e2e/tenantresource_test.go b/e2e/tenantresource_test.go
index e1cb8c1a..a1d7cede 100644
--- a/e2e/tenantresource_test.go
+++ b/e2e/tenantresource_test.go
@@ -22,18 +22,17 @@ import (
"k8s.io/utils/pointer"
"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/api"
)
var _ = Describe("Creating a TenantResource object", func() {
- solar := &capsulev1beta1.Tenant{
+ solar := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "energy-solar",
},
- Spec: capsulev1beta1.TenantSpec{
- Owners: capsulev1beta1.OwnerListSpec{
+ Spec: capsulev1beta2.TenantSpec{
+ Owners: capsulev1beta2.OwnerListSpec{
{
Name: "solar-user",
Kind: "User",
diff --git a/e2e/utils_test.go b/e2e/utils_test.go
index ad0cc1ba..46ec50d1 100644
--- a/e2e/utils_test.go
+++ b/e2e/utils_test.go
@@ -23,8 +23,7 @@ import (
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/kubernetes"
- capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
- capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
+ capsulev1beta2 "github.com/clastix/capsule/api/v1beta2"
)
const (
@@ -44,7 +43,7 @@ func NewNamespace(name string) *corev1.Namespace {
}
}
-func NamespaceCreation(ns *corev1.Namespace, owner capsulev1beta1.OwnerSpec, timeout time.Duration) AsyncAssertion {
+func NamespaceCreation(ns *corev1.Namespace, owner capsulev1beta2.OwnerSpec, timeout time.Duration) AsyncAssertion {
cs := ownerClient(owner)
return Eventually(func() (err error) {
_, err = cs.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{})
@@ -52,7 +51,7 @@ func NamespaceCreation(ns *corev1.Namespace, owner capsulev1beta1.OwnerSpec, tim
}, timeout, defaultPollInterval)
}
-func TenantNamespaceList(t *capsulev1beta1.Tenant, timeout time.Duration) AsyncAssertion {
+func TenantNamespaceList(t *capsulev1beta2.Tenant, timeout time.Duration) AsyncAssertion {
return Eventually(func() []string {
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: t.GetName()}, t)).Should(Succeed())
return t.Status.Namespaces
@@ -71,8 +70,8 @@ func EventuallyCreation(f interface{}) AsyncAssertion {
return Eventually(f, defaultTimeoutInterval, defaultPollInterval)
}
-func ModifyCapsuleConfigurationOpts(fn func(configuration *capsulev1alpha1.CapsuleConfiguration)) {
- config := &capsulev1alpha1.CapsuleConfiguration{}
+func ModifyCapsuleConfigurationOpts(fn func(configuration *capsulev1beta2.CapsuleConfiguration)) {
+ config := &capsulev1beta2.CapsuleConfiguration{}
Expect(k8sClient.Get(context.Background(), types.NamespacedName{Name: "default"}, config)).ToNot(HaveOccurred())
fn(config)
@@ -82,7 +81,7 @@ func ModifyCapsuleConfigurationOpts(fn func(configuration *capsulev1alpha1.Capsu
time.Sleep(1 * time.Second)
}
-func CheckForOwnerRoleBindings(ns *corev1.Namespace, owner capsulev1beta1.OwnerSpec, roles map[string]bool) func() error {
+func CheckForOwnerRoleBindings(ns *corev1.Namespace, owner capsulev1beta2.OwnerSpec, roles map[string]bool) func() error {
if roles == nil {
roles = map[string]bool{
"admin": false,
@@ -99,7 +98,7 @@ func CheckForOwnerRoleBindings(ns *corev1.Namespace, owner capsulev1beta1.OwnerS
var ownerName string
- if owner.Kind == capsulev1beta1.ServiceAccountOwner {
+ if owner.Kind == capsulev1beta2.ServiceAccountOwner {
parts := strings.Split(owner.Name, ":")
ownerName = parts[3]
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/pkg/api/allowed_list.go b/pkg/api/allowed_list.go
index 3bff873d..8d0a9e4f 100644
--- a/pkg/api/allowed_list.go
+++ b/pkg/api/allowed_list.go
@@ -7,10 +7,31 @@ import (
"regexp"
"sort"
"strings"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/labels"
+ "sigs.k8s.io/controller-runtime/pkg/client"
)
// +kubebuilder:object:generate=true
+type SelectorAllowedListSpec struct {
+ AllowedListSpec `json:",inline"`
+
+ Selector metav1.LabelSelector `json:",inline"`
+}
+
+func (in *SelectorAllowedListSpec) SelectorMatch(obj client.Object) bool {
+ selector, err := metav1.LabelSelectorAsSelector(&in.Selector)
+ if err != nil {
+ return false
+ }
+
+ return selector.Matches(labels.Set(obj.GetLabels()))
+}
+
+// +kubebuilder:object:generate=true
+
type AllowedListSpec struct {
Exact []string `json:"allowed,omitempty"`
Regex string `json:"allowedRegex,omitempty"`
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/api/zz_generated.deepcopy.go b/pkg/api/zz_generated.deepcopy.go
index 139a7ec8..d6545982 100644
--- a/pkg/api/zz_generated.deepcopy.go
+++ b/pkg/api/zz_generated.deepcopy.go
@@ -219,6 +219,23 @@ func (in *ResourceQuotaSpec) DeepCopy() *ResourceQuotaSpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SelectorAllowedListSpec) DeepCopyInto(out *SelectorAllowedListSpec) {
+ *out = *in
+ in.AllowedListSpec.DeepCopyInto(&out.AllowedListSpec)
+ in.Selector.DeepCopyInto(&out.Selector)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SelectorAllowedListSpec.
+func (in *SelectorAllowedListSpec) DeepCopy() *SelectorAllowedListSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(SelectorAllowedListSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceOptions) DeepCopyInto(out *ServiceOptions) {
*out = *in
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/errors.go b/pkg/webhook/ingress/errors.go
index 20988a52..79f6b5be 100644
--- a/pkg/webhook/ingress/errors.go
+++ b/pkg/webhook/ingress/errors.go
@@ -12,10 +12,10 @@ import (
type ingressClassForbiddenError struct {
className string
- spec api.AllowedListSpec
+ spec api.SelectorAllowedListSpec
}
-func NewIngressClassForbidden(className string, spec api.AllowedListSpec) error {
+func NewIngressClassForbidden(className string, spec api.SelectorAllowedListSpec) error {
return &ingressClassForbiddenError{
className: className,
spec: spec,
@@ -54,10 +54,10 @@ func (i ingressHostnameNotValidError) Error() string {
}
type ingressClassNotValidError struct {
- spec api.AllowedListSpec
+ spec api.SelectorAllowedListSpec
}
-func NewIngressClassNotValid(spec api.AllowedListSpec) error {
+func NewIngressClassNotValid(spec api.SelectorAllowedListSpec) error {
return &ingressClassNotValidError{
spec: spec,
}
@@ -68,7 +68,7 @@ func (i ingressClassNotValidError) Error() string {
}
// nolint:predeclared
-func appendClassError(spec api.AllowedListSpec) (append string) {
+func appendClassError(spec api.SelectorAllowedListSpec) (append string) {
if len(spec.Exact) > 0 {
append += fmt.Sprintf(", one of the following (%s)", strings.Join(spec.Exact, ", "))
}
@@ -77,6 +77,10 @@ func appendClassError(spec api.AllowedListSpec) (append string) {
append += fmt.Sprintf(", or matching the regex %s", spec.Regex)
}
+ if len(spec.Selector.MatchLabels) > 0 || len(spec.Selector.MatchExpressions) > 0 {
+ append += fmt.Sprintf(", or matching the label selector defined in the Tenant")
+ }
+
return
}
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..93021072 100644
--- a/pkg/webhook/ingress/validate_class.go
+++ b/pkg/webhook/ingress/validate_class.go
@@ -5,14 +5,20 @@ package ingress
import (
"context"
+ "net/http"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
+ networkingv1 "k8s.io/api/networking/v1"
+ networkingv1beta1 "k8s.io/api/networking/v1beta1"
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/util/version"
"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"
"github.com/clastix/capsule/pkg/configuration"
capsulewebhook "github.com/clastix/capsule/pkg/webhook"
"github.com/clastix/capsule/pkg/webhook/utils"
@@ -20,10 +26,43 @@ import (
type class struct {
configuration configuration.Configuration
+ version *version.Version
}
func Class(configuration configuration.Configuration) capsulewebhook.Handler {
- return &class{configuration: configuration}
+ version, _ := utils.GetK8sVersion()
+
+ return &class{
+ configuration: configuration,
+ version: version,
+ }
+}
+
+func (r *class) retrieveIngressClass(ctx context.Context, ctrlClient client.Client, ingressClassName *string) (client.Object, error) {
+ if r.version == nil || ingressClassName == nil {
+ return nil, nil
+ }
+
+ var obj client.Object
+
+ switch {
+ case r.version.Minor() < 18:
+ return nil, nil
+ case r.version.Minor() < 19:
+ obj = &networkingv1beta1.IngressClass{}
+ default:
+ obj = &networkingv1.IngressClass{}
+ }
+
+ if err := ctrlClient.Get(ctx, types.NamespacedName{Name: *ingressClassName}, obj); err != nil {
+ if k8serrors.IsNotFound(err) {
+ return nil, nil
+ }
+
+ return nil, err
+ }
+
+ return obj, nil
}
// nolint:dupl
@@ -34,7 +73,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 {
@@ -45,7 +84,14 @@ func (r *class) OnCreate(client client.Client, decoder *admission.Decoder, recor
return nil
}
- if err = r.validateClass(*tenant, ingress.IngressClass()); err == nil {
+ ic, err := r.retrieveIngressClass(ctx, client, ingress.IngressClass())
+ if err != nil {
+ response := admission.Errored(http.StatusInternalServerError, err)
+
+ return &response
+ }
+
+ if err = r.validateClass(*tenant, ingress.IngressClass(), ic); err == nil {
return nil
}
@@ -75,7 +121,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 {
@@ -86,7 +132,14 @@ func (r *class) OnUpdate(client client.Client, decoder *admission.Decoder, recor
return nil
}
- if err = r.validateClass(*tenant, ingress.IngressClass()); err == nil {
+ ic, err := r.retrieveIngressClass(ctx, client, ingress.IngressClass())
+ if err != nil {
+ response := admission.Errored(http.StatusInternalServerError, err)
+
+ return &response
+ }
+
+ if err = r.validateClass(*tenant, ingress.IngressClass(), ic); err == nil {
return nil
}
@@ -114,7 +167,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, ingressClassObj client.Object) error {
if tenant.Spec.IngressOptions.AllowedClasses == nil {
return nil
}
@@ -123,15 +176,21 @@ func (r *class) validateClass(tenant capsulev1beta1.Tenant, ingressClass *string
return NewIngressClassNotValid(*tenant.Spec.IngressOptions.AllowedClasses)
}
- var valid, matched bool
+ var valid, regex, match bool
if len(tenant.Spec.IngressOptions.AllowedClasses.Exact) > 0 {
valid = tenant.Spec.IngressOptions.AllowedClasses.ExactMatch(*ingressClass)
}
- matched = tenant.Spec.IngressOptions.AllowedClasses.RegexMatch(*ingressClass)
+ regex = tenant.Spec.IngressOptions.AllowedClasses.RegexMatch(*ingressClass)
+
+ if ingressClassObj != nil {
+ match = tenant.Spec.IngressOptions.AllowedClasses.SelectorMatch(ingressClassObj)
+ } else {
+ match = true
+ }
- if !valid && !matched {
+ if !valid && !regex && !match {
return NewIngressClassForbidden(*ingressClass, *tenant.Spec.IngressOptions.AllowedClasses)
}
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..41b79d43 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 {
@@ -133,6 +135,14 @@ func (r *userMetadataHandler) OnUpdate(client client.Client, decoder *admission.
labels, annotations := oldNs.GetLabels(), oldNs.GetAnnotations()
+ if labels == nil {
+ labels = make(map[string]string)
+ }
+
+ if annotations == nil {
+ annotations = make(map[string]string)
+ }
+
for key, value := range newNs.GetLabels() {
v, ok := labels[key]
if !ok {
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..f431b900 100644
--- a/pkg/webhook/pod/priorityclass.go
+++ b/pkg/webhook/pod/priorityclass.go
@@ -5,14 +5,18 @@ package pod
import (
"context"
+ "net/http"
corev1 "k8s.io/api/core/v1"
+ schedulingv1 "k8s.io/api/scheduling/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/fields"
+ "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"
)
@@ -23,6 +27,24 @@ func PriorityClass() capsulewebhook.Handler {
return &priorityClass{}
}
+func (h *priorityClass) class(ctx context.Context, c client.Client, name string) (client.Object, error) {
+ if len(name) == 0 {
+ return nil, nil
+ }
+
+ obj := &schedulingv1.PriorityClass{}
+
+ if err := c.Get(ctx, types.NamespacedName{Name: name}, obj); err != nil {
+ if errors.IsNotFound(err) {
+ return nil, nil
+ }
+
+ return nil, err
+ }
+
+ return obj, nil
+}
+
func (h *priorityClass) OnCreate(c client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
pod := &corev1.Pod{}
@@ -30,7 +52,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),
@@ -46,6 +68,13 @@ func (h *priorityClass) OnCreate(c client.Client, decoder *admission.Decoder, re
priorityClassName := pod.Spec.PriorityClassName
+ class, err := h.class(ctx, c, priorityClassName)
+ if err != nil {
+ response := admission.Errored(http.StatusInternalServerError, err)
+
+ return &response
+ }
+
switch {
case allowed == nil:
// Enforcement is not in place, skipping it at all
@@ -53,7 +82,7 @@ func (h *priorityClass) OnCreate(c client.Client, decoder *admission.Decoder, re
case len(priorityClassName) == 0:
// We don't have to force Pod to specify a Priority Class
return nil
- case !allowed.ExactMatch(priorityClassName) && !allowed.RegexMatch(priorityClassName):
+ case !allowed.ExactMatch(priorityClassName) && !allowed.RegexMatch(priorityClassName) && !allowed.SelectorMatch(class):
recorder.Eventf(&tntList.Items[0], corev1.EventTypeWarning, "ForbiddenPriorityClass", "Pod %s/%s is using Priority Class %s is forbidden for the current Tenant", pod.Namespace, pod.Name, priorityClassName)
response := admission.Denied(NewPodPriorityClassForbidden(priorityClassName, *allowed).Error())
diff --git a/pkg/webhook/pod/priorityclass_errors.go b/pkg/webhook/pod/priorityclass_errors.go
index 21b91d33..2d439c92 100644
--- a/pkg/webhook/pod/priorityclass_errors.go
+++ b/pkg/webhook/pod/priorityclass_errors.go
@@ -12,10 +12,10 @@ import (
type podPriorityClassForbiddenError struct {
priorityClassName string
- spec api.AllowedListSpec
+ spec api.SelectorAllowedListSpec
}
-func NewPodPriorityClassForbidden(priorityClassName string, spec api.AllowedListSpec) error {
+func NewPodPriorityClassForbidden(priorityClassName string, spec api.SelectorAllowedListSpec) error {
return &podPriorityClassForbiddenError{
priorityClassName: priorityClassName,
spec: spec,
@@ -35,6 +35,10 @@ func (f podPriorityClassForbiddenError) Error() (err string) {
extra = append(extra, fmt.Sprintf(" use one matching the following regex (%s)", f.spec.Regex))
}
+ if len(f.spec.Selector.MatchLabels) > 0 || len(f.spec.Selector.MatchExpressions) > 0 {
+ extra = append(extra, ", or matching the label selector defined in the Tenant")
+ }
+
err += strings.Join(extra, " or ")
return
diff --git a/pkg/webhook/pvc/errors.go b/pkg/webhook/pvc/errors.go
index 196f6b06..dc83403e 100644
--- a/pkg/webhook/pvc/errors.go
+++ b/pkg/webhook/pvc/errors.go
@@ -11,17 +11,17 @@ import (
)
type storageClassNotValidError struct {
- spec api.AllowedListSpec
+ spec api.SelectorAllowedListSpec
}
-func NewStorageClassNotValid(storageClasses api.AllowedListSpec) error {
+func NewStorageClassNotValid(storageClasses api.SelectorAllowedListSpec) error {
return &storageClassNotValidError{
spec: storageClasses,
}
}
// nolint:predeclared
-func appendError(spec api.AllowedListSpec) (append string) {
+func appendError(spec api.SelectorAllowedListSpec) (append string) {
if len(spec.Exact) > 0 {
append += fmt.Sprintf(", one of the following (%s)", strings.Join(spec.Exact, ", "))
}
@@ -30,6 +30,10 @@ func appendError(spec api.AllowedListSpec) (append string) {
append += fmt.Sprintf(", or matching the regex %s", spec.Regex)
}
+ if len(spec.Selector.MatchLabels) > 0 || len(spec.Selector.MatchExpressions) > 0 {
+ append += ", or matching the label selector defined in the Tenant"
+ }
+
return
}
@@ -39,10 +43,10 @@ func (s storageClassNotValidError) Error() (err string) {
type storageClassForbiddenError struct {
className string
- spec api.AllowedListSpec
+ spec api.SelectorAllowedListSpec
}
-func NewStorageClassForbidden(className string, storageClasses api.AllowedListSpec) error {
+func NewStorageClassForbidden(className string, storageClasses api.SelectorAllowedListSpec) error {
return &storageClassForbiddenError{
className: className,
spec: storageClasses,
diff --git a/pkg/webhook/pvc/validating.go b/pkg/webhook/pvc/validating.go
index 579a47f8..4014c949 100644
--- a/pkg/webhook/pvc/validating.go
+++ b/pkg/webhook/pvc/validating.go
@@ -5,14 +5,18 @@ package pvc
import (
"context"
+ "net/http"
corev1 "k8s.io/api/core/v1"
+ v1 "k8s.io/api/storage/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/fields"
+ "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"
)
@@ -23,16 +27,28 @@ func Handler() capsulewebhook.Handler {
return &handler{}
}
+func (h *handler) getStorageClass(ctx context.Context, c client.Client, name string) (client.Object, error) {
+ obj := &v1.StorageClass{}
+
+ if err := c.Get(ctx, types.NamespacedName{Name: name}, obj); err != nil {
+ if errors.IsNotFound(err) {
+ return nil, nil
+ }
+
+ return nil, err
+ }
+
+ return obj, nil
+}
+
func (h *handler) OnCreate(c client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
- var valid, matched bool
-
pvc := &corev1.PersistentVolumeClaim{}
if err := decoder.Decode(req, pvc); err != nil {
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 {
@@ -58,7 +74,25 @@ func (h *handler) OnCreate(c client.Client, decoder *admission.Decoder, recorder
}
sc := *pvc.Spec.StorageClassName
- if valid, matched = tnt.Spec.StorageClasses.ExactMatch(sc), tnt.Spec.StorageClasses.RegexMatch(sc); !valid && !matched {
+
+ scObj, err := h.getStorageClass(ctx, c, sc)
+ if err != nil {
+ response := admission.Errored(http.StatusInternalServerError, err)
+
+ return &response
+ }
+
+ var valid, regex, match bool
+
+ valid, regex = tnt.Spec.StorageClasses.ExactMatch(sc), tnt.Spec.StorageClasses.RegexMatch(sc)
+
+ if scObj != nil {
+ match = tnt.Spec.StorageClasses.SelectorMatch(scObj)
+ } else {
+ match = true
+ }
+
+ if !valid && !regex && !match {
recorder.Eventf(&tnt, corev1.EventTypeWarning, "ForbiddenStorageClass", "PersistentVolumeClaim %s/%s StorageClass %s is forbidden for the current Tenant", req.Namespace, req.Name, sc)
response := admission.Denied(NewStorageClassForbidden(*pvc.Spec.StorageClassName, *tnt.Spec.StorageClasses).Error())
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