feat(tenant): add label with tenant name for each tenant

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
This commit is contained in:
Oliver Bähler
2023-11-29 07:24:27 +01:00
committed by Dario Tranchitella
parent 3c85657d9a
commit c58b46cedf
7 changed files with 164 additions and 1 deletions
+1
View File
@@ -48,6 +48,7 @@ const (
PriorityClassesProxy ProxyServiceKind = "PriorityClasses"
RuntimeClassesProxy ProxyServiceKind = "RuntimeClasses"
PersistentVolumesProxy ProxyServiceKind = "PersistentVolumes"
TenantProxy ProxyServiceKind = "Tenant"
ListOperation ProxyOperation = "List"
UpdateOperation ProxyOperation = "Update"
+7
View File
@@ -60,6 +60,13 @@ func (r Manager) Reconcile(ctx context.Context, request ctrl.Request) (result ct
return
}
// Ensuring Metadata
if err = r.ensureMetadata(ctx, instance); err != nil {
r.Log.Error(err, "Cannot ensure metadata")
return
}
// Ensuring ResourceQuota
r.Log.Info("Ensuring limit resources count is updated")
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0
package tenant
import (
"context"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
capsuleapi "github.com/projectcapsule/capsule/pkg/api"
)
// Sets a label on the Tenant object with it's name.
func (r *Manager) ensureMetadata(ctx context.Context, tnt *capsulev1beta2.Tenant) (err error) {
// Assign Labels
if tnt.Labels == nil {
tnt.Labels = make(map[string]string)
}
tnt.Labels[capsuleapi.TenantNameLabel] = tnt.Name
return r.Client.Update(ctx, tnt)
}
+67
View File
@@ -0,0 +1,67 @@
//go:build e2e
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0
package e2e
import (
"context"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
)
func getLabels(tnt capsulev1beta2.Tenant) (map[string]string, error) {
current := &capsulev1beta2.Tenant{}
err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: tnt.GetName()}, current)
if err != nil {
return nil, err
}
return current.GetLabels(), nil
}
var _ = Describe("adding metadata to a Tenant", func() {
tnt := &capsulev1beta2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-metadata",
Labels: map[string]string{
"custom-label": "test",
},
},
Spec: capsulev1beta2.TenantSpec{
Owners: capsulev1beta2.OwnerListSpec{
{
Name: "jim",
Kind: "User",
},
},
},
}
JustBeforeEach(func() {
EventuallyCreation(func() error {
return k8sClient.Create(context.TODO(), tnt)
}).Should(Succeed())
})
JustAfterEach(func() {
Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed())
})
It("Should ensure label metadata", func() {
By("Default labels", func() {
currentlabels, _ := getLabels(*tnt)
Expect(currentlabels["kubernetes.io/metadata.name"]).To(Equal("tenant-metadata"))
Expect(currentlabels["custom-label"]).To(Equal("test"))
})
By("Disallow name overwritte", func() {
tnt.Labels["kubernetes.io/metadata.name"] = "evil"
Expect(k8sClient.Update(context.TODO(), tnt)).ShouldNot(Succeed())
})
})
})
+1 -1
View File
@@ -225,7 +225,7 @@ func main() {
route.Service(service.Handler()),
route.TenantResourceObjects(utils.InCapsuleGroups(cfg, tntresource.WriteOpsHandler())),
route.NetworkPolicy(utils.InCapsuleGroups(cfg, networkpolicy.Handler())),
route.Tenant(tenant.NameHandler(), tenant.RoleBindingRegexHandler(), tenant.IngressClassRegexHandler(), tenant.StorageClassRegexHandler(), tenant.ContainerRegistryRegexHandler(), tenant.HostnameRegexHandler(), tenant.FreezedEmitter(), tenant.ServiceAccountNameHandler(), tenant.ForbiddenAnnotationsRegexHandler(), tenant.ProtectedHandler()),
route.Tenant(tenant.NameHandler(), tenant.RoleBindingRegexHandler(), tenant.IngressClassRegexHandler(), tenant.StorageClassRegexHandler(), tenant.ContainerRegistryRegexHandler(), tenant.HostnameRegexHandler(), tenant.FreezedEmitter(), tenant.ServiceAccountNameHandler(), tenant.ForbiddenAnnotationsRegexHandler(), tenant.ProtectedHandler(), tenant.MetaHandler()),
route.OwnerReference(utils.InCapsuleGroups(cfg, ownerreference.Handler(cfg))),
route.Cordoning(tenant.CordoningHandler(cfg), tenant.ResourceCounterHandler(manager.GetClient())),
route.Node(utils.InCapsuleGroups(cfg, node.UserMetadataHandler(cfg, kubeVersion))),
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0
package api
const (
TenantNameLabel = "kubernetes.io/metadata.name"
)
+57
View File
@@ -0,0 +1,57 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0
package tenant
import (
"context"
"fmt"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
capsuleapi "github.com/projectcapsule/capsule/pkg/api"
capsulewebhook "github.com/projectcapsule/capsule/pkg/webhook"
"github.com/projectcapsule/capsule/pkg/webhook/utils"
)
type metaHandler struct{}
func MetaHandler() capsulewebhook.Handler {
return &metaHandler{}
}
func (h *metaHandler) OnCreate(_ client.Client, decoder *admission.Decoder, _ record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
return nil
}
}
func (h *metaHandler) OnDelete(client.Client, *admission.Decoder, record.EventRecorder) capsulewebhook.Func {
return func(context.Context, admission.Request) *admission.Response {
return nil
}
}
func (h *metaHandler) OnUpdate(_ client.Client, decoder *admission.Decoder, _ record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
tenant := &capsulev1beta2.Tenant{}
if err := decoder.Decode(req, tenant); err != nil {
return utils.ErroredResponse(err)
}
if tenant.Labels != nil {
if tenant.Labels[capsuleapi.TenantNameLabel] != "" {
if tenant.Labels[capsuleapi.TenantNameLabel] != tenant.Name {
response := admission.Denied(fmt.Sprintf("tenant label '%s' is immutable", capsuleapi.TenantNameLabel))
return &response
}
}
}
return nil
}
}