Repository: projectcapsule/capsule

Issue:
feat: available classes in status
<!--
Yay, it look you're enjoying Capsule and, first, thanks for that!

We're trying to build a community drive Open Source project, so don't
hesitate proposing your enhancement ideas: keep in mind, since we would like
to keep it as agnostic as possible, to motivate all your assumptions.

-->

Add the available for each tenant to it's status:

* Ingress
* Gateway
* Storage
* Runtime
* PriorityClass

Discussion:

Solution patch:
diff --git a/api/v1beta2/gateway_options.go b/api/v1beta2/gateway_options.go
index 296a023..65c469c 100644
--- a/api/v1beta2/gateway_options.go
+++ b/api/v1beta2/gateway_options.go
@@ -8,5 +8,5 @@ import (
 )
 
 type GatewayOptions struct {
-	AllowedClasses *api.SelectionListWithDefaultSpec `json:"allowedClasses,omitempty"`
+	AllowedClasses *api.DefaultAllowedListSpec `json:"allowedClasses,omitempty"`
 }
diff --git a/api/v1beta2/tenant_status.go b/api/v1beta2/tenant_status.go
index e10738b..41c7e7e 100644
--- a/api/v1beta2/tenant_status.go
+++ b/api/v1beta2/tenant_status.go
@@ -19,6 +19,9 @@ const (
 
 // Returns the observed state of the Tenant.
 type TenantStatus struct {
+	// Allowed Cluster Objects within Tenant
+	TenantAvailableStatus `json:",inline"`
+
 	// +kubebuilder:default=Active
 	// The operational state of the Tenant. Possible values are "Active", "Cordoned".
 	State tenantState `json:"state"`
@@ -50,6 +53,22 @@ type TenantStatusNamespaceMetadata struct {
 	Annotations map[string]string `json:"annotations,omitempty"`
 }
 
+type TenantAvailableStatus struct {
+	// Available Class Types within Tenant
+	Classes TenantAvailableClassesStatus `json:"classes,omitempty"`
+}
+
+type TenantAvailableClassesStatus struct {
+	// Available Storageclasses (Only collected if any matching condition is specified)
+	StorageClasses []string `json:"storage,omitempty"`
+	// Available PriorityClasses
+	PriorityClasses []string `json:"priority,omitempty"`
+	// Available StorageClasses
+	RuntimeClasses []string `json:"runtime,omitempty"`
+	// Available GatewayClasses
+	GatewayClasses []string `json:"gateway,omitempty"`
+}
+
 func (ms *TenantStatus) GetInstance(stat *TenantStatusNamespaceItem) *TenantStatusNamespaceItem {
 	for _, source := range ms.Spaces {
 		if ms.instancequal(source, stat) {
diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go
index feee1de..461b73b 100644
--- a/api/v1beta2/zz_generated.deepcopy.go
+++ b/api/v1beta2/zz_generated.deepcopy.go
@@ -155,7 +155,7 @@ func (in *GatewayOptions) DeepCopyInto(out *GatewayOptions) {
 	*out = *in
 	if in.AllowedClasses != nil {
 		in, out := &in.AllowedClasses, &out.AllowedClasses
-		*out = new(api.SelectionListWithDefaultSpec)
+		*out = new(api.DefaultAllowedListSpec)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -899,6 +899,57 @@ func (in *Tenant) DeepCopyObject() runtime.Object {
 	return nil
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TenantAvailableClassesStatus) DeepCopyInto(out *TenantAvailableClassesStatus) {
+	*out = *in
+	if in.StorageClasses != nil {
+		in, out := &in.StorageClasses, &out.StorageClasses
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.PriorityClasses != nil {
+		in, out := &in.PriorityClasses, &out.PriorityClasses
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.RuntimeClasses != nil {
+		in, out := &in.RuntimeClasses, &out.RuntimeClasses
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.GatewayClasses != nil {
+		in, out := &in.GatewayClasses, &out.GatewayClasses
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantAvailableClassesStatus.
+func (in *TenantAvailableClassesStatus) DeepCopy() *TenantAvailableClassesStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(TenantAvailableClassesStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TenantAvailableStatus) DeepCopyInto(out *TenantAvailableStatus) {
+	*out = *in
+	in.Classes.DeepCopyInto(&out.Classes)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantAvailableStatus.
+func (in *TenantAvailableStatus) DeepCopy() *TenantAvailableStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(TenantAvailableStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *TenantList) DeepCopyInto(out *TenantList) {
 	*out = *in
@@ -1127,6 +1178,7 @@ func (in *TenantSpec) DeepCopy() *TenantSpec {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *TenantStatus) DeepCopyInto(out *TenantStatus) {
 	*out = *in
+	in.TenantAvailableStatus.DeepCopyInto(&out.TenantAvailableStatus)
 	if in.Namespaces != nil {
 		in, out := &in.Namespaces, &out.Namespaces
 		*out = make([]string, len(*in))
diff --git a/charts/capsule/crds/capsule.clastix.io_tenants.yaml b/charts/capsule/crds/capsule.clastix.io_tenants.yaml
index 2668047..f333b60 100644
--- a/charts/capsule/crds/capsule.clastix.io_tenants.yaml
+++ b/charts/capsule/crds/capsule.clastix.io_tenants.yaml
@@ -123,10 +123,13 @@ spec:
                   can use only one of the allowed trusted registries. Optional.
                 properties:
                   allowed:
+                    description: Match exact elements which are allowed as class names
+                      within this tenant
                     items:
                       type: string
                     type: array
                   allowedRegex:
+                    description: Match elements by regex (DEPRECATED)
                     type: string
                 type: object
               imagePullPolicies:
@@ -151,10 +154,13 @@ spec:
                       Optional.
                     properties:
                       allowed:
+                        description: Match exact elements which are allowed as class
+                          names within this tenant
                         items:
                           type: string
                         type: array
                       allowedRegex:
+                        description: Match elements by regex (DEPRECATED)
                         type: string
                     type: object
                   allowedHostnames:
@@ -164,10 +170,13 @@ spec:
                       Optional.
                     properties:
                       allowed:
+                        description: Match exact elements which are allowed as class
+                          names within this tenant
                         items:
                           type: string
                         type: array
                       allowedRegex:
+                        description: Match elements by regex (DEPRECATED)
                         type: string
                     type: object
                   hostnameCollisionScope:
@@ -840,10 +849,13 @@ spec:
                   can use only one of the allowed PriorityClasses. Optional.
                 properties:
                   allowed:
+                    description: Match exact elements which are allowed as class names
+                      within this tenant
                     items:
                       type: string
                     type: array
                   allowedRegex:
+                    description: Match elements by regex (DEPRECATED)
                     type: string
                 type: object
               resourceQuotas:
@@ -1012,10 +1024,13 @@ spec:
                   Optional.
                 properties:
                   allowed:
+                    description: Match exact elements which are allowed as class names
+                      within this tenant
                     items:
                       type: string
                     type: array
                   allowedRegex:
+                    description: Match elements by regex (DEPRECATED)
                     type: string
                 type: object
             required:
@@ -1164,10 +1179,13 @@ spec:
                   can use only one of the allowed trusted registries. Optional.
                 properties:
                   allowed:
+                    description: Match exact elements which are allowed as class names
+                      within this tenant
                     items:
                       type: string
                     type: array
                   allowedRegex:
+                    description: Match elements by regex (DEPRECATED)
                     type: string
                 type: object
               cordoned:
@@ -1191,6 +1209,15 @@ spec:
                 properties:
                   allowedClasses:
                     properties:
+                      allowed:
+                        description: Match exact elements which are allowed as class
+                          names within this tenant
+                        items:
+                          type: string
+                        type: array
+                      allowedRegex:
+                        description: Match elements by regex (DEPRECATED)
+                        type: string
                       default:
                         type: string
                       matchExpressions:
@@ -1264,10 +1291,13 @@ spec:
                       Optional.
                     properties:
                       allowed:
+                        description: Match exact elements which are allowed as class
+                          names within this tenant
                         items:
                           type: string
                         type: array
                       allowedRegex:
+                        description: Match elements by regex (DEPRECATED)
                         type: string
                       default:
                         type: string
@@ -1321,10 +1351,13 @@ spec:
                       Optional.
                     properties:
                       allowed:
+                        description: Match exact elements which are allowed as class
+                          names within this tenant
                         items:
                           type: string
                         type: array
                       allowedRegex:
+                        description: Match elements by regex (DEPRECATED)
                         type: string
                     type: object
                   hostnameCollisionScope:
@@ -2139,10 +2172,13 @@ spec:
                   Optional.
                 properties:
                   allowed:
+                    description: Match exact elements which are allowed as class names
+                      within this tenant
                     items:
                       type: string
                     type: array
                   allowedRegex:
+                    description: Match elements by regex (DEPRECATED)
                     type: string
                   default:
                     type: string
@@ -2283,10 +2319,13 @@ spec:
                   Optional.
                 properties:
                   allowed:
+                    description: Match exact elements which are allowed as class names
+                      within this tenant
                     items:
                       type: string
                     type: array
                   allowedRegex:
+                    description: Match elements by regex (DEPRECATED)
                     type: string
                   default:
                     type: string
@@ -2413,10 +2452,13 @@ spec:
                   Optional.
                 properties:
                   allowed:
+                    description: Match exact elements which are allowed as class names
+                      within this tenant
                     items:
                       type: string
                     type: array
                   allowedRegex:
+                    description: Match elements by regex (DEPRECATED)
                     type: string
                   default:
                     type: string
@@ -2467,6 +2509,31 @@ spec:
           status:
             description: Returns the observed state of the Tenant.
             properties:
+              classes:
+                description: Available Class Types within Tenant
+                properties:
+                  gateway:
+                    description: Available GatewayClasses
+                    items:
+                      type: string
+                    type: array
+                  priority:
+                    description: Available PriorityClasses
+                    items:
+                      type: string
+                    type: array
+                  runtime:
+                    description: Available StorageClasses
+                    items:
+                      type: string
+                    type: array
+                  storage:
+                    description: Available Storageclasses (Only collected if any matching
+                      condition is specified)
+                    items:
+                      type: string
+                    type: array
+                type: object
               conditions:
                 description: Tenant Condition
                 items:
diff --git a/internal/controllers/tenant/manager.go b/internal/controllers/tenant/manager.go
index 85ea12d..f82ef89 100644
--- a/internal/controllers/tenant/manager.go
+++ b/internal/controllers/tenant/manager.go
@@ -10,7 +10,10 @@ import (
 	"github.com/go-logr/logr"
 	corev1 "k8s.io/api/core/v1"
 	networkingv1 "k8s.io/api/networking/v1"
+	nodev1 "k8s.io/api/node/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
+	schedulingv1 "k8s.io/api/scheduling/v1"
+	storagev1 "k8s.io/api/storage/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -23,6 +26,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/controller"
 	"sigs.k8s.io/controller-runtime/pkg/handler"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
+	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
 
 	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
 	"github.com/projectcapsule/capsule/internal/controllers/utils"
@@ -54,7 +58,35 @@ func (r *Manager) SetupWithManager(mgr ctrl.Manager, ctrlConfig utils.Controller
 			utils.NamesMatchingPredicate(ctrlConfig.ConfigurationName),
 			builder.WithPredicates(utils.CapsuleConfigSpecChangedPredicate),
 		).
-		Watches(&corev1.Namespace{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &capsulev1beta2.Tenant{})).
+		Watches(
+			&corev1.Namespace{},
+			handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &capsulev1beta2.Tenant{}),
+		).
+		Watches(
+			&storagev1.StorageClass{},
+			handler.EnqueueRequestsFromMapFunc(r.enqueueAllTenants),
+			builder.WithPredicates(utils.UpdatedMetadataPredicate),
+		).
+		Watches(
+			&gatewayv1.GatewayClass{},
+			handler.EnqueueRequestsFromMapFunc(r.enqueueAllTenants),
+			builder.WithPredicates(utils.UpdatedMetadataPredicate),
+		).
+		Watches(
+			&networkingv1.IngressClass{},
+			handler.EnqueueRequestsFromMapFunc(r.enqueueAllTenants),
+			builder.WithPredicates(utils.UpdatedMetadataPredicate),
+		).
+		Watches(
+			&schedulingv1.PriorityClass{},
+			handler.EnqueueRequestsFromMapFunc(r.enqueueAllTenants),
+			builder.WithPredicates(utils.UpdatedMetadataPredicate),
+		).
+		Watches(
+			&nodev1.RuntimeClass{},
+			handler.EnqueueRequestsFromMapFunc(r.enqueueAllTenants),
+			builder.WithPredicates(utils.UpdatedMetadataPredicate),
+		).
 		WithOptions(controller.Options{MaxConcurrentReconciles: ctrlConfig.MaxConcurrentReconciles}).
 		Complete(r)
 }
@@ -151,6 +183,13 @@ func (r Manager) Reconcile(ctx context.Context, request ctrl.Request) (result ct
 		return result, err
 	}
 
+	// Collect available resources
+	if err = r.collectAvailableResources(ctx, instance); err != nil {
+		err = fmt.Errorf("cannot collect available resources: %w", err)
+
+		return result, err
+	}
+
 	r.Log.V(4).Info("Tenant reconciling completed")
 
 	return ctrl.Result{}, err
diff --git a/internal/controllers/tenant/status.go b/internal/controllers/tenant/status.go
new file mode 100644
index 0000000..069ef2e
--- /dev/null
+++ b/internal/controllers/tenant/status.go
@@ -0,0 +1,172 @@
+// Copyright 2020-2025 Project Capsule Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package tenant
+
+import (
+	"context"
+	"sort"
+
+	nodev1 "k8s.io/api/node/v1"
+	schedulingv1 "k8s.io/api/scheduling/v1"
+	storagev1 "k8s.io/api/storage/v1"
+	"k8s.io/apimachinery/pkg/api/meta"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/log"
+	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
+
+	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
+	"github.com/projectcapsule/capsule/pkg/api"
+)
+
+func (r *Manager) collectAvailableResources(ctx context.Context, tnt *capsulev1beta2.Tenant) (err error) {
+	log := log.FromContext(ctx)
+
+	log.V(5).Info("collecting available storageclasses")
+
+	if tnt.Status.Classes.StorageClasses, err = listObjectNamesBySelector(
+		ctx,
+		r.Client,
+		tnt.Spec.StorageClasses,
+		&storagev1.StorageClassList{},
+	); err != nil {
+		return err
+	}
+
+	log.V(5).Info("collected available storageclasses", "size", len(tnt.Status.Classes.StorageClasses))
+
+	if tnt.Status.Classes.PriorityClasses, err = listObjectNamesBySelector(
+		ctx,
+		r.Client,
+		tnt.Spec.PriorityClasses,
+		&schedulingv1.PriorityClassList{},
+	); err != nil {
+		return err
+	}
+
+	log.V(5).Info("collected available priorityclasses", "size", len(tnt.Status.Classes.PriorityClasses))
+
+	if tnt.Status.Classes.GatewayClasses, err = listObjectNamesBySelector(
+		ctx,
+		r.Client,
+		tnt.Spec.GatewayOptions.AllowedClasses,
+		&gatewayv1.GatewayClassList{},
+	); err != nil {
+		return err
+	}
+
+	log.V(5).Info("collected available gatewayclasses", "size", len(tnt.Status.Classes.GatewayClasses))
+
+	if tnt.Status.Classes.RuntimeClasses, err = listObjectNamesBySelector(
+		ctx,
+		r.Client,
+		tnt.Spec.RuntimeClasses,
+		&nodev1.RuntimeClassList{},
+	); err != nil {
+		return err
+	}
+
+	log.V(5).Info("collected available runtimeclasses", "size", len(tnt.Status.Classes.RuntimeClasses))
+
+	return nil
+}
+
+// ListObjectNamesBySelector lists Kubernetes objects of the given List type (cluster- or namespaced)
+// matching the provided LabelSelector, and returns their .metadata.name values.
+func listObjectNamesBySelector(
+	ctx context.Context,
+	c client.Client,
+	allowed *api.DefaultAllowedListSpec,
+	list client.ObjectList,
+	opts ...client.ListOption,
+) (objects []string, err error) {
+	defer func() {
+		if err == nil {
+			sort.Strings(objects)
+		}
+	}()
+
+	if err := c.List(ctx, list, opts...); err != nil {
+		return nil, err
+	}
+
+	objs, err := meta.ExtractList(list)
+	if err != nil {
+		return nil, err
+	}
+
+	allNames := make(map[string]struct{})
+
+	selected := make(map[string]struct{})
+
+	hasSelector := false
+	if allowed != nil {
+		hasSelector = len(allowed.MatchLabels) > 0 ||
+			len(allowed.MatchExpressions) > 0
+	}
+
+	if allowed == nil || (!hasSelector && len(allowed.Exact) == 0) {
+		for _, o := range objs {
+			accessor, err := meta.Accessor(o)
+			if err != nil {
+				return nil, err
+			}
+
+			objects = append(objects, accessor.GetName())
+		}
+
+		return objects, nil
+	}
+
+	var sel labels.Selector
+	if hasSelector {
+		sel, err = metav1.LabelSelectorAsSelector(&allowed.LabelSelector)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	for _, obj := range objs {
+		accessor, err := meta.Accessor(obj)
+		if err != nil {
+			return nil, err
+		}
+
+		name := accessor.GetName()
+
+		allNames[name] = struct{}{}
+
+		if hasSelector {
+			lbls := labels.Set(accessor.GetLabels())
+
+			if sel.Matches(lbls) {
+				selected[name] = struct{}{}
+			}
+		}
+	}
+
+	exact := allowed.Exact
+	if allowed.Default != "" {
+		exact = append(exact, allowed.Default)
+	}
+
+	for _, name := range exact {
+		if _, exists := allNames[name]; !exists {
+			continue
+		}
+
+		if _, already := selected[name]; already {
+			continue
+		}
+
+		selected[name] = struct{}{}
+	}
+
+	for name := range selected {
+		objects = append(objects, name)
+	}
+
+	return objects, nil
+}
diff --git a/internal/controllers/utils/predicates.go b/internal/controllers/utils/predicates.go
index c436a45..268d18d 100644
--- a/internal/controllers/utils/predicates.go
+++ b/internal/controllers/utils/predicates.go
@@ -32,6 +32,31 @@ var CapsuleConfigSpecChangedPredicate = predicate.Funcs{
 	GenericFunc: func(e event.GenericEvent) bool { return false },
 }
 
+var UpdatedMetadataPredicate = predicate.Funcs{
+	CreateFunc: func(e event.CreateEvent) bool { return true },
+	DeleteFunc: func(e event.DeleteEvent) bool { return true },
+
+	UpdateFunc: func(e event.UpdateEvent) bool {
+		return !labelsEqual(e.ObjectOld.GetLabels(), e.ObjectNew.GetLabels())
+	},
+
+	GenericFunc: func(e event.GenericEvent) bool { return false },
+}
+
+func labelsEqual(a, b map[string]string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+
+	for k, v := range a {
+		if bv, ok := b[k]; !ok || bv != v {
+			return false
+		}
+	}
+
+	return true
+}
+
 func NamesMatchingPredicate(names ...string) builder.Predicates {
 	return builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
 		for _, name := range names {
diff --git a/internal/webhook/gateway/errors.go b/internal/webhook/gateway/errors.go
index 12289a9..b91224d 100644
--- a/internal/webhook/gateway/errors.go
+++ b/internal/webhook/gateway/errors.go
@@ -12,10 +12,10 @@ import (
 
 type gatewayClassForbiddenError struct {
 	gatewayClassName string
-	spec             api.SelectionListWithDefaultSpec
+	spec             api.DefaultAllowedListSpec
 }
 
-func NewGatewayClassForbidden(class string, spec api.SelectionListWithDefaultSpec) error {
+func NewGatewayClassForbidden(class string, spec api.DefaultAllowedListSpec) error {
 	return &gatewayClassForbiddenError{
 		gatewayClassName: class,
 		spec:             spec,
@@ -25,19 +25,19 @@ func NewGatewayClassForbidden(class string, spec api.SelectionListWithDefaultSpe
 func (i gatewayClassForbiddenError) Error() string {
 	err := fmt.Sprintf("Gateway Class %s is forbidden for the current Tenant: ", i.gatewayClassName)
 
-	return utils.SelectionListWithDefaultErrorMessage(i.spec, err)
+	return utils.DefaultAllowedValuesErrorMessage(i.spec, err)
 }
 
 type gatewayClassUndefinedError struct {
-	spec api.SelectionListWithDefaultSpec
+	spec api.DefaultAllowedListSpec
 }
 
-func NewGatewayClassUndefined(spec api.SelectionListWithDefaultSpec) error {
+func NewGatewayClassUndefined(spec api.DefaultAllowedListSpec) error {
 	return &gatewayClassUndefinedError{
 		spec: spec,
 	}
 }
 
 func (i gatewayClassUndefinedError) Error() string {
-	return utils.SelectionListWithDefaultErrorMessage(i.spec, "No gateway Class is forbidden for the current Tenant. Specify a gateway Class which is allowed within the Tenant: ")
+	return utils.DefaultAllowedValuesErrorMessage(i.spec, "No gateway Class is forbidden for the current Tenant. Specify a gateway Class which is allowed within the Tenant: ")
 }
diff --git a/internal/webhook/gateway/validate_class.go b/internal/webhook/gateway/validate_class.go
index f347766..f20fd11 100644
--- a/internal/webhook/gateway/validate_class.go
+++ b/internal/webhook/gateway/validate_class.go
@@ -103,10 +103,10 @@ func (r *class) validate(ctx context.Context, client client.Client, req admissio
 	switch {
 	case allowed.MatchDefault(gatewayClass.Name):
 		return nil
-	case selector:
+	case allowed.Match(gatewayClass.Name) || selector:
 		return nil
 	default:
-		recorder.Eventf(tnt, corev1.EventTypeWarning, "ForbiddenGatewaClass", "Gateway %s/%s GatewayClass %s is forbidden for the current Tenant", req.Namespace, req.Name, &gatewayClass)
+		recorder.Eventf(tnt, corev1.EventTypeWarning, "ForbiddenGatewayClass", "Gateway %s/%s GatewayClass %s is forbidden for the current Tenant", req.Namespace, req.Name, &gatewayClass)
 
 		response := admission.Denied(NewGatewayClassForbidden(gatewayObj.Name, *allowed).Error())
 
diff --git a/pkg/api/allowed_list.go b/pkg/api/allowed_list.go
index 09c57a3..02f3fb1 100644
--- a/pkg/api/allowed_list.go
+++ b/pkg/api/allowed_list.go
@@ -56,8 +56,10 @@ func (in *SelectorAllowedListSpec) SelectorMatch(obj client.Object) bool {
 // +kubebuilder:object:generate=true
 
 type AllowedListSpec struct {
+	// Match exact elements which are allowed as class names within this tenant
 	Exact []string `json:"allowed,omitempty"`
-	Regex string   `json:"allowedRegex,omitempty"`
+	// Match elements by regex (DEPRECATED)
+	Regex string `json:"allowedRegex,omitempty"`
 }
 
 func (in *AllowedListSpec) Match(value string) (ok bool) {
@@ -94,6 +96,7 @@ func (in *AllowedListSpec) RegexMatch(value string) (ok bool) {
 type SelectionListWithDefaultSpec struct {
 	SelectionListWithSpec `json:",inline"`
 
+	// Default class for tenant, when no class is set. This may overwrite even the global default.
 	Default string `json:"default,omitempty"`
 }
 



Test patch:
diff --git a/e2e/gateway_class_test.go b/e2e/gateway_class_test.go
index 40c864a..72b0dcd 100644
--- a/e2e/gateway_class_test.go
+++ b/e2e/gateway_class_test.go
@@ -11,16 +11,19 @@ import (
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/selection"
 	"k8s.io/apimachinery/pkg/types"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
 
 	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
 	"github.com/projectcapsule/capsule/pkg/api"
 )
 
-var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func() {
+var _ = Describe("when Tenant handles Gateway classes", Label("tenant", "classes", "gateway"), func() {
 	authorized := &gatewayv1.GatewayClass{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: "customer-class",
@@ -33,6 +36,30 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 		},
 	}
 
+	exact := &gatewayv1.GatewayClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "legacy",
+			Labels: map[string]string{
+				"env": "e2e",
+			},
+		},
+		Spec: gatewayv1.GatewayClassSpec{
+			ControllerName: "projectcapsule.dev/customer-controller",
+		},
+	}
+
+	exactU := &gatewayv1.GatewayClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "legacy-2",
+			Labels: map[string]string{
+				"env": "e2e",
+			},
+		},
+		Spec: gatewayv1.GatewayClassSpec{
+			ControllerName: "projectcapsule.dev/customer-controller",
+		},
+	}
+
 	unauthorized := &gatewayv1.GatewayClass{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: "unauthorized-class",
@@ -47,7 +74,7 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 
 	tntWithDefault := &capsulev1beta2.Tenant{
 		ObjectMeta: metav1.ObjectMeta{
-			Name: "tnt-with-default-gateway-class-and-label-selector",
+			Name: "e2e-gateway-default-and-label-selector",
 		},
 		Spec: capsulev1beta2.TenantSpec{
 			Owners: []api.OwnerSpec{
@@ -59,9 +86,12 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 				},
 			},
 			GatewayOptions: capsulev1beta2.GatewayOptions{
-				AllowedClasses: &api.SelectionListWithDefaultSpec{
+				AllowedClasses: &api.DefaultAllowedListSpec{
 					Default: "customer-class",
-					SelectionListWithSpec: api.SelectionListWithSpec{
+					SelectorAllowedListSpec: api.SelectorAllowedListSpec{
+						AllowedListSpec: api.AllowedListSpec{
+							Exact: []string{"legacy-2"},
+						},
 						LabelSelector: v1.LabelSelector{
 							MatchLabels: map[string]string{
 								"env": "production",
@@ -75,7 +105,7 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 
 	tntWithoutDefault := &capsulev1beta2.Tenant{
 		ObjectMeta: metav1.ObjectMeta{
-			Name: "tnt-with-label-selector-only",
+			Name: "e2e-gateway-label-selector-only",
 		},
 		Spec: capsulev1beta2.TenantSpec{
 			Owners: []api.OwnerSpec{
@@ -87,8 +117,11 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 				},
 			},
 			GatewayOptions: capsulev1beta2.GatewayOptions{
-				AllowedClasses: &api.SelectionListWithDefaultSpec{
-					SelectionListWithSpec: api.SelectionListWithSpec{
+				AllowedClasses: &api.DefaultAllowedListSpec{
+					SelectorAllowedListSpec: api.SelectorAllowedListSpec{
+						AllowedListSpec: api.AllowedListSpec{
+							Exact: []string{"legacy"},
+						},
 						LabelSelector: v1.LabelSelector{
 							MatchLabels: map[string]string{
 								"env": "production",
@@ -99,15 +132,32 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 			},
 		},
 	}
+
+	tntNoRestrictions := &capsulev1beta2.Tenant{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "e2e-gateway-no-restrictions",
+		},
+		Spec: capsulev1beta2.TenantSpec{
+			Owners: []api.OwnerSpec{
+				{
+					UserSpec: api.UserSpec{
+						Name: "e2e-gateway-no-restrictions",
+						Kind: "User",
+					},
+				},
+			},
+		},
+	}
+
 	JustBeforeEach(func() {
 		utilruntime.Must(gatewayv1.Install(scheme.Scheme))
-		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntWithoutDefault} {
+		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntWithoutDefault, tntNoRestrictions} {
 			tnt.ResourceVersion = ""
 			EventuallyCreation(func() error {
 				return k8sClient.Create(context.TODO(), tnt)
 			}).Should(Succeed())
 		}
-		for _, crd := range []*gatewayv1.GatewayClass{authorized, unauthorized} {
+		for _, crd := range []*gatewayv1.GatewayClass{authorized, unauthorized, exact, exactU} {
 			Eventually(func() error {
 				crd.ResourceVersion = ""
 				return k8sClient.Create(context.TODO(), crd)
@@ -116,16 +166,133 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 	})
 	JustAfterEach(func() {
 		utilruntime.Must(gatewayv1.Install(scheme.Scheme))
-		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntWithoutDefault} {
+		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntWithoutDefault, tntNoRestrictions} {
 			EventuallyCreation(func() error {
-				return k8sClient.Delete(context.TODO(), tnt)
+				return ignoreNotFound(k8sClient.Delete(context.TODO(), tnt))
 			}).Should(Succeed())
 		}
-		for _, crd := range []*gatewayv1.GatewayClass{authorized, unauthorized} {
-			Expect(k8sClient.Delete(context.TODO(), crd)).Should(Succeed())
-		}
+
+		Eventually(func() (err error) {
+			req, _ := labels.NewRequirement("env", selection.Exists, nil)
+
+			return k8sClient.DeleteAllOf(context.TODO(), &gatewayv1.GatewayClass{}, &client.DeleteAllOfOptions{
+				ListOptions: client.ListOptions{
+					LabelSelector: labels.NewSelector().Add(*req),
+				},
+			})
+		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
 	})
+	It("should allow all classes", func() {
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exact.GetName(), exactU.GetName(), authorized.GetName(), unauthorized.GetName()))
+		})
+
+		ns := NewNamespace("")
+		NamespaceCreation(ns, tntNoRestrictions.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+		TenantNamespaceList(tntNoRestrictions, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
+
+		By("providing any storageclass", func() {
+			for _, class := range []*gatewayv1.GatewayClass{authorized, unauthorized, exact, exactU} {
+				c := class.GetName()
+				Eventually(func() (err error) {
+					g := &gatewayv1.Gateway{
+						ObjectMeta: metav1.ObjectMeta{
+							Name:      class.GetName() + "-gateway",
+							Namespace: ns.GetName(),
+						},
+						Spec: gatewayv1.GatewaySpec{
+							Listeners: []gatewayv1.Listener{
+								{
+									Name:     "http",
+									Protocol: gatewayv1.HTTPProtocolType,
+									Port:     80,
+								},
+							},
+							GatewayClassName: gatewayv1.ObjectName(c),
+						},
+					}
+
+					err = k8sClient.Create(context.TODO(), g)
+					return
+				}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+			}
+		})
+
+		By("providing nonexistent gatewayClassName", func() {
+			Eventually(func() (err error) {
+				g := &gatewayv1.Gateway{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "nonexistent-gateway",
+						Namespace: ns.GetName(),
+					},
+					Spec: gatewayv1.GatewaySpec{
+						Listeners: []gatewayv1.Listener{
+							{
+								Name:     "http",
+								Protocol: gatewayv1.HTTPProtocolType,
+								Port:     80,
+							},
+						},
+						GatewayClassName: gatewayv1.ObjectName("very-unauthorized-and-nonexistent-class"),
+					},
+				}
+				err = k8sClient.Create(context.TODO(), g)
+				return
+			}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+		})
+
+		By("Verify Status (Deletion)", func() {
+			for _, crd := range []*gatewayv1.GatewayClass{authorized} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exact.GetName(), exactU.GetName(), unauthorized.GetName()))
+		})
+
+	})
+
 	It("should block Gateway", func() {
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exactU.GetName(), authorized.GetName()))
+		})
+
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
@@ -175,8 +342,67 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 				return
 			}, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed())
 		})
+
+		By("Verify Status (Deletion)", func() {
+			for _, crd := range []*gatewayv1.GatewayClass{authorized} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exactU.GetName()))
+
+			for _, crd := range []*gatewayv1.GatewayClass{exactU} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf())
+		})
+
 	})
 	It("should allow Gateway", func() {
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exactU.GetName(), authorized.GetName()))
+		})
+
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
@@ -202,6 +428,30 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 				return
 			}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
 		})
+
+		By("providing authorized class (exact)", func() {
+			Eventually(func() (err error) {
+				g := &gatewayv1.Gateway{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "authorized-gateway-exact",
+						Namespace: ns.GetName(),
+					},
+					Spec: gatewayv1.GatewaySpec{
+						Listeners: []gatewayv1.Listener{
+							{
+								Name:     "http",
+								Protocol: gatewayv1.HTTPProtocolType,
+								Port:     80,
+							},
+						},
+						GatewayClassName: gatewayv1.ObjectName("legacy-2"),
+					},
+				}
+				err = k8sClient.Create(context.TODO(), g)
+				return
+			}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+		})
+
 		By("providing no gatewayClassName", func() {
 			g := &gatewayv1.Gateway{
 				ObjectMeta: metav1.ObjectMeta{
@@ -222,10 +472,29 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 			gw := &gatewayv1.Gateway{}
 			Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: g.GetName(), Namespace: g.Namespace}, gw)).Should(Succeed())
 			Expect(gw.Spec.GatewayClassName).Should(Equal(gatewayv1.ObjectName("customer-class")))
+
 			return
 		})
 	})
 	It("should fail on invalid configuration", func() {
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithoutDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exact.GetName(), authorized.GetName()))
+		})
+
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntWithoutDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		TenantNamespaceList(tntWithoutDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
@@ -250,5 +519,45 @@ var _ = Describe("when Tenant handles Gateway classes", Label("gateway"), func()
 				return
 			}, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed())
 		})
+
+		By("Verify Status (Deletion)", func() {
+			for _, crd := range []*gatewayv1.GatewayClass{authorized} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithoutDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exact.GetName()))
+
+			for _, crd := range []*gatewayv1.GatewayClass{exact} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithoutDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.GatewayClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf())
+		})
 	})
 })
diff --git a/e2e/pod_priority_class_test.go b/e2e/pod_priority_class_test.go
index cea121d..bd9e22f 100644
--- a/e2e/pod_priority_class_test.go
+++ b/e2e/pod_priority_class_test.go
@@ -15,13 +15,14 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/selection"
+	"k8s.io/apimachinery/pkg/types"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
 	"github.com/projectcapsule/capsule/pkg/api"
 )
 
-var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
+var _ = Describe("enforcing a Priority Class", Label("pod", "classes"), func() {
 	tntWithDefaults := &capsulev1beta2.Tenant{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: "priority-class-defaults",
@@ -64,8 +65,8 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 			PriorityClasses: &api.DefaultAllowedListSpec{
 				SelectorAllowedListSpec: api.SelectorAllowedListSpec{
 					AllowedListSpec: api.AllowedListSpec{
-						Exact: []string{"gold"},
-						Regex: "pc\\-\\w+",
+						Exact: []string{"customer-gold"},
+						Regex: "customer\\-\\w+",
 					},
 					LabelSelector: metav1.LabelSelector{
 						MatchLabels: map[string]string{
@@ -77,6 +78,22 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 		},
 	}
 
+	tntNoRestrictions := &capsulev1beta2.Tenant{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "e2e-priority-class-no-restrictions",
+		},
+		Spec: capsulev1beta2.TenantSpec{
+			Owners: []api.OwnerSpec{
+				{
+					UserSpec: api.UserSpec{
+						Name: "e2e-priority-class-no-restrictions",
+						Kind: "User",
+					},
+				},
+			},
+		},
+	}
+
 	pcTenantPreemption := corev1.PreemptionPolicy("PreemptLowerPriority")
 	tenantDefault := schedulingv1.PriorityClass{
 		ObjectMeta: metav1.ObjectMeta{
@@ -115,18 +132,58 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 		GlobalDefault: true,
 	}
 
+	customerBronze := &schedulingv1.PriorityClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "customer-bronze",
+			Labels: map[string]string{
+				"env": "customer",
+			},
+		},
+		Description: "fake PriorityClass for e2e",
+		Value:       100000,
+	}
+
+	customerSilver := &schedulingv1.PriorityClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "customer-silver",
+			Labels: map[string]string{
+				"env": "e2e",
+			},
+		},
+		Description: "fake PriorityClass for e2e",
+		Value:       100000,
+	}
+
+	customerGold := &schedulingv1.PriorityClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "customer-gold",
+			Labels: map[string]string{
+				"env": "e2e",
+			},
+		},
+		Description: "fake PriorityClass for e2e",
+		Value:       100000,
+	}
+
 	JustBeforeEach(func() {
-		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefaults, tntNoDefaults} {
+		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefaults, tntNoDefaults, tntNoRestrictions} {
 			EventuallyCreation(func() error {
 				tnt.ResourceVersion = ""
 
 				return k8sClient.Create(context.TODO(), tnt)
 			}).Should(Succeed())
 		}
+
+		for _, crd := range []*schedulingv1.PriorityClass{customerBronze, customerSilver, customerGold} {
+			Eventually(func() error {
+				crd.ResourceVersion = ""
+				return k8sClient.Create(context.TODO(), crd)
+			}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+		}
 	})
 
 	JustAfterEach(func() {
-		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefaults, tntNoDefaults} {
+		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefaults, tntNoDefaults, tntNoRestrictions} {
 			Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
 		}
 
@@ -141,6 +198,74 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
 	})
 
+	It("should allow all classes", func() {
+		all := []string{"system-cluster-critical", "system-node-critical", customerBronze.GetName(), customerSilver.GetName(), customerGold.GetName()}
+
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(all))
+		})
+
+		ns := NewNamespace("")
+		NamespaceCreation(ns, tntNoRestrictions.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+		TenantNamespaceList(tntNoRestrictions, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
+
+		By("providing any priorityclass", func() {
+			for _, class := range all {
+				Eventually(func() (err error) {
+
+					g := &corev1.Pod{
+						ObjectMeta: metav1.ObjectMeta{
+							Name:      class + "-container",
+							Namespace: ns.GetName(),
+						},
+						Spec: corev1.PodSpec{
+							Containers: []corev1.Container{
+								{
+									Name:  "container",
+									Image: "quay.io/google-containers/pause-amd64:3.0",
+								},
+							},
+							PriorityClassName: class,
+						},
+					}
+
+					return k8sClient.Create(context.TODO(), g)
+				}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+			}
+		})
+
+		By("Verify Status (Deletion)", func() {
+			for _, crd := range []*schedulingv1.PriorityClass{customerGold} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf("system-cluster-critical", "system-node-critical", customerBronze.GetName(), customerSilver.GetName()))
+		})
+	})
+
 	It("should block non allowed Priority Class", func() {
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntNoDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
@@ -208,21 +333,25 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 				return err
 			}).ShouldNot(Succeed())
 		}
+
+		By("verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(customerGold.GetName(), customerBronze.GetName()))
+		})
 	})
 
 	It("should allow exact match", func() {
-		pc := &schedulingv1.PriorityClass{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "gold",
-				Labels: map[string]string{
-					"env": "e2e",
-				},
-			},
-			Description: "fake PriorityClass for e2e",
-			Value:       10000,
-		}
-		Expect(k8sClient.Create(context.TODO(), pc)).Should(Succeed())
-
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntNoDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 
@@ -237,7 +366,7 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 						Image: "quay.io/google-containers/pause-amd64:3.0",
 					},
 				},
-				PriorityClassName: "gold",
+				PriorityClassName: "customer-gold",
 			},
 		}
 
@@ -252,24 +381,11 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntNoDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 
-		for i, pc := range []string{"pc-bronze", "pc-silver", "pc-gold"} {
-			class := &schedulingv1.PriorityClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: pc,
-					Labels: map[string]string{
-						"env": "e2e",
-					},
-				},
-				Description: "fake PriorityClass for e2e",
-				Value:       int32(10000 * (i + 2)),
-			}
-
-			Expect(k8sClient.Create(context.TODO(), class)).Should(Succeed())
-
+		for _, class := range []string{customerBronze.GetName(), customerSilver.GetName(), customerGold.GetName()} {
 			EventuallyCreation(func() error {
 				pod := &corev1.Pod{
 					ObjectMeta: metav1.ObjectMeta{
-						Name:      pc,
+						Name:      class,
 						Namespace: ns.GetName(),
 					},
 					Spec: corev1.PodSpec{
@@ -279,7 +395,7 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 								Image: "quay.io/google-containers/pause-amd64:3.0",
 							},
 						},
-						PriorityClassName: class.GetName(),
+						PriorityClassName: class,
 					},
 				}
 
@@ -289,23 +405,71 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 	})
 
 	It("should allow selector match", func() {
-		for i, pc := range []string{"customer-bronze", "customer-silver", "customer-gold"} {
-			priorityName := strings.Join([]string{pc, "-", strconv.Itoa(i)}, "")
-			class := &schedulingv1.PriorityClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: priorityName,
-					Labels: map[string]string{
-						"env": "customer",
+		By("create Custom Classes", func() {
+			for i, pc := range []string{"internal-bronze-new", "internal-silver-new", "internal-gold-new"} {
+				priorityName := strings.Join([]string{pc, "-", strconv.Itoa(i)}, "")
+				class := &schedulingv1.PriorityClass{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: priorityName,
+						Labels: map[string]string{
+							"env": "customer",
+						},
 					},
-				},
-				Description: "fake PriorityClass for e2e",
-				Value:       int32(10000 * (i + 2)),
+					Description: "fake PriorityClass for e2e",
+					Value:       int32(10000 * (i + 2)),
+				}
+				Expect(k8sClient.Create(context.TODO(), class)).Should(Succeed())
+
+				pod := &corev1.Pod{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: pc,
+					},
+					Spec: corev1.PodSpec{
+						Containers: []corev1.Container{
+							{
+								Name:  "container",
+								Image: "quay.io/google-containers/pause-amd64:3.0",
+							},
+						},
+						PriorityClassName: class.GetName(),
+					},
+				}
+
+				ns := NewNamespace("")
+				cs := ownerClient(tntNoDefaults.Spec.Owners[0].UserSpec)
+
+				NamespaceCreation(ns, tntNoDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+				TenantNamespaceList(tntNoDefaults, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
+
+				EventuallyCreation(func() error {
+					_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
+					return err
+				}).Should(Succeed())
 			}
-			Expect(k8sClient.Create(context.TODO(), class)).Should(Succeed())
+		})
+
+		By("verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
 
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf("internal-bronze-new-0", "internal-silver-new-1", "internal-gold-new-2", customerGold.GetName(), customerBronze.GetName()))
+		})
+	})
+
+	It("fail if default tenant PriorityClass is absent", func() {
+		By("rejecting default", func() {
 			pod := &corev1.Pod{
 				ObjectMeta: metav1.ObjectMeta{
-					Name: pc,
+					Name: "tenant-default",
 				},
 				Spec: corev1.PodSpec{
 					Containers: []corev1.Container{
@@ -314,84 +478,88 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 							Image: "quay.io/google-containers/pause-amd64:3.0",
 						},
 					},
-					PriorityClassName: class.GetName(),
 				},
 			}
 
 			ns := NewNamespace("")
-			cs := ownerClient(tntNoDefaults.Spec.Owners[0].UserSpec)
+			cs := ownerClient(tntWithDefaults.Spec.Owners[0].UserSpec)
 
-			NamespaceCreation(ns, tntNoDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
-			TenantNamespaceList(tntNoDefaults, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
+			NamespaceCreation(ns, tntWithDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+			TenantNamespaceList(tntWithDefaults, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
 
 			EventuallyCreation(func() error {
 				_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
-				return err
-			}).Should(Succeed())
-		}
-	})
 
-	It("fail if default tenant PriorityClass is absent", func() {
-		pod := &corev1.Pod{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "tenant-default",
-			},
-			Spec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "container",
-						Image: "quay.io/google-containers/pause-amd64:3.0",
-					},
-				},
-			},
-		}
-
-		ns := NewNamespace("")
-		cs := ownerClient(tntWithDefaults.Spec.Owners[0].UserSpec)
-
-		NamespaceCreation(ns, tntWithDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
-		TenantNamespaceList(tntWithDefaults, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
-
-		EventuallyCreation(func() error {
-			_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
-
-			return err
-		}).ShouldNot(Succeed())
+				return err
+			}).ShouldNot(Succeed())
+		})
+
+		By("verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
 
-		Expect(k8sClient.Delete(context.TODO(), ns)).Should(Succeed())
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(customerBronze.GetName()))
+		})
 	})
 
 	It("should mutate to default tenant PriorityClass", func() {
-		class := tenantDefault.DeepCopy()
-		class.SetResourceVersion("")
-		Expect(k8sClient.Create(context.TODO(), class)).Should(Succeed())
+		By("creating default tenant class", func() {
+			class := tenantDefault.DeepCopy()
+			class.SetResourceVersion("")
+			Expect(k8sClient.Create(context.TODO(), class)).Should(Succeed())
 
-		ns := NewNamespace("")
-		NamespaceCreation(ns, tntWithDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
-		TenantNamespaceList(tntWithDefaults, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
+			ns := NewNamespace("")
+			NamespaceCreation(ns, tntWithDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+			TenantNamespaceList(tntWithDefaults, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
 
-		pod := corev1.Pod{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "tenant-default-present",
-				Namespace: ns.GetName(),
-			},
-			Spec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "container",
-						Image: "quay.io/google-containers/pause-amd64:3.0",
+			pod := corev1.Pod{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "tenant-default-present",
+					Namespace: ns.GetName(),
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "container",
+							Image: "quay.io/google-containers/pause-amd64:3.0",
+						},
 					},
 				},
-			},
-		}
+			}
 
-		EventuallyCreation(func() error {
-			return k8sClient.Create(context.Background(), &pod)
-		}).Should(Succeed())
-		// Check if correct mutated
-		Expect(pod.Spec.PriorityClassName).To(Equal(class.GetName()))
-		Expect(pod.Spec.Priority).To(Equal(&class.Value))
-		Expect(pod.Spec.PreemptionPolicy).To(Equal(class.PreemptionPolicy))
+			EventuallyCreation(func() error {
+				return k8sClient.Create(context.Background(), &pod)
+			}).Should(Succeed())
+			// Check if correct mutated
+			Expect(pod.Spec.PriorityClassName).To(Equal(class.GetName()))
+			Expect(pod.Spec.Priority).To(Equal(&class.Value))
+			Expect(pod.Spec.PreemptionPolicy).To(Equal(class.PreemptionPolicy))
+		})
+
+		By("verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(tenantDefault.GetName(), customerBronze.GetName()))
+		})
 	})
 
 	It("should mutate to default tenant PriorityClass although the cluster global one is not allowed", func() {
@@ -430,6 +598,22 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 		Expect(pod.Spec.PriorityClassName).To(Equal(class.GetName()))
 		Expect(pod.Spec.Priority).To(Equal(&class.Value))
 		Expect(pod.Spec.PreemptionPolicy).To(Equal(class.PreemptionPolicy))
+
+		By("verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(tenantDefault.GetName(), customerBronze.GetName()))
+		})
 	})
 
 	It("should mutate to default tenant PriorityClass although the cluster global one is allowed", func() {
@@ -466,5 +650,21 @@ var _ = Describe("enforcing a Priority Class", Label("pod"), func() {
 		// Check if correctly applied
 		Expect(pod.Spec.PriorityClassName).To(Equal(class.GetName()))
 		Expect(*pod.Spec.Priority).To(Equal(class.Value))
+
+		By("verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.PriorityClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(global.GetName(), tenantDefault.GetName(), customerBronze.GetName()))
+		})
 	})
 })
diff --git a/e2e/pod_runtime_class_test.go b/e2e/pod_runtime_class_test.go
index 4b93a2d..cc751be 100644
--- a/e2e/pod_runtime_class_test.go
+++ b/e2e/pod_runtime_class_test.go
@@ -13,16 +13,20 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	nodev1 "k8s.io/api/node/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/selection"
+	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/projectcapsule/capsule/pkg/api"
 
 	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
 )
 
-var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
-	tnt := &capsulev1beta2.Tenant{
+var _ = Describe("enforcing a Runtime Class", Label("pod", "classes", "current"), func() {
+	tntWithDefault := &capsulev1beta2.Tenant{
 		ObjectMeta: metav1.ObjectMeta{
-			Name: "runtime-class",
+			Name: "e2e-runtime-selection",
 		},
 		Spec: capsulev1beta2.TenantSpec{
 			Owners: api.OwnerListSpec{
@@ -50,70 +54,234 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 		},
 	}
 
+	tntNoRestrictions := &capsulev1beta2.Tenant{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "e2e-runtime-no-restrictions",
+		},
+		Spec: capsulev1beta2.TenantSpec{
+			Owners: []api.OwnerSpec{
+				{
+					UserSpec: api.UserSpec{
+						Name: "e2e-gateway-no-restrictions",
+						Kind: "User",
+					},
+				},
+			},
+		},
+	}
+
+	defaultRuntime := &nodev1.RuntimeClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "default-runtime",
+			Labels: map[string]string{
+				"name": "default-runtime",
+				"env":  "customers",
+			},
+		},
+		Handler: "custom-handler",
+	}
+
+	legacy := &nodev1.RuntimeClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "legacy",
+			Labels: map[string]string{
+				"env": "e2e",
+			},
+		},
+		Handler: "custom-handler",
+	}
+
+	disallowed := &nodev1.RuntimeClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "disallowed",
+			Labels: map[string]string{
+				"env": "e2e",
+			},
+		},
+		Handler: "custom-handler",
+	}
+
+	customerContainerd := &nodev1.RuntimeClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "customer-containerd",
+			Labels: map[string]string{
+				"name": "customer-containerd",
+				"env":  "customers",
+			},
+		},
+		Handler: "custom-handler",
+	}
+
+	customerKubevirt := &nodev1.RuntimeClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "customer-virt",
+			Labels: map[string]string{
+				"name": "customer-virt",
+				"env":  "customers",
+			},
+		},
+		Handler: "custom-handler",
+	}
+
+	customerUni := &nodev1.RuntimeClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "customer-runu",
+			Labels: map[string]string{
+				"name": "customer-runu",
+				"env":  "e2e",
+			},
+		},
+		Handler: "custom-handler",
+	}
+
 	JustBeforeEach(func() {
-		EventuallyCreation(func() error {
+		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntNoRestrictions} {
 			tnt.ResourceVersion = ""
-			return k8sClient.Create(context.TODO(), tnt)
-		}).Should(Succeed())
+			EventuallyCreation(func() error {
+				return k8sClient.Create(context.TODO(), tnt)
+			}).Should(Succeed())
+		}
+		for _, crd := range []*nodev1.RuntimeClass{legacy, disallowed, customerUni, customerKubevirt, customerContainerd} {
+			Eventually(func() error {
+				crd.ResourceVersion = ""
+				return k8sClient.Create(context.TODO(), crd)
+			}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+		}
 	})
 	JustAfterEach(func() {
-		Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
-	})
 
-	It("should block non allowed Runtime Class", func() {
-		runtime := &nodev1.RuntimeClass{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "disallowed",
-			},
-			Handler: "custom-handler",
+		for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntNoRestrictions} {
+			EventuallyCreation(func() error {
+				return ignoreNotFound(k8sClient.Delete(context.TODO(), tnt))
+			}).Should(Succeed())
 		}
-		Expect(k8sClient.Create(context.TODO(), runtime)).Should(Succeed())
 
-		defer func() {
-			Expect(k8sClient.Delete(context.TODO(), runtime)).Should(Succeed())
-		}()
+		Eventually(func() (err error) {
+			req, _ := labels.NewRequirement("env", selection.Exists, nil)
 
-		ns := NewNamespace("rt-disallow")
-		NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
-		runtimeName := "disallowed"
-		pod := &corev1.Pod{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "container",
-			},
-			Spec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "container",
-						Image: "quay.io/google-containers/pause-amd64:3.0",
-					},
+			return k8sClient.DeleteAllOf(context.TODO(), &nodev1.RuntimeClass{}, &client.DeleteAllOfOptions{
+				ListOptions: client.ListOptions{
+					LabelSelector: labels.NewSelector().Add(*req),
 				},
-				RuntimeClassName: &runtimeName,
-			},
-		}
+			})
+		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+	})
 
-		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
-		EventuallyCreation(func() error {
-			_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
-			return err
-		}).ShouldNot(Succeed())
+	It("should allow all classes", func() {
+		all := []string{customerUni.GetName(), customerKubevirt.GetName(), customerContainerd.GetName(), legacy.GetName(), disallowed.GetName()}
+
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.RuntimeClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(all))
+		})
+
+		ns := NewNamespace("")
+		NamespaceCreation(ns, tntNoRestrictions.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+		TenantNamespaceList(tntNoRestrictions, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
+
+		By("providing any runtimeclass", func() {
+			for _, class := range all {
+				Eventually(func() (err error) {
+
+					g := &corev1.Pod{
+						ObjectMeta: metav1.ObjectMeta{
+							Name:      class + "-container",
+							Namespace: ns.GetName(),
+						},
+						Spec: corev1.PodSpec{
+							Containers: []corev1.Container{
+								{
+									Name:  "container",
+									Image: "quay.io/google-containers/pause-amd64:3.0",
+								},
+							},
+							RuntimeClassName: &class,
+						},
+					}
+
+					return k8sClient.Create(context.TODO(), g)
+				}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+			}
+		})
+
+		By("Verify Status (Deletion)", func() {
+			for _, crd := range []*nodev1.RuntimeClass{customerKubevirt} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.RuntimeClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(customerUni.GetName(), customerContainerd.GetName(), legacy.GetName(), disallowed.GetName()))
+		})
 	})
 
-	It("should allow exact match", func() {
-		runtime := &nodev1.RuntimeClass{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "legacy",
-			},
-			Handler: "custom-handler",
-		}
-		Expect(k8sClient.Create(context.TODO(), runtime)).Should(Succeed())
+	It("should block non allowed Runtime Class", func() {
+		By("blocked disallowed runtime", func() {
+			ns := NewNamespace("rt-disallow")
+			NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 
-		defer func() {
-			Expect(k8sClient.Delete(context.TODO(), runtime)).Should(Succeed())
-		}()
+			pod := &corev1.Pod{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "container",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "container",
+							Image: "quay.io/google-containers/pause-amd64:3.0",
+						},
+					},
+					RuntimeClassName: &disallowed.Name,
+				},
+			}
 
+			cs := ownerClient(tntWithDefault.Spec.Owners[0].UserSpec)
+			EventuallyCreation(func() error {
+				_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
+				return err
+			}).ShouldNot(Succeed())
+		})
+
+		By("verify status", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.RuntimeClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(customerContainerd.GetName(), customerKubevirt.GetName(), legacy.GetName()))
+		})
+	})
+
+	It("should allow exact match", func() {
 		ns := NewNamespace("rt-exact-match")
-		NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
-		runtimeName := "legacy"
+		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		pod := &corev1.Pod{
 			ObjectMeta: metav1.ObjectMeta{
 				Name: "container",
@@ -125,11 +293,11 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 						Image: "quay.io/google-containers/pause-amd64:3.0",
 					},
 				},
-				RuntimeClassName: &runtimeName,
+				RuntimeClassName: &legacy.Name,
 			},
 		}
 
-		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
+		cs := ownerClient(tntWithDefault.Spec.Owners[0].UserSpec)
 		EventuallyCreation(func() error {
 			_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
 			return err
@@ -139,7 +307,7 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 	It("should allow regex match", func() {
 		ns := NewNamespace("rc-regex-match")
 
-		NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 
 		for i, rt := range []string{"hardened-crio", "hardened-containerd", "hardened-dockerd"} {
 			runtimeName := strings.Join([]string{rt, "-", strconv.Itoa(i)}, "")
@@ -167,7 +335,7 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 				},
 			}
 
-			cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
+			cs := ownerClient(tntWithDefault.Spec.Owners[0].UserSpec)
 
 			EventuallyCreation(func() error {
 				_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
@@ -181,7 +349,7 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 	It("should allow selector match", func() {
 		ns := NewNamespace("rc-selector-match")
 
-		NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 
 		for i, rt := range []string{"customer-containerd", "customer-crio", "customer-dockerd"} {
 			runtimeName := strings.Join([]string{rt, "-", strconv.Itoa(i)}, "")
@@ -213,32 +381,37 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 				},
 			}
 
-			cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
+			cs := ownerClient(tntWithDefault.Spec.Owners[0].UserSpec)
 
 			EventuallyCreation(func() error {
 				_, err := cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), pod, metav1.CreateOptions{})
 				return err
 			}).Should(Succeed())
-
-			Expect(k8sClient.Delete(context.TODO(), runtime)).Should(Succeed())
 		}
+
+		By("verify status", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.RuntimeClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf("customer-containerd-0", "customer-crio-1", "customer-dockerd-2", customerContainerd.GetName(), customerKubevirt.GetName(), legacy.GetName()))
+		})
 	})
 
 	It("should auto assign the default", func() {
 		ns := NewNamespace("rc-default")
 
-		NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 
-		runtime := &nodev1.RuntimeClass{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "default-runtime",
-			},
-			Handler: "custom-handler",
-		}
-		Expect(k8sClient.Create(context.TODO(), runtime)).Should(Succeed())
-		defer func() {
-			Expect(k8sClient.Delete(context.TODO(), runtime)).Should(Succeed())
-		}()
+		Expect(k8sClient.Create(context.TODO(), defaultRuntime)).Should(Succeed())
 
 		pod := corev1.Pod{
 			ObjectMeta: metav1.ObjectMeta{
@@ -255,7 +428,7 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 			},
 		}
 
-		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)
+		cs := ownerClient(tntWithDefault.Spec.Owners[0].UserSpec)
 
 		var createdPod *corev1.Pod
 
@@ -266,7 +439,23 @@ var _ = Describe("enforcing a Runtime Class", Label("pod"), func() {
 		}).Should(Succeed())
 
 		Expect(createdPod.Spec.RuntimeClassName).NotTo(BeNil())
-		_, err := Equal(createdPod.Spec.RuntimeClassName).Match(tnt.Spec.RuntimeClasses.Default)
+		_, err := Equal(createdPod.Spec.RuntimeClassName).Match(tntWithDefault.Spec.RuntimeClasses.Default)
 		Expect(err).NotTo(HaveOccurred())
+
+		By("verify status", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.RuntimeClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(defaultRuntime.GetName(), customerContainerd.GetName(), customerKubevirt.GetName(), legacy.GetName()))
+		})
 	})
 })
diff --git a/e2e/storage_class_test.go b/e2e/storage_class_test.go
index 798a4a0..0ed6415 100644
--- a/e2e/storage_class_test.go
+++ b/e2e/storage_class_test.go
@@ -19,6 +19,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/selection"
+	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/utils/ptr"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -26,7 +27,7 @@ import (
 	"github.com/projectcapsule/capsule/pkg/api"
 )
 
-var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage"), func() {
+var _ = Describe("when Tenant handles Storage classes", Label("tenant", "classes", "storage"), func() {
 	tntNoDefaults := &capsulev1beta2.Tenant{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: "storage-class-selector",
@@ -82,6 +83,33 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 		},
 	}
 
+	tntNoRestrictions := &capsulev1beta2.Tenant{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "e2e-storage-no-restrictions",
+		},
+		Spec: capsulev1beta2.TenantSpec{
+			Owners: api.OwnerListSpec{
+				{
+					UserSpec: api.UserSpec{
+						Name: "no-restrictions",
+						Kind: "User",
+					},
+				},
+			},
+		},
+	}
+
+	exact := storagev1.StorageClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "cephfs",
+			Labels: map[string]string{
+				"name": "cephfs",
+				"env":  "e2e",
+			},
+		},
+		Provisioner: "kubernetes.io/no-provisioner",
+	}
+
 	tenantDefault := storagev1.StorageClass{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: "tenant-default",
@@ -113,16 +141,23 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 	}
 
 	JustBeforeEach(func() {
-		for _, tnt := range []*capsulev1beta2.Tenant{tntNoDefaults, tntWithDefault} {
+		for _, tnt := range []*capsulev1beta2.Tenant{tntNoDefaults, tntWithDefault, tntNoRestrictions} {
 			EventuallyCreation(func() error {
 				tnt.ResourceVersion = ""
 
 				return k8sClient.Create(context.TODO(), tnt)
 			}).Should(Succeed())
 		}
+
+		for _, class := range []storagev1.StorageClass{exact, tenantDefault, globalDefault, disallowedGlobalDefault} {
+			Eventually(func() error {
+				class.ResourceVersion = ""
+				return k8sClient.Create(context.TODO(), &class)
+			}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+		}
 	})
 	JustAfterEach(func() {
-		for _, tnt := range []*capsulev1beta2.Tenant{tntNoDefaults, tntWithDefault} {
+		for _, tnt := range []*capsulev1beta2.Tenant{tntNoDefaults, tntWithDefault, tntNoRestrictions} {
 			Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
 		}
 
@@ -137,8 +172,90 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
 	})
 
+	It("should allow all classes", func() {
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.StorageClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf("standard", exact.GetName(), tenantDefault.GetName(), globalDefault.GetName(), disallowedGlobalDefault.GetName()))
+		})
+
+		ns := NewNamespace("")
+		NamespaceCreation(ns, tntNoRestrictions.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
+		TenantNamespaceList(tntNoRestrictions, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
+
+		By("providing any storageclass", func() {
+			for _, class := range []storagev1.StorageClass{exact, tenantDefault, globalDefault, disallowedGlobalDefault} {
+				c := class.GetName()
+				Eventually(func() (err error) {
+					cs := ownerClient(tntNoRestrictions.Spec.Owners[0].UserSpec)
+					p := &corev1.PersistentVolumeClaim{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: class.GetName() + "-pvc",
+						},
+						Spec: corev1.PersistentVolumeClaimSpec{
+							StorageClassName: &c,
+							AccessModes:      []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+							Resources: corev1.VolumeResourceRequirements{
+								Requests: map[corev1.ResourceName]resource.Quantity{
+									corev1.ResourceStorage: resource.MustParse("1Gi"),
+								},
+							},
+						},
+					}
+					_, err = cs.CoreV1().PersistentVolumeClaims(ns.GetName()).Create(context.TODO(), p, metav1.CreateOptions{})
+					return
+				}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
+			}
+		})
+
+		By("Verify Status (Deletion)", func() {
+			for _, class := range []storagev1.StorageClass{exact, tenantDefault} {
+				Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), &class))).To(Succeed())
+			}
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoRestrictions.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.StorageClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf("standard", globalDefault.GetName(), disallowedGlobalDefault.GetName()))
+		})
+	})
+
 	It("should fail", func() {
-		k8sClient.Create(context.TODO(), tntNoDefaults)
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.StorageClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exact.GetName(), globalDefault.GetName()))
+		})
 
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntNoDefaults.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
@@ -225,6 +342,24 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 	})
 
 	It("should allow", func() {
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.StorageClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(exact.GetName(), globalDefault.GetName()))
+		})
+
 		ns := NewNamespace("")
 		cs := ownerClient(tntNoDefaults.Spec.Owners[0].UserSpec)
 
@@ -309,37 +444,70 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 				}).Should(Succeed())
 			}
 		})
+
+		By("Verify Status (Update)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+
+				// return the error so Eventually will retry until it’s nil
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntNoDefaults.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.StorageClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf("customer-hdd-0", "customer-ssd-1", exact.GetName(), globalDefault.GetName()))
+		})
 	})
 
 	It("should mutate to default tenant StorageClass (class does not exists)", func() {
+		By("Verify Status (Creation)", func() {
+			Eventually(func() ([]string, error) {
+				t := &capsulev1beta2.Tenant{}
+				if err := k8sClient.Get(
+					context.TODO(),
+					types.NamespacedName{Name: tntWithDefault.GetName()},
+					t,
+				); err != nil {
+					return nil, err
+				}
+
+				return t.Status.Classes.StorageClasses, nil
+			}, defaultTimeoutInterval, defaultPollInterval).
+				Should(ConsistOf(tenantDefault.GetName()))
+		})
+
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
 
-		p := &corev1.PersistentVolumeClaim{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "pvc-default-sc",
-				Namespace: ns.GetName(),
-			},
-			Spec: corev1.PersistentVolumeClaimSpec{
-				AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
-				Resources: corev1.VolumeResourceRequirements{
-					Requests: map[corev1.ResourceName]resource.Quantity{
-						corev1.ResourceStorage: resource.MustParse("3Gi"),
+		By("Patch Tenant Default", func() {
+			p := &corev1.PersistentVolumeClaim{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "pvc-default-sc",
+					Namespace: ns.GetName(),
+				},
+				Spec: corev1.PersistentVolumeClaimSpec{
+					AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+					Resources: corev1.VolumeResourceRequirements{
+						Requests: map[corev1.ResourceName]resource.Quantity{
+							corev1.ResourceStorage: resource.MustParse("3Gi"),
+						},
 					},
 				},
-			},
-		}
-		EventuallyCreation(func() error {
-			return k8sClient.Create(context.Background(), p)
-		}).Should(Succeed())
-		Expect(*p.Spec.StorageClassName).To(Equal("tenant-default"))
+			}
+			EventuallyCreation(func() error {
+				return k8sClient.Create(context.Background(), p)
+			}).Should(Succeed())
+			Expect(*p.Spec.StorageClassName).To(Equal("tenant-default"))
+		})
 	})
 
 	It("should mutate to default tenant StorageClass (class exists)", func() {
-		class := tenantDefault
-		Expect(k8sClient.Create(context.TODO(), &class)).Should(Succeed())
-
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
@@ -362,16 +530,10 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 		EventuallyCreation(func() error {
 			return k8sClient.Create(context.Background(), p)
 		}).Should(Succeed())
-		Expect(*p.Spec.StorageClassName).To(Equal(class.GetName()))
+		Expect(*p.Spec.StorageClassName).To(Equal(tenantDefault.GetName()))
 	})
 
 	It("should mutate to default tenant StorageClass although cluster global ons is not allowed", func() {
-		class := tenantDefault
-		global := disallowedGlobalDefault
-
-		Expect(k8sClient.Create(context.TODO(), &class)).Should(Succeed())
-		Expect(k8sClient.Create(context.TODO(), &global)).Should(Succeed())
-
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
@@ -393,16 +555,10 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 		EventuallyCreation(func() error {
 			return k8sClient.Create(context.Background(), p)
 		}).Should(Succeed())
-		Expect(*p.Spec.StorageClassName).To(Equal(class.GetName()))
+		Expect(*p.Spec.StorageClassName).To(Equal(tenantDefault.GetName()))
 	})
 
 	It("should mutate to default tenant StorageClass although cluster global ons is allowed", func() {
-		class := tenantDefault
-		global := globalDefault
-
-		Expect(k8sClient.Create(context.TODO(), &class)).Should(Succeed())
-		Expect(k8sClient.Create(context.TODO(), &global)).Should(Succeed())
-
 		ns := NewNamespace("")
 		NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
 		TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
@@ -424,6 +580,6 @@ var _ = Describe("when Tenant handles Storage classes", Label("tenant", "storage
 		EventuallyCreation(func() error {
 			return k8sClient.Create(context.Background(), p)
 		}).Should(Succeed())
-		Expect(*p.Spec.StorageClassName).To(Equal(class.GetName()))
+		Expect(*p.Spec.StorageClassName).To(Equal(tenantDefault.GetName()))
 	})
 })
diff --git a/e2e/utils_test.go b/e2e/utils_test.go
index 463e298..bf2ef65 100644
--- a/e2e/utils_test.go
+++ b/e2e/utils_test.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 	"time"
 
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/util/rand"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -35,6 +36,13 @@ const (
 	defaultConfigurationName = "default"
 )
 
+func ignoreNotFound(err error) error {
+	if apierrors.IsNotFound(err) {
+		return nil
+	}
+	return err
+}
+
 func NewService(svc types.NamespacedName) *corev1.Service {
 	return &corev1.Service{
 		ObjectMeta: metav1.ObjectMeta{