Only owner Tenant specification key is mandatory (#153)

* Only Tenant owner specification key is mandatory

* Increasing default timeout to avoid e2e flakiness on GH Actions

* Ensuring also empty Namespace annotations and labels
This commit is contained in:
Dario Tranchitella
2020-12-11 15:47:29 +01:00
committed by GitHub
parent a3c77b3531
commit 007bdff512
30 changed files with 211 additions and 438 deletions
+5 -1
View File
@@ -23,7 +23,11 @@ import (
)
func (t *Tenant) IsFull() bool {
return t.Status.Namespaces.Len() >= int(t.Spec.NamespaceQuota)
// we don't have limits on assigned Namespaces
if t.Spec.NamespaceQuota == nil {
return false
}
return t.Status.Namespaces.Len() >= int(*t.Spec.NamespaceQuota)
}
func (t *Tenant) AssignNamespaces(namespaces []corev1.Namespace) {
+21 -36
View File
@@ -23,55 +23,42 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +kubebuilder:validation:Minimum=1
type NamespaceQuota uint
type AdditionalMetadata struct {
// +nullable
AdditionalLabels map[string]string `json:"additionalLabels"`
// +nullable
AdditionalAnnotations map[string]string `json:"additionalAnnotations"`
AdditionalLabels map[string]string `json:"additionalLabels,omitempty"`
AdditionalAnnotations map[string]string `json:"additionalAnnotations,omitempty"`
}
type StorageClassesSpec struct {
// +nullable
Allowed StorageClassList `json:"allowed"`
// +nullable
AllowedRegex string `json:"allowedRegex"`
Allowed StorageClassList `json:"allowed,omitempty"`
AllowedRegex string `json:"allowedRegex,omitempty"`
}
type IngressClassesSpec struct {
// +nullable
Allowed IngressClassList `json:"allowed"`
// +nullable
AllowedRegex string `json:"allowedRegex"`
Allowed IngressClassList `json:"allowed,omitempty"`
AllowedRegex string `json:"allowedRegex,omitempty"`
}
type ContainerRegistriesSpec struct {
// +nullable
Allowed RegistryList `json:"allowed"`
// +nullable
AllowedRegex string `json:"allowedRegex"`
Allowed RegistryList `json:"allowed,omitempty"`
AllowedRegex string `json:"allowedRegex,omitempty"`
}
// TenantSpec defines the desired state of Tenant
type TenantSpec struct {
Owner OwnerSpec `json:"owner"`
// +kubebuilder:validation:Optional
NamespacesMetadata AdditionalMetadata `json:"namespacesMetadata"`
// +kubebuilder:validation:Optional
ServicesMetadata AdditionalMetadata `json:"servicesMetadata"`
StorageClasses StorageClassesSpec `json:"storageClasses"`
IngressClasses IngressClassesSpec `json:"ingressClasses"`
ContainerRegistries *ContainerRegistriesSpec `json:"containerRegistries,omitempty"`
// +kubebuilder:validation:Optional
NodeSelector map[string]string `json:"nodeSelector"`
NamespaceQuota NamespaceQuota `json:"namespaceQuota"`
NetworkPolicies []networkingv1.NetworkPolicySpec `json:"networkPolicies,omitempty"`
LimitRanges []corev1.LimitRangeSpec `json:"limitRanges"`
// +kubebuilder:validation:Optional
ResourceQuota []corev1.ResourceQuotaSpec `json:"resourceQuotas"`
AdditionalRoleBindings []AdditionalRoleBindings `json:"additionalRoleBindings,omitempty"`
//+kubebuilder:validation:Minimum=1
NamespaceQuota *int32 `json:"namespaceQuota,omitempty"`
NamespacesMetadata AdditionalMetadata `json:"namespacesMetadata,omitempty"`
ServicesMetadata AdditionalMetadata `json:"servicesMetadata,omitempty"`
StorageClasses *StorageClassesSpec `json:"storageClasses,omitempty"`
IngressClasses *IngressClassesSpec `json:"ingressClasses,omitempty"`
ContainerRegistries *ContainerRegistriesSpec `json:"containerRegistries,omitempty"`
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
NetworkPolicies []networkingv1.NetworkPolicySpec `json:"networkPolicies,omitempty"`
LimitRanges []corev1.LimitRangeSpec `json:"limitRanges,omitempty"`
ResourceQuota []corev1.ResourceQuotaSpec `json:"resourceQuotas,omitempty"`
AdditionalRoleBindings []AdditionalRoleBindings `json:"additionalRoleBindings,omitempty"`
}
type AdditionalRoleBindings struct {
@@ -97,8 +84,6 @@ func (k Kind) String() string {
type TenantStatus struct {
Size uint `json:"size"`
Namespaces NamespaceList `json:"namespaces,omitempty"`
Users []string `json:"users,omitempty"`
Groups []string `json:"groups,omitempty"`
}
// +kubebuilder:object:root=true
+15 -12
View File
@@ -290,10 +290,23 @@ func (in *TenantList) DeepCopyObject() runtime.Object {
func (in *TenantSpec) DeepCopyInto(out *TenantSpec) {
*out = *in
out.Owner = in.Owner
if in.NamespaceQuota != nil {
in, out := &in.NamespaceQuota, &out.NamespaceQuota
*out = new(int32)
**out = **in
}
in.NamespacesMetadata.DeepCopyInto(&out.NamespacesMetadata)
in.ServicesMetadata.DeepCopyInto(&out.ServicesMetadata)
in.StorageClasses.DeepCopyInto(&out.StorageClasses)
in.IngressClasses.DeepCopyInto(&out.IngressClasses)
if in.StorageClasses != nil {
in, out := &in.StorageClasses, &out.StorageClasses
*out = new(StorageClassesSpec)
(*in).DeepCopyInto(*out)
}
if in.IngressClasses != nil {
in, out := &in.IngressClasses, &out.IngressClasses
*out = new(IngressClassesSpec)
(*in).DeepCopyInto(*out)
}
if in.ContainerRegistries != nil {
in, out := &in.ContainerRegistries, &out.ContainerRegistries
*out = new(ContainerRegistriesSpec)
@@ -354,16 +367,6 @@ func (in *TenantStatus) DeepCopyInto(out *TenantStatus) {
*out = make(NamespaceList, len(*in))
copy(*out, *in)
}
if in.Users != nil {
in, out := &in.Users, &out.Users
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Groups != nil {
in, out := &in.Groups, &out.Groups
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantStatus.
+92 -106
View File
@@ -7,37 +7,37 @@ metadata:
name: tenants.capsule.clastix.io
spec:
additionalPrinterColumns:
- JSONPath: .spec.namespaceQuota
description: The max amount of Namespaces can be created
name: Namespace quota
type: integer
- JSONPath: .status.size
description: The total amount of Namespaces in use
name: Namespace count
type: integer
- JSONPath: .spec.owner.name
description: The assigned Tenant owner
name: Owner name
type: string
- JSONPath: .spec.owner.kind
description: The assigned Tenant owner kind
name: Owner kind
type: string
- JSONPath: .spec.nodeSelector
description: Node Selector applied to Pods
name: Node selector
type: string
- JSONPath: .metadata.creationTimestamp
description: Age
name: Age
type: date
- JSONPath: .spec.namespaceQuota
description: The max amount of Namespaces can be created
name: Namespace quota
type: integer
- JSONPath: .status.size
description: The total amount of Namespaces in use
name: Namespace count
type: integer
- JSONPath: .spec.owner.name
description: The assigned Tenant owner
name: Owner name
type: string
- JSONPath: .spec.owner.kind
description: The assigned Tenant owner kind
name: Owner kind
type: string
- JSONPath: .spec.nodeSelector
description: Node Selector applied to Pods
name: Node selector
type: string
- JSONPath: .metadata.creationTimestamp
description: Age
name: Age
type: date
group: capsule.clastix.io
names:
kind: Tenant
listKind: TenantList
plural: tenants
shortNames:
- tnt
- tnt
singular: tenant
scope: Cluster
subresources:
@@ -61,20 +61,6 @@ spec:
spec:
description: TenantSpec defines the desired state of Tenant
properties:
containerRegistries:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
type: object
additionalRoleBindings:
items:
properties:
@@ -109,28 +95,38 @@ spec:
an error.
type: string
required:
- kind
- name
- kind
- name
type: object
type: array
required:
- clusterRoleName
- subjects
- clusterRoleName
- subjects
type: object
type: array
containerRegistries:
properties:
allowed:
items:
type: string
type: array
allowedRegex:
type: string
required:
- allowed
- allowedRegex
type: object
ingressClasses:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
- allowed
- allowedRegex
type: object
limitRanges:
items:
@@ -147,8 +143,8 @@ spec:
default:
additionalProperties:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: Default resource requirement limit value by
@@ -157,8 +153,8 @@ spec:
defaultRequest:
additionalProperties:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: DefaultRequest is the default resource requirement
@@ -168,8 +164,8 @@ spec:
max:
additionalProperties:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: Max usage constraints on this kind by resource
@@ -178,8 +174,8 @@ spec:
maxLimitRequestRatio:
additionalProperties:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: MaxLimitRequestRatio if specified, the named
@@ -191,8 +187,8 @@ spec:
min:
additionalProperties:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: Min usage constraints on this kind by resource
@@ -202,31 +198,29 @@ spec:
description: Type of resource that this limit applies to.
type: string
required:
- type
- type
type: object
type: array
required:
- limits
- limits
type: object
type: array
namespaceQuota:
minimum: 1
format: int32
type: integer
namespacesMetadata:
properties:
additionalAnnotations:
additionalProperties:
type: string
nullable: true
type: object
additionalLabels:
additionalProperties:
type: string
nullable: true
type: object
required:
- additionalAnnotations
- additionalLabels
- additionalAnnotations
- additionalLabels
type: object
networkPolicies:
items:
@@ -261,8 +255,8 @@ spec:
properties:
port:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
description: The port on the given protocol. This
can either be a numerical or named port on a pod.
If this field is not provided, this matches all
@@ -308,7 +302,7 @@ spec:
type: string
type: array
required:
- cidr
- cidr
type: object
namespaceSelector:
description: "Selects Namespaces using cluster-scoped
@@ -349,8 +343,8 @@ spec:
type: string
type: array
required:
- key
- operator
- key
- operator
type: object
type: array
matchLabels:
@@ -403,8 +397,8 @@ spec:
type: string
type: array
required:
- key
- operator
- key
- operator
type: object
type: array
matchLabels:
@@ -470,7 +464,7 @@ spec:
type: string
type: array
required:
- cidr
- cidr
type: object
namespaceSelector:
description: "Selects Namespaces using cluster-scoped
@@ -511,8 +505,8 @@ spec:
type: string
type: array
required:
- key
- operator
- key
- operator
type: object
type: array
matchLabels:
@@ -565,8 +559,8 @@ spec:
type: string
type: array
required:
- key
- operator
- key
- operator
type: object
type: array
matchLabels:
@@ -596,8 +590,8 @@ spec:
properties:
port:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
description: The port on the given protocol. This
can either be a numerical or named port on a pod.
If this field is not provided, this matches all
@@ -648,8 +642,8 @@ spec:
type: string
type: array
required:
- key
- operator
- key
- operator
type: object
type: array
matchLabels:
@@ -682,7 +676,7 @@ spec:
type: string
type: array
required:
- podSelector
- podSelector
type: object
type: array
nodeSelector:
@@ -694,14 +688,14 @@ spec:
properties:
kind:
enum:
- User
- Group
- User
- Group
type: string
name:
type: string
required:
- kind
- name
- kind
- name
type: object
resourceQuotas:
items:
@@ -711,8 +705,8 @@ spec:
hard:
additionalProperties:
anyOf:
- type: integer
- type: string
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'hard is the set of desired hard limits for each
@@ -752,8 +746,8 @@ spec:
type: string
type: array
required:
- operator
- scopeName
- operator
- scopeName
type: object
type: array
type: object
@@ -773,37 +767,29 @@ spec:
additionalAnnotations:
additionalProperties:
type: string
nullable: true
type: object
additionalLabels:
additionalProperties:
type: string
nullable: true
type: object
required:
- additionalAnnotations
- additionalLabels
- additionalAnnotations
- additionalLabels
type: object
storageClasses:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
- allowed
- allowedRegex
type: object
required:
- ingressClasses
- limitRanges
- namespaceQuota
- owner
- storageClasses
- owner
type: object
status:
description: TenantStatus defines the observed state of Tenant
@@ -823,14 +809,14 @@ spec:
type: string
type: array
required:
- size
- size
type: object
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
@@ -111,28 +111,18 @@ spec:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
type: object
ingressClasses:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
type: object
limitRanges:
items:
@@ -212,6 +202,7 @@ spec:
type: object
type: array
namespaceQuota:
format: int32
minimum: 1
type: integer
namespacesMetadata:
@@ -219,16 +210,11 @@ spec:
additionalAnnotations:
additionalProperties:
type: string
nullable: true
type: object
additionalLabels:
additionalProperties:
type: string
nullable: true
type: object
required:
- additionalAnnotations
- additionalLabels
type: object
networkPolicies:
items:
@@ -775,55 +761,33 @@ spec:
additionalAnnotations:
additionalProperties:
type: string
nullable: true
type: object
additionalLabels:
additionalProperties:
type: string
nullable: true
type: object
required:
- additionalAnnotations
- additionalLabels
type: object
storageClasses:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
type: object
required:
- ingressClasses
- limitRanges
- namespaceQuota
- owner
- storageClasses
type: object
status:
description: TenantStatus defines the observed state of Tenant
properties:
groups:
items:
type: string
type: array
namespaces:
items:
type: string
type: array
size:
type: integer
users:
items:
type: string
type: array
required:
- size
type: object
+31 -25
View File
@@ -478,23 +478,38 @@ func (r *TenantReconciler) syncNamespace(namespace string, tnt *capsulev1alpha1.
if a == nil {
a = make(map[string]string)
}
if len(tnt.Spec.IngressClasses.Allowed) > 0 {
a[capsulev1alpha1.AvailableIngressClassesAnnotation] = strings.Join(tnt.Spec.IngressClasses.Allowed, ",")
// resetting Capsule annotations
delete(a, capsulev1alpha1.AvailableIngressClassesAnnotation)
delete(a, capsulev1alpha1.AvailableIngressClassesRegexpAnnotation)
delete(a, capsulev1alpha1.AvailableStorageClassesAnnotation)
delete(a, capsulev1alpha1.AvailableStorageClassesRegexpAnnotation)
delete(a, capsulev1alpha1.AllowedRegistriesAnnotation)
delete(a, capsulev1alpha1.AllowedRegistriesRegexpAnnotation)
if tnt.Spec.IngressClasses != nil {
if len(tnt.Spec.IngressClasses.Allowed) > 0 {
a[capsulev1alpha1.AvailableIngressClassesAnnotation] = strings.Join(tnt.Spec.IngressClasses.Allowed, ",")
}
if len(tnt.Spec.IngressClasses.AllowedRegex) > 0 {
a[capsulev1alpha1.AvailableIngressClassesRegexpAnnotation] = tnt.Spec.IngressClasses.AllowedRegex
}
}
if len(tnt.Spec.IngressClasses.AllowedRegex) > 0 {
a[capsulev1alpha1.AvailableIngressClassesRegexpAnnotation] = tnt.Spec.IngressClasses.AllowedRegex
if tnt.Spec.StorageClasses != nil {
if len(tnt.Spec.StorageClasses.Allowed) > 0 {
a[capsulev1alpha1.AvailableStorageClassesAnnotation] = strings.Join(tnt.Spec.StorageClasses.Allowed, ",")
}
if len(tnt.Spec.StorageClasses.AllowedRegex) > 0 {
a[capsulev1alpha1.AvailableStorageClassesRegexpAnnotation] = tnt.Spec.StorageClasses.AllowedRegex
}
}
if len(tnt.Spec.StorageClasses.Allowed) > 0 {
a[capsulev1alpha1.AvailableStorageClassesAnnotation] = strings.Join(tnt.Spec.StorageClasses.Allowed, ",")
}
if len(tnt.Spec.StorageClasses.AllowedRegex) > 0 {
a[capsulev1alpha1.AvailableStorageClassesRegexpAnnotation] = tnt.Spec.StorageClasses.AllowedRegex
}
if tnt.Spec.ContainerRegistries != nil && len(tnt.Spec.ContainerRegistries.Allowed) > 0 {
a[capsulev1alpha1.AllowedRegistriesAnnotation] = strings.Join(tnt.Spec.ContainerRegistries.Allowed, ",")
}
if tnt.Spec.ContainerRegistries != nil && len(tnt.Spec.ContainerRegistries.AllowedRegex) > 0 {
a[capsulev1alpha1.AllowedRegistriesRegexpAnnotation] = tnt.Spec.ContainerRegistries.AllowedRegex
if tnt.Spec.ContainerRegistries != nil {
if len(tnt.Spec.ContainerRegistries.Allowed) > 0 {
a[capsulev1alpha1.AllowedRegistriesAnnotation] = strings.Join(tnt.Spec.ContainerRegistries.Allowed, ",")
}
if len(tnt.Spec.ContainerRegistries.AllowedRegex) > 0 {
a[capsulev1alpha1.AllowedRegistriesRegexpAnnotation] = tnt.Spec.ContainerRegistries.AllowedRegex
}
}
if aa := tnt.Spec.NamespacesMetadata.AdditionalAnnotations; aa != nil {
@@ -651,16 +666,7 @@ func (r *TenantReconciler) ownerRoleBinding(tenant *capsulev1alpha1.Tenant) erro
}
func (r *TenantReconciler) ensureNodeSelector(tenant *capsulev1alpha1.Tenant) (err error) {
if tenant.Spec.NodeSelector == nil {
return
}
for _, namespace := range tenant.Status.Namespaces {
selectorMap := tenant.Spec.NodeSelector
if selectorMap == nil {
return
}
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
@@ -673,7 +679,7 @@ func (r *TenantReconciler) ensureNodeSelector(tenant *capsulev1alpha1.Tenant) (e
ns.Annotations = make(map[string]string)
}
var selector []string
for k, v := range selectorMap {
for k, v := range tenant.Spec.NodeSelector {
selector = append(selector, fmt.Sprintf("%s=%s", k, v))
}
ns.Annotations["scheduler.alpha.kubernetes.io/node-selector"] = strings.Join(selector, ",")
-9
View File
@@ -24,7 +24,6 @@ import (
. "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"
@@ -41,14 +40,6 @@ var _ = Describe("creating a Namespace with additional Role Binding", func() {
Name: "dale",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
AdditionalRoleBindings: []v1alpha1.AdditionalRoleBindings{
{
ClusterRoleName: "crds-rolebinding",
+3 -4
View File
@@ -46,10 +46,9 @@ var _ = Describe("enforcing a Container Registry", func() {
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
StorageClasses: v1alpha1.StorageClassesSpec{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: &v1alpha1.StorageClassesSpec{},
IngressClasses: &v1alpha1.IngressClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
@@ -72,7 +71,7 @@ var _ = Describe("enforcing a Container Registry", func() {
}
for a, expected := range map[string]string{
"capsule.clastix.io/allowed-registries": "docker.io,docker.tld",
"capsule.clastix.io/allowed-registries": "docker.io,docker.tld",
"capsule.clastix.io/allowed-registries-regexp": `quay\.\w+`,
} {
var v string
-9
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Namespace as Tenant owner with custom --capsule-gro
Name: "alice",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
StorageClasses: v1alpha1.StorageClassesSpec{},
IngressClasses: v1alpha1.IngressClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
-17
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Namespace with --force-tenant-name flag", func() {
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
t2 := &v1alpha1.Tenant{
@@ -58,14 +49,6 @@ var _ = Describe("creating a Namespace with --force-tenant-name flag", func() {
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
+1 -11
View File
@@ -20,9 +20,7 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
@@ -40,21 +38,13 @@ var _ = Describe("when Tenant handles Ingress classes", func() {
Name: "ingress",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
StorageClasses: v1alpha1.StorageClassesSpec{},
IngressClasses: v1alpha1.IngressClassesSpec{
IngressClasses: &v1alpha1.IngressClassesSpec{
Allowed: []string{
"nginx",
"haproxy",
},
AllowedRegex: "^oil-.*$",
},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 3,
NodeSelector: map[string]string{},
NetworkPolicies: []networkingv1.NetworkPolicySpec{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
-8
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -40,8 +39,6 @@ var _ = Describe("creating a Namespace for a Tenant with additional metadata", f
Name: "gatsby",
Kind: "User",
},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
NamespacesMetadata: v1alpha1.AdditionalMetadata{
AdditionalLabels: map[string]string{
"k8s.io/custom-label": "foo",
@@ -52,11 +49,6 @@ var _ = Describe("creating a Namespace for a Tenant with additional metadata", f
"clastix.io/custom-annotation": "buzz",
},
},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
-9
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Namespace as Tenant owner", func() {
Name: "alice",
Kind: "User",
},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
+2 -9
View File
@@ -23,8 +23,8 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
"github.com/clastix/capsule/api/v1alpha1"
)
@@ -39,14 +39,7 @@ var _ = Describe("creating a Namespace over-quota", func() {
Name: "bob",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 3,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
NamespaceQuota: pointer.Int32Ptr(3),
},
}
JustBeforeEach(func() {
+1 -6
View File
@@ -43,15 +43,12 @@ var _ = Describe("when Tenant owner interacts with the webhooks", func() {
Name: "ruby",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
StorageClasses: v1alpha1.StorageClassesSpec{
StorageClasses: &v1alpha1.StorageClassesSpec{
Allowed: []string{
"cephfs",
"glusterfs",
},
},
IngressClasses: v1alpha1.IngressClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{
{
Limits: []corev1.LimitRangeItem{
@@ -69,8 +66,6 @@ var _ = Describe("when Tenant owner interacts with the webhooks", func() {
},
},
},
NamespaceQuota: 3,
NodeSelector: map[string]string{},
NetworkPolicies: []networkingv1.NetworkPolicySpec{
{
Egress: []networkingv1.NetworkPolicyEgressRule{
-9
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Namespace with --protected-namespace-regex enabled"
Name: "alice",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
-8
View File
@@ -27,7 +27,6 @@ import (
. "github.com/onsi/gomega"
v1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -46,10 +45,6 @@ var _ = Describe("exceeding Tenant resource quota", func() {
Name: "bobby",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{
{
Limits: []corev1.LimitRangeItem{
@@ -95,9 +90,6 @@ var _ = Describe("exceeding Tenant resource quota", func() {
},
},
},
NetworkPolicies: []networkingv1.NetworkPolicySpec{},
NamespaceQuota: 2,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{
{
Hard: map[corev1.ResourceName]resource.Quantity{
-8
View File
@@ -39,14 +39,6 @@ var _ = Describe("creating a Namespace trying to select a third Tenant", func()
Name: "undefined",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
-33
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Namespace without a Tenant selector when user owns
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
t2 := &v1alpha1.Tenant{
@@ -58,14 +49,6 @@ var _ = Describe("creating a Namespace without a Tenant selector when user owns
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
t3 := &v1alpha1.Tenant{
@@ -77,14 +60,6 @@ var _ = Describe("creating a Namespace without a Tenant selector when user owns
Name: "john",
Kind: "Group",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
t4 := &v1alpha1.Tenant{
@@ -96,14 +71,6 @@ var _ = Describe("creating a Namespace without a Tenant selector when user owns
Name: "john",
Kind: "Group",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
It("should fail", func() {
-17
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Namespace with Tenant selector when user owns multi
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
t2 := &v1alpha1.Tenant{
@@ -58,14 +49,6 @@ var _ = Describe("creating a Namespace with Tenant selector when user owns multi
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
-7
View File
@@ -41,9 +41,6 @@ var _ = Describe("creating a Service/Endpoint/EndpointSlice for a Tenant with ad
Name: "gatsby",
Kind: "User",
},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{
AdditionalLabels: map[string]string{
"k8s.io/custom-label": "foo",
@@ -54,10 +51,6 @@ var _ = Describe("creating a Service/Endpoint/EndpointSlice for a Tenant with ad
"clastix.io/custom-annotation": "buzz",
},
},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
epsCR := &rbacv1.ClusterRole{
+1 -10
View File
@@ -21,7 +21,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
@@ -39,21 +38,13 @@ var _ = Describe("when Tenant handles Storage classes", func() {
Name: "storage",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
StorageClasses: v1alpha1.StorageClassesSpec{
StorageClasses: &v1alpha1.StorageClassesSpec{
Allowed: []string{
"cephfs",
"glusterfs",
},
AllowedRegex: "^oil-.*$",
},
IngressClasses: v1alpha1.IngressClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 3,
NodeSelector: map[string]string{},
NetworkPolicies: []networkingv1.NetworkPolicySpec{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
-9
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Tenant with wrong name", func() {
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
It("should fail", func() {
+3 -10
View File
@@ -23,7 +23,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/clastix/capsule/api/v1alpha1"
@@ -39,14 +38,6 @@ var _ = Describe("creating a Namespace with group Tenant owner", func() {
Name: "alice",
Kind: "Group",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{},
NamespaceQuota: 10,
NodeSelector: map[string]string{},
ResourceQuota: []corev1.ResourceQuotaSpec{},
},
}
JustBeforeEach(func() {
@@ -62,6 +53,8 @@ var _ = Describe("creating a Namespace with group Tenant owner", func() {
ns := NewNamespace("gto-namespace")
NamespaceCreation(ns, tnt, defaultTimeoutInterval).Should(Succeed())
TenantNamespaceList(tnt, podRecreationTimeoutInterval).Should(ContainElement(ns.GetName()))
GroupShouldBeUsedInTenantRoleBinding(ns, tnt, defaultTimeoutInterval)
for _, a := range KindInTenantRoleBindingAssertions(ns, defaultTimeoutInterval) {
a.Should(BeIdenticalTo("Group"))
}
})
})
-5
View File
@@ -44,10 +44,6 @@ var _ = Describe("changing Tenant managed Kubernetes resources", func() {
Name: "laura",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{
{
Limits: []corev1.LimitRangeItem{
@@ -137,7 +133,6 @@ var _ = Describe("changing Tenant managed Kubernetes resources", func() {
},
},
},
NamespaceQuota: 4,
NodeSelector: map[string]string{
"kubernetes.io/os": "linux",
},
-5
View File
@@ -45,10 +45,6 @@ var _ = Describe("creating namespaces within a Tenant with resources", func() {
Name: "john",
Kind: "User",
},
NamespacesMetadata: v1alpha1.AdditionalMetadata{},
ServicesMetadata: v1alpha1.AdditionalMetadata{},
IngressClasses: v1alpha1.IngressClassesSpec{},
StorageClasses: v1alpha1.StorageClassesSpec{},
LimitRanges: []corev1.LimitRangeSpec{
{
Limits: []corev1.LimitRangeItem{
@@ -138,7 +134,6 @@ var _ = Describe("creating namespaces within a Tenant with resources", func() {
},
},
},
NamespaceQuota: 3,
NodeSelector: map[string]string{
"kubernetes.io/os": "linux",
},
+11 -9
View File
@@ -38,7 +38,7 @@ import (
)
const (
defaultTimeoutInterval = 10 * time.Second
defaultTimeoutInterval = 20 * time.Second
podRecreationTimeoutInterval = 90 * time.Second
defaultPollInterval = time.Second
)
@@ -115,15 +115,17 @@ func ModifyCapsuleManagerPodArgs(args []string) {
time.Sleep(defaultTimeoutInterval)
}
func GroupShouldBeUsedInTenantRoleBinding(ns *corev1.Namespace, t *v1alpha1.Tenant, timeout time.Duration) {
for _, roleBindingName := range tenantRoleBindingNames {
tenantRoleBindig := &rbacv1.RoleBinding{}
Eventually(func() string {
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: roleBindingName, Namespace: ns.GetName()}, tenantRoleBindig)).Should(Succeed())
return tenantRoleBindig.Subjects[0].Kind
}, timeout, defaultPollInterval).Should(BeIdenticalTo("Group"))
func KindInTenantRoleBindingAssertions(ns *corev1.Namespace, timeout time.Duration) (out []AsyncAssertion) {
for _, rbn := range tenantRoleBindingNames {
rb := &rbacv1.RoleBinding{}
out = append(out, Eventually(func() string {
if err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: rbn, Namespace: ns.GetName()}, rb); err != nil {
return ""
}
return rb.Subjects[0].Kind
}, timeout, defaultPollInterval))
}
return
}
func GetKubernetesSemVer() (major, minor int, ver string) {
+6 -2
View File
@@ -134,9 +134,13 @@ func (r *handler) validateIngress(ctx context.Context, c client.Client, object I
tnt := tl.Items[0]
if tnt.Spec.IngressClasses == nil {
return admission.Allowed("")
}
ingressClass := object.IngressClass()
if ingressClass == nil {
return admission.Errored(http.StatusBadRequest, NewIngressClassNotValid(tnt.Spec.IngressClasses))
return admission.Errored(http.StatusBadRequest, NewIngressClassNotValid(*tnt.Spec.IngressClasses))
}
if len(tnt.Spec.IngressClasses.Allowed) > 0 {
@@ -148,7 +152,7 @@ func (r *handler) validateIngress(ctx context.Context, c client.Client, object I
}
if !valid && !matched {
return admission.Errored(http.StatusBadRequest, NewIngressClassForbidden(*ingressClass, tnt.Spec.IngressClasses))
return admission.Errored(http.StatusBadRequest, NewIngressClassForbidden(*ingressClass, *tnt.Spec.IngressClasses))
}
return admission.Allowed("")
+8 -4
View File
@@ -79,11 +79,16 @@ func (h *handler) OnCreate(c client.Client, decoder *admission.Decoder) capsulew
return admission.Allowed("")
}
tnt := tl.Items[0]
if tnt.Spec.StorageClasses == nil {
return admission.Allowed("")
}
if pvc.Spec.StorageClassName == nil {
return admission.Errored(http.StatusBadRequest, NewStorageClassNotValid(tl.Items[0].Spec.StorageClasses))
return admission.Errored(http.StatusBadRequest, NewStorageClassNotValid(*tl.Items[0].Spec.StorageClasses))
}
tnt := tl.Items[0]
sc := *pvc.Spec.StorageClassName
if len(tnt.Spec.StorageClasses.Allowed) > 0 {
@@ -95,10 +100,9 @@ func (h *handler) OnCreate(c client.Client, decoder *admission.Decoder) capsulew
}
if !valid && !matched {
return admission.Errored(http.StatusBadRequest, NewStorageClassForbidden(*pvc.Spec.StorageClassName, tnt.Spec.StorageClasses))
return admission.Errored(http.StatusBadRequest, NewStorageClassForbidden(*pvc.Spec.StorageClassName, *tnt.Spec.StorageClasses))
}
return admission.Allowed("")
}
}
+10 -3
View File
@@ -57,7 +57,7 @@ func Handler() capsulewebhook.Handler {
return &handler{}
}
func (r *handler) OnCreate(client client.Client, decoder *admission.Decoder) capsulewebhook.Func {
func (h *handler) OnCreate(client client.Client, decoder *admission.Decoder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) admission.Response {
tnt := &v1alpha1.Tenant{}
if err := decoder.Decode(req, tnt); err != nil {
@@ -70,19 +70,26 @@ func (r *handler) OnCreate(client client.Client, decoder *admission.Decoder) cap
}
// Validate ingressClasses regexp
if len(tnt.Spec.IngressClasses.AllowedRegex) > 0 {
if tnt.Spec.IngressClasses != nil && len(tnt.Spec.IngressClasses.AllowedRegex) > 0 {
if _, err := regexp.Compile(tnt.Spec.IngressClasses.AllowedRegex); err != nil {
return admission.Denied("Unable to compile ingressClasses allowedRegex")
}
}
// Validate storageClasses regexp
if len(tnt.Spec.StorageClasses.AllowedRegex) > 0 {
if tnt.Spec.StorageClasses != nil && len(tnt.Spec.StorageClasses.AllowedRegex) > 0 {
if _, err := regexp.Compile(tnt.Spec.StorageClasses.AllowedRegex); err != nil {
return admission.Denied("Unable to compile storageClasses allowedRegex")
}
}
// Validate containerRegistries regexp
if tnt.Spec.ContainerRegistries != nil && len(tnt.Spec.ContainerRegistries.AllowedRegex) > 0 {
if _, err := regexp.Compile(tnt.Spec.ContainerRegistries.AllowedRegex); err != nil {
return admission.Denied("Unable to compile containerRegistries allowedRegex")
}
}
return admission.Allowed("")
}
}