Skip to content

Commit

Permalink
feat: add validation webhook for PromotionTemplate
Browse files Browse the repository at this point in the history
Signed-off-by: Hidde Beydals <[email protected]>
  • Loading branch information
hiddeco committed Dec 2, 2024
1 parent 4ea7964 commit d01d1ec
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
15 changes: 15 additions & 0 deletions charts/kargo/templates/webhooks/webhooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,21 @@ webhooks:
resources: ["promotions"]
operations: ["CREATE", "UPDATE", "DELETE"]
failurePolicy: Fail
- name: promotiontemplate.kargo.akuity.io
admissionReviewVersions: [ "v1" ]
sideEffects: None
clientConfig:
service:
namespace: {{ .Release.Namespace }}
name: kargo-webhooks-server
path: /validate-kargo-akuity-io-v1alpha1-promotiontemplate
rules:
- scope: Namespaced
apiGroups: ["kargo.akuity.io"]
apiVersions: ["v1alpha1"]
resources: ["promotiontemplates"]
operations: ["CREATE"]
failurePolicy: Fail
- name: stage.kargo.akuity.io
admissionReviewVersions: ["v1"]
sideEffects: None
Expand Down
4 changes: 4 additions & 0 deletions cmd/controlplane/webhooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/akuity/kargo/internal/webhook/freight"
"github.com/akuity/kargo/internal/webhook/project"
"github.com/akuity/kargo/internal/webhook/promotion"
"github.com/akuity/kargo/internal/webhook/promotiontemplate"
"github.com/akuity/kargo/internal/webhook/stage"
"github.com/akuity/kargo/internal/webhook/warehouse"
)
Expand Down Expand Up @@ -135,6 +136,9 @@ func (o *webhooksServerOptions) run(ctx context.Context) error {
if err = promotion.SetupWebhookWithManager(ctx, webhookCfg, mgr); err != nil {
return fmt.Errorf("setup Promotion webhook: %w", err)
}
if err = promotiontemplate.SetupWebhookWithManager(mgr); err != nil {
return fmt.Errorf("setup PromotionTemplate webhook: %w", err)
}
if err = stage.SetupWebhookWithManager(webhookCfg, mgr); err != nil {
return fmt.Errorf("setup Stage webhook: %w", err)
}
Expand Down
51 changes: 51 additions & 0 deletions internal/webhook/promotiontemplate/webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package promotiontemplate

import (
"context"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

kargoapi "github.com/akuity/kargo/api/v1alpha1"
libWebhook "github.com/akuity/kargo/internal/webhook"
)

var promotionTemplateGroupKind = schema.GroupKind{
Group: kargoapi.GroupVersion.Group,
Kind: "PromotionTemplate",
}

type webhook struct {
client client.Client
}

func SetupWebhookWithManager(
mgr ctrl.Manager,
) error {
w := &webhook{
client: mgr.GetClient(),
}
return ctrl.NewWebhookManagedBy(mgr).
For(&kargoapi.PromotionTemplate{}).
WithValidator(w).
Complete()
}

func (w *webhook) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
template := obj.(*kargoapi.PromotionTemplate) // nolint: forcetypeassert
if err := libWebhook.ValidateProject(ctx, w.client, promotionTemplateGroupKind, template); err != nil {
return nil, err
}
return nil, nil
}

func (w *webhook) ValidateUpdate(context.Context, runtime.Object, runtime.Object) (admission.Warnings, error) {
return nil, nil
}

func (w *webhook) ValidateDelete(context.Context, runtime.Object) (admission.Warnings, error) {
return nil, nil
}
94 changes: 94 additions & 0 deletions internal/webhook/promotiontemplate/webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package promotiontemplate

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

kargoapi "github.com/akuity/kargo/api/v1alpha1"
)

func Test_webhook_ValidateCreate(t *testing.T) {
scheme := runtime.NewScheme()
require.NoError(t, corev1.AddToScheme(scheme))
require.NoError(t, kargoapi.AddToScheme(scheme))

tests := []struct {
name string
objects []client.Object
template *kargoapi.PromotionTemplate
assertions func(*testing.T, admission.Warnings, error)
}{
{
name: "project does not exist",
objects: []client.Object{
&corev1.Namespace{
ObjectMeta: v1.ObjectMeta{
Name: "fake-project",
},
},
},
template: &kargoapi.PromotionTemplate{
ObjectMeta: v1.ObjectMeta{
Name: "fake-template",
Namespace: "fake-project",
},
},
assertions: func(t *testing.T, warnings admission.Warnings, err error) {
assert.Empty(t, warnings)
assert.ErrorContains(t, err, "namespace \"fake-project\" is not a project")
},
},
{
name: "project exists",
objects: []client.Object{
&corev1.Namespace{
ObjectMeta: v1.ObjectMeta{
Name: "fake-project",
Labels: map[string]string{
kargoapi.ProjectLabelKey: kargoapi.LabelTrueValue,
},
},
},
&kargoapi.Project{
ObjectMeta: v1.ObjectMeta{
Name: "fake-project",
},
},
},
template: &kargoapi.PromotionTemplate{
ObjectMeta: v1.ObjectMeta{
Name: "fake-template",
Namespace: "fake-project",
},
},
assertions: func(t *testing.T, warnings admission.Warnings, err error) {
assert.Empty(t, warnings)
assert.NoError(t, err)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := fake.NewClientBuilder().
WithObjects(tt.objects...).
WithScheme(scheme).
Build()

w := &webhook{
client: c,
}

got, err := w.ValidateCreate(context.Background(), tt.template)
tt.assertions(t, got, err)
})
}
}

0 comments on commit d01d1ec

Please sign in to comment.