Skip to content

Commit

Permalink
Merge pull request #787 from alenkacz/av/envtest-webhook
Browse files Browse the repository at this point in the history
⚠ (:warning:, major) Webhook support in envtest
  • Loading branch information
k8s-ci-robot authored Mar 5, 2020
2 parents 28f24de + 528cd19 commit bfc9827
Show file tree
Hide file tree
Showing 10 changed files with 834 additions and 4 deletions.
27 changes: 26 additions & 1 deletion pkg/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
Expect(cfg).NotTo(BeNil())

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

By("creating the informer cache")
var err error
informerCache, err = createCacheFunc(cfg, cache.Options{})
Expect(err).NotTo(HaveOccurred())
By("running the cache and waiting for it to sync")
Expand Down Expand Up @@ -681,3 +688,21 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
})
})
}

// ensureNamespace installs namespace of a given name if not exists
func ensureNamespace(namespace string, client client.Client) error {
ns := kcorev1.Namespace{
ObjectMeta: kmetav1.ObjectMeta{
Name: namespace,
},
TypeMeta: kmetav1.TypeMeta{
Kind: "Namespace",
APIVersion: "v1",
},
}
err := client.Create(context.TODO(), &ns)
if errors.IsAlreadyExists(err) {
return nil
}
return err
}
93 changes: 93 additions & 0 deletions pkg/envtest/envtest_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import (

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

close(done)
}, StartTimeout)

func initializeWebhookInEnvironment() {
namespacedScopeV1Beta1 := admissionv1beta1.NamespacedScope
namespacedScopeV1 := admissionv1.NamespacedScope
failedTypeV1Beta1 := admissionv1beta1.Fail
failedTypeV1 := admissionv1.Fail
equivalentTypeV1Beta1 := admissionv1beta1.Equivalent
equivalentTypeV1 := admissionv1.Equivalent
noSideEffectsV1Beta1 := admissionv1beta1.SideEffectClassNone
noSideEffectsV1 := admissionv1.SideEffectClassNone
webhookPathV1 := "/failing"

env.WebhookInstallOptions = WebhookInstallOptions{
ValidatingWebhooks: []runtime.Object{
&admissionv1beta1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "deployment-validation-webhook-config",
},
TypeMeta: metav1.TypeMeta{
Kind: "ValidatingWebhookConfiguration",
APIVersion: "admissionregistration.k8s.io/v1beta1",
},
Webhooks: []admissionv1beta1.ValidatingWebhook{
{
Name: "deployment-validation.kubebuilder.io",
Rules: []admissionv1beta1.RuleWithOperations{
{
Operations: []admissionv1beta1.OperationType{"CREATE", "UPDATE"},
Rule: admissionv1beta1.Rule{
APIGroups: []string{"apps"},
APIVersions: []string{"v1"},
Resources: []string{"deployments"},
Scope: &namespacedScopeV1Beta1,
},
},
},
FailurePolicy: &failedTypeV1Beta1,
MatchPolicy: &equivalentTypeV1Beta1,
SideEffects: &noSideEffectsV1Beta1,
ClientConfig: admissionv1beta1.WebhookClientConfig{
Service: &admissionv1beta1.ServiceReference{
Name: "deployment-validation-service",
Namespace: "default",
Path: &webhookPathV1,
},
},
},
},
},
&admissionv1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "deployment-validation-webhook-config",
},
TypeMeta: metav1.TypeMeta{
Kind: "ValidatingWebhookConfiguration",
APIVersion: "admissionregistration.k8s.io/v1beta1",
},
Webhooks: []admissionv1.ValidatingWebhook{
{
Name: "deployment-validation.kubebuilder.io",
Rules: []admissionv1.RuleWithOperations{
{
Operations: []admissionv1.OperationType{"CREATE", "UPDATE"},
Rule: admissionv1.Rule{
APIGroups: []string{"apps"},
APIVersions: []string{"v1"},
Resources: []string{"deployments"},
Scope: &namespacedScopeV1,
},
},
},
FailurePolicy: &failedTypeV1,
MatchPolicy: &equivalentTypeV1,
SideEffects: &noSideEffectsV1,
ClientConfig: admissionv1.WebhookClientConfig{
Service: &admissionv1.ServiceReference{
Name: "deployment-validation-service",
Namespace: "default",
Path: &webhookPathV1,
},
},
},
},
},
},
}
}

var _ = AfterSuite(func(done Done) {
Expect(env.Stop()).NotTo(HaveOccurred())

Expand Down
6 changes: 4 additions & 2 deletions pkg/envtest/envtest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -779,16 +779,18 @@ var _ = Describe("Test", func() {

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

It("should not raise an error on invalid dir when flag is disabled", func(done Done) {
env = &Environment{ErrorIfCRDPathMissing: false, CRDDirectoryPaths: []string{invalidDirectory}}
env := &Environment{ErrorIfCRDPathMissing: false, CRDDirectoryPaths: []string{invalidDirectory}}
_, err := env.Start()
Expect(err).NotTo(HaveOccurred())
Expect(env.Stop()).To(Succeed())
close(done)
}, 30)
})
Expand Down
14 changes: 14 additions & 0 deletions pkg/envtest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ type Environment struct {
// CRDInstallOptions are the options for installing CRDs.
CRDInstallOptions CRDInstallOptions

// CRDInstallOptions are the options for installing webhooks.
WebhookInstallOptions WebhookInstallOptions

// ErrorIfCRDPathMissing provides an interface for the underlying
// CRDInstallOptions.ErrorIfPathMissing. It prevents silent failures
// for missing CRD paths.
Expand Down Expand Up @@ -137,6 +140,10 @@ func (te *Environment) Stop() error {
if te.useExistingCluster() {
return nil
}
err := te.WebhookInstallOptions.Cleanup()
if err != nil {
return err
}
return te.ControlPlane.Stop()
}

Expand Down Expand Up @@ -240,7 +247,14 @@ func (te *Environment) Start() (*rest.Config, error) {
te.CRDInstallOptions.Paths = mergePaths(te.CRDInstallOptions.Paths, te.CRDDirectoryPaths)
te.CRDInstallOptions.ErrorIfPathMissing = te.ErrorIfCRDPathMissing
crds, err := InstallCRDs(te.Config, te.CRDInstallOptions)
if err != nil {
return te.Config, err
}
te.CRDs = crds

log.V(1).Info("installing webhooks")
err = te.WebhookInstallOptions.Install(te.Config)

return te.Config, err
}

Expand Down
Loading

0 comments on commit bfc9827

Please sign in to comment.