Skip to content

Commit

Permalink
feat(tenant): add label with tenant name for each tenant
Browse files Browse the repository at this point in the history
Signed-off-by: Oliver Bähler <[email protected]>
  • Loading branch information
oliverbaehler authored and prometherion committed Nov 29, 2023
1 parent 3c85657 commit c58b46c
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 1 deletion.
1 change: 1 addition & 0 deletions api/v1beta2/owner.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
PriorityClassesProxy ProxyServiceKind = "PriorityClasses"
RuntimeClassesProxy ProxyServiceKind = "RuntimeClasses"
PersistentVolumesProxy ProxyServiceKind = "PersistentVolumes"
TenantProxy ProxyServiceKind = "Tenant"

ListOperation ProxyOperation = "List"
UpdateOperation ProxyOperation = "Update"
Expand Down
7 changes: 7 additions & 0 deletions controllers/tenant/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
23 changes: 23 additions & 0 deletions controllers/tenant/metadata.go
Original file line number Diff line number Diff line change
@@ -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 changes: 67 additions & 0 deletions e2e/tenant_metadata.go
Original file line number Diff line number Diff line change
@@ -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())
})

})
})
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))),
Expand Down
8 changes: 8 additions & 0 deletions pkg/api/metadata_const.go
Original file line number Diff line number Diff line change
@@ -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 changes: 57 additions & 0 deletions pkg/webhook/tenant/metadata.go
Original file line number Diff line number Diff line change
@@ -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
}
}

0 comments on commit c58b46c

Please sign in to comment.