Skip to content

Commit fd72425

Browse files
Merge pull request konflux-ci#930 from FilipNikolovski/RELEASE-1894
2 parents d7c98e9 + 968ea89 commit fd72425

8 files changed

Lines changed: 165 additions & 1 deletion

File tree

api/v1alpha1/webhooks/release/webhook.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,15 @@ func (w *Webhook) Register(mgr ctrl.Manager, log *logr.Logger) error {
8080
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
8181
func (w *Webhook) ValidateCreate(ctx context.Context, obj runtime.Object) (warnings admission.Warnings, err error) {
8282
release := obj.(*v1alpha1.Release)
83+
84+
// Validate that resource names used as labels don't exceed Kubernetes label value limit (63 characters)
8385
if len(release.Name) > 63 {
8486
return nil, fmt.Errorf("release name must be no more than 63 characters, got %d characters", len(release.Name))
8587
}
88+
if len(release.Spec.Snapshot) > 63 {
89+
return nil, fmt.Errorf("snapshot name must be no more than 63 characters, got %d characters", len(release.Spec.Snapshot))
90+
}
91+
8692
return nil, nil
8793
}
8894

api/v1alpha1/webhooks/release/webhook_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,39 @@ var _ = Describe("Release validation webhook", func() {
123123
Expect(err.Error()).To(ContainSubstring("release name must be no more than 63 characters"))
124124
Expect(warnings).To(BeEmpty())
125125
})
126+
127+
It("should return an error when snapshot name is longer than 63 characters", func() {
128+
release := &v1alpha1.Release{
129+
ObjectMeta: metav1.ObjectMeta{
130+
Name: "test-release",
131+
Namespace: "default",
132+
},
133+
Spec: v1alpha1.ReleaseSpec{
134+
Snapshot: "this-is-a-very-long-snapshot-name-that-exceeds-sixty-three-chars",
135+
ReleasePlan: "test-releaseplan",
136+
},
137+
}
138+
warnings, err := webhook.ValidateCreate(context.TODO(), release)
139+
Expect(err).To(HaveOccurred())
140+
Expect(err.Error()).To(ContainSubstring("snapshot name must be no more than 63 characters"))
141+
Expect(warnings).To(BeEmpty())
142+
})
143+
144+
It("should not return an error when both release name and snapshot name are within 63 characters", func() {
145+
release := &v1alpha1.Release{
146+
ObjectMeta: metav1.ObjectMeta{
147+
Name: "test-release",
148+
Namespace: "default",
149+
},
150+
Spec: v1alpha1.ReleaseSpec{
151+
Snapshot: "test-snapshot",
152+
ReleasePlan: "test-releaseplan",
153+
},
154+
}
155+
warnings, err := webhook.ValidateCreate(context.TODO(), release)
156+
Expect(err).NotTo(HaveOccurred())
157+
Expect(warnings).To(BeEmpty())
158+
})
126159
})
127160

128161
createResources = func() {

api/v1alpha1/webhooks/releaseplan/suite_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ var (
5959
k8sClient client.Client
6060
mgr manager.Manager
6161
testEnv *envtest.Environment
62+
webhook *Webhook
6263
)
6364

6465
func TestReleasePlanWebhook(t *testing.T) {
@@ -107,7 +108,8 @@ var _ = BeforeSuite(func() {
107108
})
108109
Expect(err).NotTo(HaveOccurred())
109110

110-
err = toolkit.SetupWebhooks(mgr, &Webhook{}, &author.Webhook{})
111+
webhook = &Webhook{}
112+
err = toolkit.SetupWebhooks(mgr, webhook, &author.Webhook{})
111113
Expect(err).NotTo(HaveOccurred())
112114

113115
//+kubebuilder:scaffold:webhook

api/v1alpha1/webhooks/releaseplan/webhook.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ package releaseplan
1818

1919
import (
2020
"context"
21+
"fmt"
2122

2223
"github.com/go-logr/logr"
2324
"github.com/konflux-ci/release-service/api/v1alpha1"
2425
"github.com/konflux-ci/release-service/metadata"
2526
"k8s.io/apimachinery/pkg/runtime"
2627
ctrl "sigs.k8s.io/controller-runtime"
2728
"sigs.k8s.io/controller-runtime/pkg/client"
29+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2830
)
2931

3032
// Webhook describes the data structure for the bar webhook
@@ -49,6 +51,7 @@ func (w *Webhook) Default(ctx context.Context, obj runtime.Object) error {
4951
}
5052

5153
// +kubebuilder:webhook:path=/mutate-appstudio-redhat-com-v1alpha1-releaseplan,mutating=true,failurePolicy=fail,sideEffects=None,groups=appstudio.redhat.com,resources=releaseplans,verbs=create,versions=v1alpha1,name=mreleaseplan.kb.io,admissionReviewVersions=v1
54+
// +kubebuilder:webhook:path=/validate-appstudio-redhat-com-v1alpha1-releaseplan,mutating=false,failurePolicy=fail,sideEffects=None,groups=appstudio.redhat.com,resources=releaseplans,verbs=create;update,versions=v1alpha1,name=vreleaseplan.kb.io,admissionReviewVersions=v1
5255

5356
// Register registers the webhook with the passed manager and log.
5457
func (w *Webhook) Register(mgr ctrl.Manager, log *logr.Logger) error {
@@ -58,5 +61,35 @@ func (w *Webhook) Register(mgr ctrl.Manager, log *logr.Logger) error {
5861
return ctrl.NewWebhookManagedBy(mgr).
5962
For(&v1alpha1.ReleasePlan{}).
6063
WithDefaulter(w).
64+
WithValidator(w).
6165
Complete()
6266
}
67+
68+
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
69+
func (w *Webhook) ValidateCreate(ctx context.Context, obj runtime.Object) (warnings admission.Warnings, err error) {
70+
releasePlan := obj.(*v1alpha1.ReleasePlan)
71+
72+
// Validate that the Application field doesn't exceed Kubernetes label value limit (63 characters)
73+
if len(releasePlan.Spec.Application) > 63 {
74+
return nil, fmt.Errorf("application name must be no more than 63 characters, got %d characters", len(releasePlan.Spec.Application))
75+
}
76+
77+
return nil, nil
78+
}
79+
80+
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
81+
func (w *Webhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings admission.Warnings, err error) {
82+
releasePlan := newObj.(*v1alpha1.ReleasePlan)
83+
84+
// Validate that the Application field doesn't exceed Kubernetes label value limit (63 characters)
85+
if len(releasePlan.Spec.Application) > 63 {
86+
return nil, fmt.Errorf("application name must be no more than 63 characters, got %d characters", len(releasePlan.Spec.Application))
87+
}
88+
89+
return nil, nil
90+
}
91+
92+
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
93+
func (w *Webhook) ValidateDelete(ctx context.Context, obj runtime.Object) (warnings admission.Warnings, err error) {
94+
return nil, nil
95+
}

api/v1alpha1/webhooks/releaseplan/webhook_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,30 @@ var _ = Describe("ReleasePlan webhook", func() {
105105
}, timeout).Should(BeTrue())
106106
})
107107
})
108+
109+
When("ValidateDelete method is called", func() {
110+
It("should return nil", func() {
111+
releasePlan := &v1alpha1.ReleasePlan{}
112+
Expect(webhook.ValidateDelete(ctx, releasePlan)).To(BeNil())
113+
})
114+
})
115+
116+
When("a ReleasePlan is created with an application name longer than 63 characters", func() {
117+
It("should be rejected", func() {
118+
releasePlan.Spec.Application = "this-is-a-very-long-application-name-that-exceeds-sixty-three-chars"
119+
err := k8sClient.Create(ctx, releasePlan)
120+
Expect(err).To(HaveOccurred())
121+
Expect(err.Error()).To(ContainSubstring("application name must be no more than 63 characters"))
122+
})
123+
})
124+
125+
When("a ReleasePlan is updated with an application name longer than 63 characters", func() {
126+
It("should be rejected", func() {
127+
Expect(k8sClient.Create(ctx, releasePlan)).Should(Succeed())
128+
releasePlan.Spec.Application = "this-is-a-very-long-application-name-that-exceeds-sixty-three-chars"
129+
err := k8sClient.Update(ctx, releasePlan)
130+
Expect(err).To(HaveOccurred())
131+
Expect(err.Error()).To(ContainSubstring("application name must be no more than 63 characters"))
132+
})
133+
})
108134
})

api/v1alpha1/webhooks/releaseplanadmission/webhook.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,29 @@ func (w *Webhook) Register(mgr ctrl.Manager, log *logr.Logger) error {
6969

7070
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
7171
func (w *Webhook) ValidateCreate(ctx context.Context, obj runtime.Object) (warnings admission.Warnings, err error) {
72+
releasePlanAdmission := obj.(*v1alpha1.ReleasePlanAdmission)
73+
74+
// Validate that application names don't exceed Kubernetes label value limit (63 characters)
75+
for _, app := range releasePlanAdmission.Spec.Applications {
76+
if len(app) > 63 {
77+
return nil, fmt.Errorf("application name '%s' must be no more than 63 characters, got %d characters", app, len(app))
78+
}
79+
}
80+
7281
return w.validateBlockReleasesLabel(obj)
7382
}
7483

7584
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
7685
func (w *Webhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings admission.Warnings, err error) {
86+
releasePlanAdmission := newObj.(*v1alpha1.ReleasePlanAdmission)
87+
88+
// Validate that application names don't exceed Kubernetes label value limit (63 characters)
89+
for _, app := range releasePlanAdmission.Spec.Applications {
90+
if len(app) > 63 {
91+
return nil, fmt.Errorf("application name '%s' must be no more than 63 characters, got %d characters", app, len(app))
92+
}
93+
}
94+
7795
return w.validateBlockReleasesLabel(newObj)
7896
}
7997

api/v1alpha1/webhooks/releaseplanadmission/webhook_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,30 @@ var _ = Describe("ReleasePlanAdmission webhook", func() {
143143
Expect(webhook.ValidateDelete(ctx, releasePlanAdmission)).To(BeNil())
144144
})
145145
})
146+
147+
When("a ReleasePlanAdmission is created with an application name longer than 63 characters", func() {
148+
It("should be rejected", func() {
149+
releasePlanAdmission.Spec.Applications = []string{
150+
"valid-app",
151+
"this-is-a-very-long-application-name-that-exceeds-sixty-three-chars",
152+
}
153+
err := k8sClient.Create(ctx, releasePlanAdmission)
154+
Expect(err).To(HaveOccurred())
155+
Expect(err.Error()).To(ContainSubstring("application name"))
156+
Expect(err.Error()).To(ContainSubstring("must be no more than 63 characters"))
157+
})
158+
})
159+
160+
When("a ReleasePlanAdmission is updated with an application name longer than 63 characters", func() {
161+
It("should be rejected", func() {
162+
Expect(k8sClient.Create(ctx, releasePlanAdmission)).Should(Succeed())
163+
releasePlanAdmission.Spec.Applications = []string{
164+
"this-is-a-very-long-application-name-that-exceeds-sixty-three-chars",
165+
}
166+
err := k8sClient.Update(ctx, releasePlanAdmission)
167+
Expect(err).To(HaveOccurred())
168+
Expect(err.Error()).To(ContainSubstring("application name"))
169+
Expect(err.Error()).To(ContainSubstring("must be no more than 63 characters"))
170+
})
171+
})
146172
})

config/webhook/manifests.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,26 @@ webhooks:
108108
resources:
109109
- releases
110110
sideEffects: None
111+
- admissionReviewVersions:
112+
- v1
113+
clientConfig:
114+
service:
115+
name: webhook-service
116+
namespace: system
117+
path: /validate-appstudio-redhat-com-v1alpha1-releaseplan
118+
failurePolicy: Fail
119+
name: vreleaseplan.kb.io
120+
rules:
121+
- apiGroups:
122+
- appstudio.redhat.com
123+
apiVersions:
124+
- v1alpha1
125+
operations:
126+
- CREATE
127+
- UPDATE
128+
resources:
129+
- releaseplans
130+
sideEffects: None
111131
- admissionReviewVersions:
112132
- v1
113133
clientConfig:

0 commit comments

Comments
 (0)