Skip to content

Commit

Permalink
refactor!: using multiple handers per route
Browse files Browse the repository at this point in the history
  • Loading branch information
prometherion committed Jun 27, 2021
1 parent d799726 commit ba07f99
Show file tree
Hide file tree
Showing 48 changed files with 1,795 additions and 1,201 deletions.
32 changes: 13 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,15 @@ import (
"github.com/clastix/capsule/pkg/configuration"
"github.com/clastix/capsule/pkg/indexer"
"github.com/clastix/capsule/pkg/webhook"
"github.com/clastix/capsule/pkg/webhook/imagepullpolicy"
"github.com/clastix/capsule/pkg/webhook/ingress"
namespacewebhook "github.com/clastix/capsule/pkg/webhook/namespace"
"github.com/clastix/capsule/pkg/webhook/networkpolicies"
"github.com/clastix/capsule/pkg/webhook/networkpolicy"
"github.com/clastix/capsule/pkg/webhook/ownerreference"
"github.com/clastix/capsule/pkg/webhook/podpriority"
"github.com/clastix/capsule/pkg/webhook/pod"
"github.com/clastix/capsule/pkg/webhook/pvc"
"github.com/clastix/capsule/pkg/webhook/registry"
"github.com/clastix/capsule/pkg/webhook/services"
"github.com/clastix/capsule/pkg/webhook/route"
"github.com/clastix/capsule/pkg/webhook/service"
"github.com/clastix/capsule/pkg/webhook/tenant"
"github.com/clastix/capsule/pkg/webhook/tenantprefix"
"github.com/clastix/capsule/pkg/webhook/utils"
// +kubebuilder:scaffold:imports
)
Expand Down Expand Up @@ -142,19 +140,15 @@ func main() {
// webhooks: the order matters, don't change it and just append
webhooksList := append(
make([]webhook.Webhook, 0),
ingress.Webhook(ingress.Handler(cfg)),
pvc.Webhook(pvc.Handler()),
registry.Webhook(registry.Handler()),
podpriority.Webhook(podpriority.Handler()),
services.Webhook(services.Handler()),
ownerreference.Webhook(utils.InCapsuleGroups(cfg, ownerreference.Handler(cfg))),
namespacewebhook.QuotaWebhook(utils.InCapsuleGroups(cfg, namespacewebhook.QuotaHandler())),
namespacewebhook.FreezedWebhook(utils.InCapsuleGroups(cfg, namespacewebhook.FreezeHandler(cfg))),
networkpolicies.Webhook(utils.InCapsuleGroups(cfg, networkpolicies.Handler())),
tenantprefix.Webhook(utils.InCapsuleGroups(cfg, tenantprefix.Handler(cfg))),
tenant.Validating(tenant.ValidatingHandler(cfg)),
imagepullpolicy.Webhook(imagepullpolicy.Handler()),
tenant.Cordoning(tenant.CordoningHandler(cfg)),
route.Pod(pod.ImagePullPolicy(), pod.ContainerRegistry(), pod.PriorityClass()),
route.Namespace(utils.InCapsuleGroups(cfg, namespacewebhook.QuotaHandler(), namespacewebhook.FreezeHandler(cfg), namespacewebhook.PrefixHandler(cfg))),
route.Ingress(ingress.Class(cfg), ingress.Hostnames(cfg), ingress.Collision(cfg)),
route.PVC(pvc.Handler()),
route.Service(service.Handler()),
route.NetworkPolicy(utils.InCapsuleGroups(cfg, networkpolicy.Handler())),
route.Tenant(tenant.NameHandler(), tenant.IngressClassRegexHandler(), tenant.StorageClassRegexHandler(), tenant.ContainerRegistryRegexHandler(), tenant.HostnameRegexHandler(), tenant.HostnamesCollisionHandler(cfg), tenant.FreezedEmitter()),
route.OwnerReference(utils.InCapsuleGroups(cfg, ownerreference.Handler(cfg))),
route.Cordoning(tenant.CordoningHandler(cfg)),
)
if err = webhook.Register(manager, webhooksList...); err != nil {
setupLog.Error(err, "unable to setup webhooks")
Expand Down
2 changes: 1 addition & 1 deletion pkg/webhook/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

type Func func(ctx context.Context, req admission.Request) admission.Response
type Func func(ctx context.Context, req admission.Request) *admission.Response

type Handler interface {
OnCreate(client client.Client, decoder *admission.Decoder, recorder record.EventRecorder) Func
Expand Down
101 changes: 0 additions & 101 deletions pkg/webhook/imagepullpolicy/validating.go

This file was deleted.

4 changes: 2 additions & 2 deletions pkg/webhook/ingress/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package ingress
import (
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
networkingv1beta "k8s.io/api/networking/v1beta1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
)

const (
Expand Down Expand Up @@ -54,7 +54,7 @@ func (n NetworkingV1) Hostnames() []string {
}

type NetworkingV1Beta1 struct {
*networkingv1beta.Ingress
*networkingv1beta1.Ingress
}

func (n NetworkingV1Beta1) Name() string {
Expand Down
61 changes: 61 additions & 0 deletions pkg/webhook/ingress/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2020-2021 Clastix Labs
// SPDX-License-Identifier: Apache-2.0

package ingress

import (
"context"
"fmt"

extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
"k8s.io/apimachinery/pkg/fields"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
)

func tenantFromIngress(ctx context.Context, c client.Client, ingress Ingress) (*capsulev1alpha1.Tenant, error) {
tenantList := &capsulev1alpha1.TenantList{}
if err := c.List(ctx, tenantList, client.MatchingFieldsSelector{
Selector: fields.OneTermEqualSelector(".status.namespaces", ingress.Namespace()),
}); err != nil {
return nil, err
}

if len(tenantList.Items) == 0 {
return nil, nil
}

return &tenantList.Items[0], nil
}

func ingressFromRequest(req admission.Request, decoder *admission.Decoder) (ingress Ingress, err error) {
switch req.Kind.Group {
case "networking.k8s.io":
if req.Kind.Version == "v1" {
ingressObj := &networkingv1.Ingress{}
if err = decoder.Decode(req, ingressObj); err != nil {
return
}
ingress = NetworkingV1{Ingress: ingressObj}
break
}
ingressObj := &networkingv1beta1.Ingress{}
if err = decoder.Decode(req, ingressObj); err != nil {
return
}
ingress = NetworkingV1Beta1{Ingress: ingressObj}
case "extensions":
ingressObj := &extensionsv1beta1.Ingress{}
if err = decoder.Decode(req, ingressObj); err != nil {
return
}
ingress = Extension{Ingress: ingressObj}
default:
err = fmt.Errorf("cannot recognize type %s", req.Kind.Group)
}
return
}
134 changes: 134 additions & 0 deletions pkg/webhook/ingress/validate_class.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2020-2021 Clastix Labs
// SPDX-License-Identifier: Apache-2.0

package ingress

import (
"context"

"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

"github.com/clastix/capsule/api/v1alpha1"
"github.com/clastix/capsule/pkg/configuration"
capsulewebhook "github.com/clastix/capsule/pkg/webhook"
"github.com/clastix/capsule/pkg/webhook/utils"
)

type class struct {
configuration configuration.Configuration
}

func Class(configuration configuration.Configuration) capsulewebhook.Handler {
return &class{configuration: configuration}
}

func (r *class) OnCreate(client client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
ingress, err := ingressFromRequest(req, decoder)
if err != nil {
return utils.ErroredResponse(err)
}

var tenant *v1alpha1.Tenant

tenant, err = tenantFromIngress(ctx, client, ingress)
if err != nil {
return utils.ErroredResponse(err)
}

if tenant == nil {
return nil
}

if err = r.validateClass(*tenant, ingress.IngressClass()); err == nil {
return nil
}

var forbiddenErr *ingressClassForbidden

if errors.As(err, &forbiddenErr) {
recorder.Eventf(tenant, corev1.EventTypeWarning, "IngressClassForbidden", "Ingress %s/%s class is forbidden", ingress.Namespace(), ingress.Name())
}

var invalidErr *ingressClassNotValid

if errors.As(err, &invalidErr) {
recorder.Eventf(tenant, corev1.EventTypeWarning, "IngressClassNotValid", "Ingress %s/%s class is invalid", ingress.Namespace(), ingress.Name())
}

response := admission.Denied(err.Error())

return &response
}
}

func (r *class) OnUpdate(client client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
ingress, err := ingressFromRequest(req, decoder)
if err != nil {
return utils.ErroredResponse(err)
}

var tenant *v1alpha1.Tenant

tenant, err = tenantFromIngress(ctx, client, ingress)
if err != nil {
return utils.ErroredResponse(err)
}

if tenant == nil {
return nil
}

err = r.validateClass(*tenant, ingress.IngressClass())

var forbiddenErr *ingressClassForbidden

if errors.As(err, &forbiddenErr) {
recorder.Eventf(tenant, corev1.EventTypeWarning, "IngressClassForbidden", "Ingress %s/%s class is forbidden", ingress.Namespace(), ingress.Name())
}

var invalidErr *ingressClassNotValid

if errors.As(err, &invalidErr) {
recorder.Eventf(tenant, corev1.EventTypeWarning, "IngressClassNotValid", "Ingress %s/%s class is invalid", ingress.Namespace(), ingress.Name())
}

response := admission.Denied(err.Error())

return &response
}
}

func (r *class) OnDelete(client.Client, *admission.Decoder, record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
return nil
}
}

func (r *class) validateClass(tenant v1alpha1.Tenant, ingressClass *string) error {
if tenant.Spec.IngressClasses == nil {
return nil
}

if ingressClass == nil {
return NewIngressClassNotValid(*tenant.Spec.IngressClasses)
}

var valid, matched bool

if len(tenant.Spec.IngressClasses.Exact) > 0 {
valid = tenant.Spec.IngressClasses.ExactMatch(*ingressClass)
}
matched = tenant.Spec.IngressClasses.RegexMatch(*ingressClass)

if !valid && !matched {
return NewIngressClassForbidden(*ingressClass, *tenant.Spec.IngressClasses)
}

return nil
}

0 comments on commit ba07f99

Please sign in to comment.