Skip to content

Commit bfc9827

Browse files
authored
Merge pull request #787 from alenkacz/av/envtest-webhook
⚠ (:warning:, major) Webhook support in envtest
2 parents 28f24de + 528cd19 commit bfc9827

File tree

10 files changed

+834
-4
lines changed

10 files changed

+834
-4
lines changed

pkg/cache/cache_test.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
9696
Expect(cfg).NotTo(BeNil())
9797

9898
By("creating three pods")
99+
cl, err := client.New(cfg, client.Options{})
100+
Expect(err).NotTo(HaveOccurred())
101+
err = ensureNamespace(testNamespaceOne, cl)
102+
Expect(err).NotTo(HaveOccurred())
103+
err = ensureNamespace(testNamespaceTwo, cl)
104+
Expect(err).NotTo(HaveOccurred())
105+
err = ensureNamespace(testNamespaceThree, cl)
106+
Expect(err).NotTo(HaveOccurred())
99107
// Includes restart policy since these objects are indexed on this field.
100108
knownPod1 = createPod("test-pod-1", testNamespaceOne, kcorev1.RestartPolicyNever)
101109
knownPod2 = createPod("test-pod-2", testNamespaceTwo, kcorev1.RestartPolicyAlways)
@@ -111,7 +119,6 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
111119
knownPod4.GetObjectKind().SetGroupVersionKind(podGVK)
112120

113121
By("creating the informer cache")
114-
var err error
115122
informerCache, err = createCacheFunc(cfg, cache.Options{})
116123
Expect(err).NotTo(HaveOccurred())
117124
By("running the cache and waiting for it to sync")
@@ -681,3 +688,21 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
681688
})
682689
})
683690
}
691+
692+
// ensureNamespace installs namespace of a given name if not exists
693+
func ensureNamespace(namespace string, client client.Client) error {
694+
ns := kcorev1.Namespace{
695+
ObjectMeta: kmetav1.ObjectMeta{
696+
Name: namespace,
697+
},
698+
TypeMeta: kmetav1.TypeMeta{
699+
Kind: "Namespace",
700+
APIVersion: "v1",
701+
},
702+
}
703+
err := client.Create(context.TODO(), &ns)
704+
if errors.IsAlreadyExists(err) {
705+
return nil
706+
}
707+
return err
708+
}

pkg/envtest/envtest_suite_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import (
2121

2222
. "github.com/onsi/ginkgo"
2323
. "github.com/onsi/gomega"
24+
admissionv1 "k8s.io/api/admissionregistration/v1"
25+
admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/runtime"
2428
logf "sigs.k8s.io/controller-runtime/pkg/log"
2529
"sigs.k8s.io/controller-runtime/pkg/log/zap"
2630
)
@@ -35,12 +39,101 @@ var env *Environment
3539
var _ = BeforeSuite(func(done Done) {
3640
logf.SetLogger(zap.LoggerTo(GinkgoWriter, true))
3741
env = &Environment{}
42+
// we're initializing webhook here and not in webhook.go to also test the envtest install code via WebhookOptions
43+
initializeWebhookInEnvironment()
3844
_, err := env.Start()
3945
Expect(err).NotTo(HaveOccurred())
4046

4147
close(done)
4248
}, StartTimeout)
4349

50+
func initializeWebhookInEnvironment() {
51+
namespacedScopeV1Beta1 := admissionv1beta1.NamespacedScope
52+
namespacedScopeV1 := admissionv1.NamespacedScope
53+
failedTypeV1Beta1 := admissionv1beta1.Fail
54+
failedTypeV1 := admissionv1.Fail
55+
equivalentTypeV1Beta1 := admissionv1beta1.Equivalent
56+
equivalentTypeV1 := admissionv1.Equivalent
57+
noSideEffectsV1Beta1 := admissionv1beta1.SideEffectClassNone
58+
noSideEffectsV1 := admissionv1.SideEffectClassNone
59+
webhookPathV1 := "/failing"
60+
61+
env.WebhookInstallOptions = WebhookInstallOptions{
62+
ValidatingWebhooks: []runtime.Object{
63+
&admissionv1beta1.ValidatingWebhookConfiguration{
64+
ObjectMeta: metav1.ObjectMeta{
65+
Name: "deployment-validation-webhook-config",
66+
},
67+
TypeMeta: metav1.TypeMeta{
68+
Kind: "ValidatingWebhookConfiguration",
69+
APIVersion: "admissionregistration.k8s.io/v1beta1",
70+
},
71+
Webhooks: []admissionv1beta1.ValidatingWebhook{
72+
{
73+
Name: "deployment-validation.kubebuilder.io",
74+
Rules: []admissionv1beta1.RuleWithOperations{
75+
{
76+
Operations: []admissionv1beta1.OperationType{"CREATE", "UPDATE"},
77+
Rule: admissionv1beta1.Rule{
78+
APIGroups: []string{"apps"},
79+
APIVersions: []string{"v1"},
80+
Resources: []string{"deployments"},
81+
Scope: &namespacedScopeV1Beta1,
82+
},
83+
},
84+
},
85+
FailurePolicy: &failedTypeV1Beta1,
86+
MatchPolicy: &equivalentTypeV1Beta1,
87+
SideEffects: &noSideEffectsV1Beta1,
88+
ClientConfig: admissionv1beta1.WebhookClientConfig{
89+
Service: &admissionv1beta1.ServiceReference{
90+
Name: "deployment-validation-service",
91+
Namespace: "default",
92+
Path: &webhookPathV1,
93+
},
94+
},
95+
},
96+
},
97+
},
98+
&admissionv1.ValidatingWebhookConfiguration{
99+
ObjectMeta: metav1.ObjectMeta{
100+
Name: "deployment-validation-webhook-config",
101+
},
102+
TypeMeta: metav1.TypeMeta{
103+
Kind: "ValidatingWebhookConfiguration",
104+
APIVersion: "admissionregistration.k8s.io/v1beta1",
105+
},
106+
Webhooks: []admissionv1.ValidatingWebhook{
107+
{
108+
Name: "deployment-validation.kubebuilder.io",
109+
Rules: []admissionv1.RuleWithOperations{
110+
{
111+
Operations: []admissionv1.OperationType{"CREATE", "UPDATE"},
112+
Rule: admissionv1.Rule{
113+
APIGroups: []string{"apps"},
114+
APIVersions: []string{"v1"},
115+
Resources: []string{"deployments"},
116+
Scope: &namespacedScopeV1,
117+
},
118+
},
119+
},
120+
FailurePolicy: &failedTypeV1,
121+
MatchPolicy: &equivalentTypeV1,
122+
SideEffects: &noSideEffectsV1,
123+
ClientConfig: admissionv1.WebhookClientConfig{
124+
Service: &admissionv1.ServiceReference{
125+
Name: "deployment-validation-service",
126+
Namespace: "default",
127+
Path: &webhookPathV1,
128+
},
129+
},
130+
},
131+
},
132+
},
133+
},
134+
}
135+
}
136+
44137
var _ = AfterSuite(func(done Done) {
45138
Expect(env.Stop()).NotTo(HaveOccurred())
46139

pkg/envtest/envtest_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -779,16 +779,18 @@ var _ = Describe("Test", func() {
779779

780780
Describe("Start", func() {
781781
It("should raise an error on invalid dir when flag is enabled", func(done Done) {
782-
env = &Environment{ErrorIfCRDPathMissing: true, CRDDirectoryPaths: []string{invalidDirectory}}
782+
env := &Environment{ErrorIfCRDPathMissing: true, CRDDirectoryPaths: []string{invalidDirectory}}
783783
_, err := env.Start()
784784
Expect(err).To(HaveOccurred())
785+
Expect(env.Stop()).To(Succeed())
785786
close(done)
786787
}, 30)
787788

788789
It("should not raise an error on invalid dir when flag is disabled", func(done Done) {
789-
env = &Environment{ErrorIfCRDPathMissing: false, CRDDirectoryPaths: []string{invalidDirectory}}
790+
env := &Environment{ErrorIfCRDPathMissing: false, CRDDirectoryPaths: []string{invalidDirectory}}
790791
_, err := env.Start()
791792
Expect(err).NotTo(HaveOccurred())
793+
Expect(env.Stop()).To(Succeed())
792794
close(done)
793795
}, 30)
794796
})

pkg/envtest/server.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ type Environment struct {
8686
// CRDInstallOptions are the options for installing CRDs.
8787
CRDInstallOptions CRDInstallOptions
8888

89+
// CRDInstallOptions are the options for installing webhooks.
90+
WebhookInstallOptions WebhookInstallOptions
91+
8992
// ErrorIfCRDPathMissing provides an interface for the underlying
9093
// CRDInstallOptions.ErrorIfPathMissing. It prevents silent failures
9194
// for missing CRD paths.
@@ -137,6 +140,10 @@ func (te *Environment) Stop() error {
137140
if te.useExistingCluster() {
138141
return nil
139142
}
143+
err := te.WebhookInstallOptions.Cleanup()
144+
if err != nil {
145+
return err
146+
}
140147
return te.ControlPlane.Stop()
141148
}
142149

@@ -240,7 +247,14 @@ func (te *Environment) Start() (*rest.Config, error) {
240247
te.CRDInstallOptions.Paths = mergePaths(te.CRDInstallOptions.Paths, te.CRDDirectoryPaths)
241248
te.CRDInstallOptions.ErrorIfPathMissing = te.ErrorIfCRDPathMissing
242249
crds, err := InstallCRDs(te.Config, te.CRDInstallOptions)
250+
if err != nil {
251+
return te.Config, err
252+
}
243253
te.CRDs = crds
254+
255+
log.V(1).Info("installing webhooks")
256+
err = te.WebhookInstallOptions.Install(te.Config)
257+
244258
return te.Config, err
245259
}
246260

0 commit comments

Comments
 (0)