Cleanup CRD/CR confusion in webhook e2e tests

pull/8/head
jennybuckley 2018-04-03 15:14:30 -07:00
parent 6c96dfd81e
commit 3fcc269733
4 changed files with 54 additions and 39 deletions

View File

@ -52,15 +52,16 @@ const (
roleBindingName = "webhook-auth-reader" roleBindingName = "webhook-auth-reader"
// The webhook configuration names should not be reused between test instances. // The webhook configuration names should not be reused between test instances.
crdWebhookConfigName = "e2e-test-webhook-config-crd" crWebhookConfigName = "e2e-test-webhook-config-cr"
webhookConfigName = "e2e-test-webhook-config" webhookConfigName = "e2e-test-webhook-config"
mutatingWebhookConfigName = "e2e-test-mutating-webhook-config" mutatingWebhookConfigName = "e2e-test-mutating-webhook-config"
podMutatingWebhookConfigName = "e2e-test-mutating-webhook-pod" podMutatingWebhookConfigName = "e2e-test-mutating-webhook-pod"
crdMutatingWebhookConfigName = "e2e-test-mutating-webhook-config-crd" crMutatingWebhookConfigName = "e2e-test-mutating-webhook-config-cr"
webhookFailClosedConfigName = "e2e-test-webhook-fail-closed" webhookFailClosedConfigName = "e2e-test-webhook-fail-closed"
webhookForWebhooksConfigName = "e2e-test-webhook-for-webhooks-config" webhookForWebhooksConfigName = "e2e-test-webhook-for-webhooks-config"
removableValidatingHookName = "e2e-test-should-be-removable-validating-webhook-config" removableValidatingHookName = "e2e-test-should-be-removable-validating-webhook-config"
removableMutatingHookName = "e2e-test-should-be-removable-mutating-webhook-config" removableMutatingHookName = "e2e-test-should-be-removable-mutating-webhook-config"
crdWebhookConfigName = "e2e-test-webhook-config-crd"
skipNamespaceLabelKey = "skip-webhook-admission" skipNamespaceLabelKey = "skip-webhook-admission"
skipNamespaceLabelValue = "yes" skipNamespaceLabelValue = "yes"
@ -72,6 +73,8 @@ const (
failNamespaceLabelKey = "fail-closed-webhook" failNamespaceLabelKey = "fail-closed-webhook"
failNamespaceLabelValue = "yes" failNamespaceLabelValue = "yes"
failNamespaceName = "fail-closed-namesapce" failNamespaceName = "fail-closed-namesapce"
disallowedCrdLabelKey = "disallowed-crd"
disallowedCrdLabelValue = "yes"
) )
var serverWebhookVersion = utilversion.MustParseSemantic("v1.8.0") var serverWebhookVersion = utilversion.MustParseSemantic("v1.8.0")
@ -122,9 +125,9 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
return return
} }
defer testcrd.CleanUp() defer testcrd.CleanUp()
webhookCleanup := registerWebhookForCRD(f, context, testcrd) webhookCleanup := registerWebhookForCustomResource(f, context, testcrd)
defer webhookCleanup() defer webhookCleanup()
testCRDWebhook(f, testcrd.Crd, testcrd.DynamicClient) testCustomResourceWebhook(f, testcrd.Crd, testcrd.DynamicClient)
}) })
It("Should unconditionally reject operations on fail closed webhook", func() { It("Should unconditionally reject operations on fail closed webhook", func() {
@ -151,15 +154,15 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
testWebhookForWebhookConfigurations(f) testWebhookForWebhookConfigurations(f)
}) })
It("Should mutate crd", func() { It("Should mutate custom resource", func() {
testcrd, err := framework.CreateTestCRD(f) testcrd, err := framework.CreateTestCRD(f)
if err != nil { if err != nil {
return return
} }
defer testcrd.CleanUp() defer testcrd.CleanUp()
webhookCleanup := registerMutatingWebhookForCRD(f, context, testcrd) webhookCleanup := registerMutatingWebhookForCustomResource(f, context, testcrd)
defer webhookCleanup() defer webhookCleanup()
testMutatingCRDWebhook(f, testcrd.Crd, testcrd.DynamicClient) testMutatingCustomResourceWebhook(f, testcrd.Crd, testcrd.DynamicClient)
}) })
It("Should deny crd creation", func() { It("Should deny crd creation", func() {
@ -980,19 +983,19 @@ func cleanWebhookTest(client clientset.Interface, namespaceName string) {
_ = client.RbacV1beta1().RoleBindings("kube-system").Delete(roleBindingName, nil) _ = client.RbacV1beta1().RoleBindings("kube-system").Delete(roleBindingName, nil)
} }
func registerWebhookForCRD(f *framework.Framework, context *certContext, testcrd *framework.TestCrd) func() { func registerWebhookForCustomResource(f *framework.Framework, context *certContext, testcrd *framework.TestCrd) func() {
client := f.ClientSet client := f.ClientSet
By("Registering the crd webhook via the AdmissionRegistration API") By("Registering the custom resource webhook via the AdmissionRegistration API")
namespace := f.Namespace.Name namespace := f.Namespace.Name
configName := crdWebhookConfigName configName := crWebhookConfigName
_, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{ _, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: configName, Name: configName,
}, },
Webhooks: []v1beta1.Webhook{ Webhooks: []v1beta1.Webhook{
{ {
Name: "deny-unwanted-crd-data.k8s.io", Name: "deny-unwanted-custom-resource-data.k8s.io",
Rules: []v1beta1.RuleWithOperations{{ Rules: []v1beta1.RuleWithOperations{{
Operations: []v1beta1.OperationType{v1beta1.Create}, Operations: []v1beta1.OperationType{v1beta1.Create},
Rule: v1beta1.Rule{ Rule: v1beta1.Rule{
@ -1005,14 +1008,14 @@ func registerWebhookForCRD(f *framework.Framework, context *certContext, testcrd
Service: &v1beta1.ServiceReference{ Service: &v1beta1.ServiceReference{
Namespace: namespace, Namespace: namespace,
Name: serviceName, Name: serviceName,
Path: strPtr("/crd"), Path: strPtr("/custom-resource"),
}, },
CABundle: context.signingCert, CABundle: context.signingCert,
}, },
}, },
}, },
}) })
framework.ExpectNoError(err, "registering crd webhook config %s with namespace %s", configName, namespace) framework.ExpectNoError(err, "registering custom resource webhook config %s with namespace %s", configName, namespace)
// The webhook configuration is honored in 10s. // The webhook configuration is honored in 10s.
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
@ -1021,19 +1024,19 @@ func registerWebhookForCRD(f *framework.Framework, context *certContext, testcrd
} }
} }
func registerMutatingWebhookForCRD(f *framework.Framework, context *certContext, testcrd *framework.TestCrd) func() { func registerMutatingWebhookForCustomResource(f *framework.Framework, context *certContext, testcrd *framework.TestCrd) func() {
client := f.ClientSet client := f.ClientSet
By("Registering the mutating webhook for crd via the AdmissionRegistration API") By("Registering the mutating webhook for a custom resource via the AdmissionRegistration API")
namespace := f.Namespace.Name namespace := f.Namespace.Name
configName := crdMutatingWebhookConfigName configName := crMutatingWebhookConfigName
_, err := client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&v1beta1.MutatingWebhookConfiguration{ _, err := client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&v1beta1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: configName, Name: configName,
}, },
Webhooks: []v1beta1.Webhook{ Webhooks: []v1beta1.Webhook{
{ {
Name: "mutate-crd-data-stage-1.k8s.io", Name: "mutate-custom-resource-data-stage-1.k8s.io",
Rules: []v1beta1.RuleWithOperations{{ Rules: []v1beta1.RuleWithOperations{{
Operations: []v1beta1.OperationType{v1beta1.Create}, Operations: []v1beta1.OperationType{v1beta1.Create},
Rule: v1beta1.Rule{ Rule: v1beta1.Rule{
@ -1046,13 +1049,13 @@ func registerMutatingWebhookForCRD(f *framework.Framework, context *certContext,
Service: &v1beta1.ServiceReference{ Service: &v1beta1.ServiceReference{
Namespace: namespace, Namespace: namespace,
Name: serviceName, Name: serviceName,
Path: strPtr("/mutating-crd"), Path: strPtr("/mutating-custom-resource"),
}, },
CABundle: context.signingCert, CABundle: context.signingCert,
}, },
}, },
{ {
Name: "mutate-crd-data-stage-2.k8s.io", Name: "mutate-custom-resource-data-stage-2.k8s.io",
Rules: []v1beta1.RuleWithOperations{{ Rules: []v1beta1.RuleWithOperations{{
Operations: []v1beta1.OperationType{v1beta1.Create}, Operations: []v1beta1.OperationType{v1beta1.Create},
Rule: v1beta1.Rule{ Rule: v1beta1.Rule{
@ -1065,14 +1068,14 @@ func registerMutatingWebhookForCRD(f *framework.Framework, context *certContext,
Service: &v1beta1.ServiceReference{ Service: &v1beta1.ServiceReference{
Namespace: namespace, Namespace: namespace,
Name: serviceName, Name: serviceName,
Path: strPtr("/mutating-crd"), Path: strPtr("/mutating-custom-resource"),
}, },
CABundle: context.signingCert, CABundle: context.signingCert,
}, },
}, },
}, },
}) })
framework.ExpectNoError(err, "registering crd webhook config %s with namespace %s", configName, namespace) framework.ExpectNoError(err, "registering custom resource webhook config %s with namespace %s", configName, namespace)
// The webhook configuration is honored in 10s. // The webhook configuration is honored in 10s.
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
@ -1080,7 +1083,7 @@ func registerMutatingWebhookForCRD(f *framework.Framework, context *certContext,
return func() { client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(configName, nil) } return func() { client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(configName, nil) }
} }
func testCRDWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, crdClient dynamic.ResourceInterface) { func testCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.ResourceInterface) {
By("Creating a custom resource that should be denied by the webhook") By("Creating a custom resource that should be denied by the webhook")
crInstance := &unstructured.Unstructured{ crInstance := &unstructured.Unstructured{
Object: map[string]interface{}{ Object: map[string]interface{}{
@ -1095,7 +1098,7 @@ func testCRDWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomReso
}, },
}, },
} }
_, err := crdClient.Create(crInstance) _, err := customResourceClient.Create(crInstance)
Expect(err).NotTo(BeNil()) Expect(err).NotTo(BeNil())
expectedErrMsg := "the custom resource contains unwanted data" expectedErrMsg := "the custom resource contains unwanted data"
if !strings.Contains(err.Error(), expectedErrMsg) { if !strings.Contains(err.Error(), expectedErrMsg) {
@ -1103,7 +1106,7 @@ func testCRDWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomReso
} }
} }
func testMutatingCRDWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, crdClient dynamic.ResourceInterface) { func testMutatingCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.ResourceInterface) {
By("Creating a custom resource that should be mutated by the webhook") By("Creating a custom resource that should be mutated by the webhook")
cr := &unstructured.Unstructured{ cr := &unstructured.Unstructured{
Object: map[string]interface{}{ Object: map[string]interface{}{
@ -1118,7 +1121,7 @@ func testMutatingCRDWebhook(f *framework.Framework, crd *apiextensionsv1beta1.Cu
}, },
}, },
} }
mutatedCR, err := crdClient.Create(cr) mutatedCR, err := customResourceClient.Create(cr)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
expectedCRData := map[string]interface{}{ expectedCRData := map[string]interface{}{
"mutation-start": "yes", "mutation-start": "yes",
@ -1135,7 +1138,7 @@ func registerValidatingWebhookForCRD(f *framework.Framework, context *certContex
By("Registering the crd webhook via the AdmissionRegistration API") By("Registering the crd webhook via the AdmissionRegistration API")
namespace := f.Namespace.Name namespace := f.Namespace.Name
configName := webhookConfigName configName := crdWebhookConfigName
_, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{ _, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: configName, Name: configName,
@ -1151,6 +1154,15 @@ func registerValidatingWebhookForCRD(f *framework.Framework, context *certContex
Resources: []string{"customresourcedefinitions"}, Resources: []string{"customresourcedefinitions"},
}, },
}}, }},
NamespaceSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: disallowedCrdLabelKey,
Operator: metav1.LabelSelectorOpIn,
Values: []string{disallowedCrdLabelValue},
},
},
},
ClientConfig: v1beta1.WebhookClientConfig{ ClientConfig: v1beta1.WebhookClientConfig{
Service: &v1beta1.ServiceReference{ Service: &v1beta1.ServiceReference{
Namespace: namespace, Namespace: namespace,
@ -1196,7 +1208,10 @@ func testCRDDenyWebhook(f *framework.Framework) {
return return
} }
crd := &apiextensionsv1beta1.CustomResourceDefinition{ crd := &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: testcrd.GetMetaName()}, ObjectMeta: metav1.ObjectMeta{
Name: testcrd.GetMetaName(),
Labels: map[string]string{disallowedCrdLabelKey: disallowedCrdLabelValue},
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: testcrd.ApiGroup, Group: testcrd.ApiGroup,
Version: testcrd.ApiVersion, Version: testcrd.ApiVersion,

View File

@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
IMAGE = gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64 IMAGE = gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64
TAG = 1.9v2 TAG = 1.10v1
build: build:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o webhook . CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o webhook .

View File

@ -204,8 +204,8 @@ func mutateConfigmaps(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
return &reviewResponse return &reviewResponse
} }
func mutateCRD(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse { func mutateCustomResource(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
glog.V(2).Info("mutating crd") glog.V(2).Info("mutating custom resource")
cr := struct { cr := struct {
metav1.ObjectMeta metav1.ObjectMeta
Data map[string]string Data map[string]string
@ -232,8 +232,8 @@ func mutateCRD(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
return &reviewResponse return &reviewResponse
} }
func admitCRD(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse { func admitCustomResource(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
glog.V(2).Info("admitting crd") glog.V(2).Info("admitting custom resource")
cr := struct { cr := struct {
metav1.ObjectMeta metav1.ObjectMeta
Data map[string]string Data map[string]string
@ -324,12 +324,12 @@ func serveMutateConfigmaps(w http.ResponseWriter, r *http.Request) {
serve(w, r, mutateConfigmaps) serve(w, r, mutateConfigmaps)
} }
func serveCRD(w http.ResponseWriter, r *http.Request) { func serveCustomResource(w http.ResponseWriter, r *http.Request) {
serve(w, r, admitCRD) serve(w, r, admitCustomResource)
} }
func serveMutateCRD(w http.ResponseWriter, r *http.Request) { func serveMutateCustomResource(w http.ResponseWriter, r *http.Request) {
serve(w, r, mutateCRD) serve(w, r, mutateCustomResource)
} }
func main() { func main() {
@ -342,8 +342,8 @@ func main() {
http.HandleFunc("/mutating-pods", serveMutatePods) http.HandleFunc("/mutating-pods", serveMutatePods)
http.HandleFunc("/configmaps", serveConfigmaps) http.HandleFunc("/configmaps", serveConfigmaps)
http.HandleFunc("/mutating-configmaps", serveMutateConfigmaps) http.HandleFunc("/mutating-configmaps", serveMutateConfigmaps)
http.HandleFunc("/crd", serveCRD) http.HandleFunc("/custom-resource", serveCustomResource)
http.HandleFunc("/mutating-crd", serveMutateCRD) http.HandleFunc("/mutating-custom-resource", serveMutateCustomResource)
clientset := getClient() clientset := getClient()
server := &http.Server{ server := &http.Server{
Addr: ":443", Addr: ":443",

View File

@ -48,7 +48,7 @@ func (i *ImageConfig) SetVersion(version string) {
} }
var ( var (
AdmissionWebhook = ImageConfig{e2eRegistry, "k8s-sample-admission-webhook", "1.9v2", true} AdmissionWebhook = ImageConfig{e2eRegistry, "k8s-sample-admission-webhook", "1.10v1", true}
APIServer = ImageConfig{e2eRegistry, "k8s-aggregator-sample-apiserver", "1.7v2", true} APIServer = ImageConfig{e2eRegistry, "k8s-aggregator-sample-apiserver", "1.7v2", true}
AppArmorLoader = ImageConfig{gcRegistry, "apparmor-loader", "0.1", false} AppArmorLoader = ImageConfig{gcRegistry, "apparmor-loader", "0.1", false}
BusyBox = ImageConfig{gcRegistry, "busybox", "1.24", false} BusyBox = ImageConfig{gcRegistry, "busybox", "1.24", false}