Skip to content

Commit b13bb6e

Browse files
✨ (go/v4) Add scaffold for e2e webhook checks
A new scaffold marker is introduced to automatically adds end-to-end tests for webhooks in the test/e2e/test.go The scaffolded tests include: - Validation that cert-manager has successfully provisioned the secret, when/if an webhook is scaffold for the project. - Verification that the CA bundle is injected into the mutating webhooks, if a mutating webhook is scaffolded. - Verification that the CA bundle is injected into the validating webhooks, if a validating webhook is scaffolded.
1 parent defede3 commit b13bb6e

File tree

10 files changed

+306
-2
lines changed

10 files changed

+306
-2
lines changed

docs/book/src/cronjob-tutorial/testdata/project/test/e2e/e2e_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ var _ = Describe("Manager", Ordered, func() {
184184
))
185185
})
186186

187+
It("should provisioned cert-manager", func() {
188+
By("validating that cert-manager has the certificate Secret")
189+
verifyCertManager := func(g Gomega) {
190+
cmd := exec.Command("kubectl", "get", "secrets", "webhook-server-cert", "-n", namespace)
191+
_, err := utils.Run(cmd)
192+
g.Expect(err).NotTo(HaveOccurred())
193+
}
194+
Eventually(verifyCertManager).Should(Succeed())
195+
})
196+
197+
It("should have CA injection for mutating webhooks", func() {
198+
By("checking CA injection for mutating webhooks")
199+
verifyCAInjection := func(g Gomega) {
200+
cmd := exec.Command("kubectl", "get",
201+
"mutatingwebhookconfigurations.admissionregistration.k8s.io",
202+
"project-mutating-webhook-configuration",
203+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
204+
mwhOutput, err := utils.Run(cmd)
205+
g.Expect(err).NotTo(HaveOccurred())
206+
g.Expect(len(mwhOutput)).To(BeNumerically(">", 10))
207+
}
208+
Eventually(verifyCAInjection).Should(Succeed())
209+
})
210+
211+
It("should have CA injection for validating webhooks", func() {
212+
By("checking CA injection for validating webhooks")
213+
verifyCAInjection := func(g Gomega) {
214+
cmd := exec.Command("kubectl", "get",
215+
"validatingwebhookconfigurations.admissionregistration.k8s.io",
216+
"project-validating-webhook-configuration",
217+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
218+
vwhOutput, err := utils.Run(cmd)
219+
g.Expect(err).NotTo(HaveOccurred())
220+
g.Expect(len(vwhOutput)).To(BeNumerically(">", 10))
221+
}
222+
Eventually(verifyCAInjection).Should(Succeed())
223+
})
224+
225+
// +kubebuilder:scaffold:e2e-webhooks-checks
226+
187227
// TODO: Customize the e2e test suite with scenarios specific to your project.
188228
// Consider applying sample/CR(s) and check their status and/or verifying
189229
// the reconciliation by using the metrics, i.e.:

docs/book/src/getting-started/testdata/project/test/e2e/e2e_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ var _ = Describe("Manager", Ordered, func() {
184184
))
185185
})
186186

187+
// +kubebuilder:scaffold:e2e-webhooks-checks
188+
187189
// TODO: Customize the e2e test suite with scenarios specific to your project.
188190
// Consider applying sample/CR(s) and check their status and/or verifying
189191
// the reconciliation by using the metrics, i.e.:

pkg/plugins/golang/v4/scaffolds/init.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ func (s *initScaffolder) Scaffold() error {
160160
&templates.Readme{},
161161
&templates.Golangci{},
162162
&e2e.Test{},
163+
&e2e.WebhookTestUpdater{WireWebhook: false},
163164
&e2e.SuiteTest{},
164165
&utils.Utils{},
165166
&templates.DevContainer{},

pkg/plugins/golang/v4/scaffolds/internal/templates/test/e2e/test.go

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@ limitations under the License.
1717
package e2e
1818

1919
import (
20+
"fmt"
21+
"path/filepath"
22+
2023
"sigs.k8s.io/kubebuilder/v4/pkg/machinery"
2124
)
2225

23-
var _ machinery.Template = &SuiteTest{}
26+
var _ machinery.Template = &Test{}
27+
var _ machinery.Inserter = &WebhookTestUpdater{}
2428

29+
const webhookChecksMarker = "e2e-webhooks-checks"
30+
31+
// Test defines the basic setup for the e2e test
2532
type Test struct {
2633
machinery.TemplateMixin
2734
machinery.BoilerplateMixin
@@ -31,13 +38,115 @@ type Test struct {
3138

3239
func (f *Test) SetTemplateDefaults() error {
3340
if f.Path == "" {
34-
f.Path = "test/e2e/e2e_test.go"
41+
f.Path = filepath.Join("test", "e2e", "e2e_test.go")
3542
}
3643

44+
// This is where the template body is defined with markers
3745
f.TemplateBody = TestTemplate
46+
3847
return nil
3948
}
4049

50+
// WebhookTestUpdater updates e2e_test.go to insert additional webhook validation tests
51+
type WebhookTestUpdater struct {
52+
machinery.RepositoryMixin
53+
machinery.ProjectNameMixin
54+
machinery.ResourceMixin
55+
WireWebhook bool
56+
}
57+
58+
// GetPath implements file.Builder
59+
func (*WebhookTestUpdater) GetPath() string {
60+
return filepath.Join("test", "e2e", "e2e_test.go")
61+
}
62+
63+
// GetIfExistsAction implements file.Builder
64+
func (*WebhookTestUpdater) GetIfExistsAction() machinery.IfExistsAction {
65+
return machinery.OverwriteFile // Ensures only the marker is replaced
66+
}
67+
68+
// GetMarkers implements file.Inserter
69+
func (f *WebhookTestUpdater) GetMarkers() []machinery.Marker {
70+
return []machinery.Marker{
71+
machinery.NewMarkerFor(f.GetPath(), webhookChecksMarker),
72+
}
73+
}
74+
75+
// GetCodeFragments implements file.Inserter
76+
func (f *WebhookTestUpdater) GetCodeFragments() machinery.CodeFragmentsMap {
77+
codeFragments := machinery.CodeFragmentsMap{}
78+
if !f.WireWebhook {
79+
return nil
80+
}
81+
codeFragments[machinery.NewMarkerFor(f.GetPath(), webhookChecksMarker)] = append(
82+
codeFragments[machinery.NewMarkerFor(f.GetPath(), webhookChecksMarker)],
83+
webhookChecksFragment,
84+
)
85+
86+
if f.Resource != nil && f.Resource.HasDefaultingWebhook() {
87+
mutatingWebhookCode := fmt.Sprintf(mutatingWebhookChecksFragment, f.ProjectName)
88+
codeFragments[machinery.NewMarkerFor(f.GetPath(), webhookChecksMarker)] = append(
89+
codeFragments[machinery.NewMarkerFor(f.GetPath(), webhookChecksMarker)],
90+
mutatingWebhookCode,
91+
)
92+
}
93+
94+
if f.Resource.HasValidationWebhook() {
95+
validatingWebhookCode := fmt.Sprintf(validatingWebhookChecksFragment, f.ProjectName)
96+
codeFragments[machinery.NewMarkerFor(f.GetPath(), webhookChecksMarker)] = append(
97+
codeFragments[machinery.NewMarkerFor(f.GetPath(), webhookChecksMarker)],
98+
validatingWebhookCode,
99+
)
100+
}
101+
102+
return codeFragments
103+
}
104+
105+
const webhookChecksFragment = `It("should provisioned cert-manager", func() {
106+
By("validating that cert-manager has the certificate Secret")
107+
verifyCertManager := func(g Gomega) {
108+
cmd := exec.Command("kubectl", "get", "secrets", "webhook-server-cert", "-n", namespace)
109+
_, err := utils.Run(cmd)
110+
g.Expect(err).NotTo(HaveOccurred())
111+
}
112+
Eventually(verifyCertManager).Should(Succeed())
113+
})
114+
115+
`
116+
117+
const mutatingWebhookChecksFragment = `It("should have CA injection for mutating webhooks", func() {
118+
By("checking CA injection for mutating webhooks")
119+
verifyCAInjection := func(g Gomega) {
120+
cmd := exec.Command("kubectl", "get",
121+
"mutatingwebhookconfigurations.admissionregistration.k8s.io",
122+
"%s-mutating-webhook-configuration",
123+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
124+
mwhOutput, err := utils.Run(cmd)
125+
g.Expect(err).NotTo(HaveOccurred())
126+
g.Expect(len(mwhOutput)).To(BeNumerically(">", 10))
127+
}
128+
Eventually(verifyCAInjection).Should(Succeed())
129+
})
130+
131+
`
132+
133+
// nolint:lll
134+
const validatingWebhookChecksFragment = `It("should have CA injection for validating webhooks", func() {
135+
By("checking CA injection for validating webhooks")
136+
verifyCAInjection := func(g Gomega) {
137+
cmd := exec.Command("kubectl", "get",
138+
"validatingwebhookconfigurations.admissionregistration.k8s.io",
139+
"%s-validating-webhook-configuration",
140+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
141+
vwhOutput, err := utils.Run(cmd)
142+
g.Expect(err).NotTo(HaveOccurred())
143+
g.Expect(len(vwhOutput)).To(BeNumerically(">", 10))
144+
}
145+
Eventually(verifyCAInjection).Should(Succeed())
146+
})
147+
148+
`
149+
41150
var TestTemplate = `{{ .Boilerplate }}
42151
43152
@@ -208,6 +317,8 @@ var _ = Describe("Manager", Ordered, func() {
208317
))
209318
})
210319
320+
// +kubebuilder:scaffold:e2e-webhooks-checks
321+
211322
// TODO: Customize the e2e test suite with scenarios specific to your project.
212323
// Consider applying sample/CR(s) and check their status and/or verifying
213324
// the reconciliation by using the metrics, i.e.:

pkg/plugins/golang/v4/scaffolds/webhook.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/v4/scaffolds/internal/templates"
3030
"sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/v4/scaffolds/internal/templates/api"
3131
"sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/v4/scaffolds/internal/templates/hack"
32+
"sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/v4/scaffolds/internal/templates/test/e2e"
3233
)
3334

3435
var _ plugins.Scaffolder = &webhookScaffolder{}
@@ -86,6 +87,7 @@ func (s *webhookScaffolder) Scaffold() error {
8687

8788
if err := scaffold.Execute(
8889
&api.Webhook{Force: s.force},
90+
&e2e.WebhookTestUpdater{WireWebhook: true},
8991
&templates.MainUpdater{WireWebhook: true},
9092
&api.WebhookTest{Force: s.force},
9193
); err != nil {

testdata/project-v4-multigroup-with-deploy-image/test/e2e/e2e_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ var _ = Describe("Manager", Ordered, func() {
184184
))
185185
})
186186

187+
It("should provisioned cert-manager", func() {
188+
By("validating that cert-manager has the certificate Secret")
189+
verifyCertManager := func(g Gomega) {
190+
cmd := exec.Command("kubectl", "get", "secrets", "webhook-server-cert", "-n", namespace)
191+
_, err := utils.Run(cmd)
192+
g.Expect(err).NotTo(HaveOccurred())
193+
}
194+
Eventually(verifyCertManager).Should(Succeed())
195+
})
196+
197+
It("should have CA injection for mutating webhooks", func() {
198+
By("checking CA injection for mutating webhooks")
199+
verifyCAInjection := func(g Gomega) {
200+
cmd := exec.Command("kubectl", "get",
201+
"mutatingwebhookconfigurations.admissionregistration.k8s.io",
202+
"project-v4-multigroup-with-deploy-image-mutating-webhook-configuration",
203+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
204+
mwhOutput, err := utils.Run(cmd)
205+
g.Expect(err).NotTo(HaveOccurred())
206+
g.Expect(len(mwhOutput)).To(BeNumerically(">", 10))
207+
}
208+
Eventually(verifyCAInjection).Should(Succeed())
209+
})
210+
211+
It("should have CA injection for validating webhooks", func() {
212+
By("checking CA injection for validating webhooks")
213+
verifyCAInjection := func(g Gomega) {
214+
cmd := exec.Command("kubectl", "get",
215+
"validatingwebhookconfigurations.admissionregistration.k8s.io",
216+
"project-v4-multigroup-with-deploy-image-validating-webhook-configuration",
217+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
218+
vwhOutput, err := utils.Run(cmd)
219+
g.Expect(err).NotTo(HaveOccurred())
220+
g.Expect(len(vwhOutput)).To(BeNumerically(">", 10))
221+
}
222+
Eventually(verifyCAInjection).Should(Succeed())
223+
})
224+
225+
// +kubebuilder:scaffold:e2e-webhooks-checks
226+
187227
// TODO: Customize the e2e test suite with scenarios specific to your project.
188228
// Consider applying sample/CR(s) and check their status and/or verifying
189229
// the reconciliation by using the metrics, i.e.:

testdata/project-v4-multigroup/test/e2e/e2e_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ var _ = Describe("Manager", Ordered, func() {
184184
))
185185
})
186186

187+
It("should provisioned cert-manager", func() {
188+
By("validating that cert-manager has the certificate Secret")
189+
verifyCertManager := func(g Gomega) {
190+
cmd := exec.Command("kubectl", "get", "secrets", "webhook-server-cert", "-n", namespace)
191+
_, err := utils.Run(cmd)
192+
g.Expect(err).NotTo(HaveOccurred())
193+
}
194+
Eventually(verifyCertManager).Should(Succeed())
195+
})
196+
197+
It("should have CA injection for mutating webhooks", func() {
198+
By("checking CA injection for mutating webhooks")
199+
verifyCAInjection := func(g Gomega) {
200+
cmd := exec.Command("kubectl", "get",
201+
"mutatingwebhookconfigurations.admissionregistration.k8s.io",
202+
"project-v4-multigroup-mutating-webhook-configuration",
203+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
204+
mwhOutput, err := utils.Run(cmd)
205+
g.Expect(err).NotTo(HaveOccurred())
206+
g.Expect(len(mwhOutput)).To(BeNumerically(">", 10))
207+
}
208+
Eventually(verifyCAInjection).Should(Succeed())
209+
})
210+
211+
It("should have CA injection for validating webhooks", func() {
212+
By("checking CA injection for validating webhooks")
213+
verifyCAInjection := func(g Gomega) {
214+
cmd := exec.Command("kubectl", "get",
215+
"validatingwebhookconfigurations.admissionregistration.k8s.io",
216+
"project-v4-multigroup-validating-webhook-configuration",
217+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
218+
vwhOutput, err := utils.Run(cmd)
219+
g.Expect(err).NotTo(HaveOccurred())
220+
g.Expect(len(vwhOutput)).To(BeNumerically(">", 10))
221+
}
222+
Eventually(verifyCAInjection).Should(Succeed())
223+
})
224+
225+
// +kubebuilder:scaffold:e2e-webhooks-checks
226+
187227
// TODO: Customize the e2e test suite with scenarios specific to your project.
188228
// Consider applying sample/CR(s) and check their status and/or verifying
189229
// the reconciliation by using the metrics, i.e.:

testdata/project-v4-with-deploy-image/test/e2e/e2e_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,32 @@ var _ = Describe("Manager", Ordered, func() {
184184
))
185185
})
186186

187+
It("should provisioned cert-manager", func() {
188+
By("validating that cert-manager has the certificate Secret")
189+
verifyCertManager := func(g Gomega) {
190+
cmd := exec.Command("kubectl", "get", "secrets", "webhook-server-cert", "-n", namespace)
191+
_, err := utils.Run(cmd)
192+
g.Expect(err).NotTo(HaveOccurred())
193+
}
194+
Eventually(verifyCertManager).Should(Succeed())
195+
})
196+
197+
It("should have CA injection for validating webhooks", func() {
198+
By("checking CA injection for validating webhooks")
199+
verifyCAInjection := func(g Gomega) {
200+
cmd := exec.Command("kubectl", "get",
201+
"validatingwebhookconfigurations.admissionregistration.k8s.io",
202+
"project-v4-with-deploy-image-validating-webhook-configuration",
203+
"-o", "go-template={{ range .webhooks }}{{ .clientConfig.caBundle }}{{ end }}")
204+
vwhOutput, err := utils.Run(cmd)
205+
g.Expect(err).NotTo(HaveOccurred())
206+
g.Expect(len(vwhOutput)).To(BeNumerically(">", 10))
207+
}
208+
Eventually(verifyCAInjection).Should(Succeed())
209+
})
210+
211+
// +kubebuilder:scaffold:e2e-webhooks-checks
212+
187213
// TODO: Customize the e2e test suite with scenarios specific to your project.
188214
// Consider applying sample/CR(s) and check their status and/or verifying
189215
// the reconciliation by using the metrics, i.e.:

testdata/project-v4-with-grafana/test/e2e/e2e_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ var _ = Describe("Manager", Ordered, func() {
184184
))
185185
})
186186

187+
// +kubebuilder:scaffold:e2e-webhooks-checks
188+
187189
// TODO: Customize the e2e test suite with scenarios specific to your project.
188190
// Consider applying sample/CR(s) and check their status and/or verifying
189191
// the reconciliation by using the metrics, i.e.:

0 commit comments

Comments
 (0)