mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
vendor update for CSI 0.3.0
This commit is contained in:
7
vendor/k8s.io/kubernetes/test/e2e/apimachinery/BUILD
generated
vendored
7
vendor/k8s.io/kubernetes/test/e2e/apimachinery/BUILD
generated
vendored
@ -11,6 +11,7 @@ go_library(
|
||||
"aggregator.go",
|
||||
"certs.go",
|
||||
"chunking.go",
|
||||
"crd_watch.go",
|
||||
"custom_resource_definition.go",
|
||||
"etcd_failure.go",
|
||||
"framework.go",
|
||||
@ -19,12 +20,12 @@ go_library(
|
||||
"initializers.go",
|
||||
"namespace.go",
|
||||
"table_conversion.go",
|
||||
"watch.go",
|
||||
"webhook.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/test/e2e/apimachinery",
|
||||
deps = [
|
||||
"//pkg/api/v1/pod:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
@ -38,6 +39,7 @@ go_library(
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/api/admissionregistration/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/api/admissionregistration/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/authorization/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
|
||||
@ -47,7 +49,9 @@ go_library(
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/test/integration/testserver:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
|
||||
@ -55,6 +59,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
|
84
vendor/k8s.io/kubernetes/test/e2e/apimachinery/aggregator.go
generated
vendored
84
vendor/k8s.io/kubernetes/test/e2e/apimachinery/aggregator.go
generated
vendored
@ -24,8 +24,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -87,7 +87,7 @@ func cleanTest(client clientset.Interface, aggrclient *aggregatorclient.Clientse
|
||||
// delete the APIService first to avoid causing discovery errors
|
||||
_ = aggrclient.ApiregistrationV1beta1().APIServices().Delete("v1alpha1.wardle.k8s.io", nil)
|
||||
|
||||
_ = client.ExtensionsV1beta1().Deployments(namespace).Delete("sample-apiserver", nil)
|
||||
_ = client.AppsV1().Deployments(namespace).Delete("sample-apiserver", nil)
|
||||
_ = client.CoreV1().Secrets(namespace).Delete("sample-apiserver-secret", nil)
|
||||
_ = client.CoreV1().Services(namespace).Delete("sample-api", nil)
|
||||
_ = client.CoreV1().ServiceAccounts(namespace).Delete("sample-apiserver", nil)
|
||||
@ -133,7 +133,7 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
|
||||
// kubectl create -f deploy.yaml
|
||||
deploymentName := "sample-apiserver-deployment"
|
||||
etcdImage := "quay.io/coreos/etcd:v3.2.14"
|
||||
etcdImage := "quay.io/coreos/etcd:v3.2.18"
|
||||
podLabels := map[string]string{"app": "sample-apiserver", "apiserver": "true"}
|
||||
replicas := int32(1)
|
||||
zero := int64(0)
|
||||
@ -171,14 +171,18 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
Image: etcdImage,
|
||||
},
|
||||
}
|
||||
d := &extensions.Deployment{
|
||||
d := &apps.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deploymentName,
|
||||
Name: deploymentName,
|
||||
Labels: podLabels,
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Spec: apps.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Strategy: extensions.DeploymentStrategy{
|
||||
Type: extensions.RollingUpdateDeploymentStrategyType,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: podLabels,
|
||||
},
|
||||
Strategy: apps.DeploymentStrategy{
|
||||
Type: apps.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -192,7 +196,7 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
},
|
||||
},
|
||||
}
|
||||
deployment, err := client.ExtensionsV1beta1().Deployments(namespace).Create(d)
|
||||
deployment, err := client.AppsV1().Deployments(namespace).Create(d)
|
||||
framework.ExpectNoError(err, "creating deployment %s in namespace %s", deploymentName, namespace)
|
||||
err = framework.WaitForDeploymentRevisionAndImage(client, namespace, deploymentName, "1", image)
|
||||
framework.ExpectNoError(err, "waiting for the deployment of image %s in %s in %s to complete", image, deploymentName, namespace)
|
||||
@ -315,7 +319,16 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
})
|
||||
framework.ExpectNoError(err, "creating apiservice %s with namespace %s", "v1alpha1.wardle.k8s.io", namespace)
|
||||
|
||||
err = wait.Poll(100*time.Millisecond, 30*time.Second, func() (bool, error) {
|
||||
var (
|
||||
currentAPIService *apiregistrationv1beta1.APIService
|
||||
currentPods *v1.PodList
|
||||
)
|
||||
|
||||
err = pollTimed(100*time.Millisecond, 60*time.Second, func() (bool, error) {
|
||||
|
||||
currentAPIService, _ = aggrclient.ApiregistrationV1beta1().APIServices().Get("v1alpha1.wardle.k8s.io", metav1.GetOptions{})
|
||||
currentPods, _ = client.CoreV1().Pods(namespace).List(metav1.ListOptions{})
|
||||
|
||||
request := restClient.Get().AbsPath("/apis/wardle.k8s.io/v1alpha1/namespaces/default/flunders")
|
||||
request.SetHeader("Accept", "application/json")
|
||||
_, err := request.DoRaw()
|
||||
@ -333,7 +346,23 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
}, "Waited %s for the sample-apiserver to be ready to handle requests.")
|
||||
if err != nil {
|
||||
currentAPIServiceJSON, _ := json.Marshal(currentAPIService)
|
||||
framework.Logf("current APIService: %s", string(currentAPIServiceJSON))
|
||||
|
||||
currentPodsJSON, _ := json.Marshal(currentPods)
|
||||
framework.Logf("current pods: %s", string(currentPodsJSON))
|
||||
|
||||
if currentPods != nil {
|
||||
for _, pod := range currentPods.Items {
|
||||
for _, container := range pod.Spec.Containers {
|
||||
logs, err := framework.GetPodLogs(client, namespace, pod.Name, container.Name)
|
||||
framework.Logf("logs of %s/%s (error: %v): %s", pod.Name, container.Name, err, logs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
framework.ExpectNoError(err, "gave up waiting for apiservice wardle to come up successfully")
|
||||
|
||||
flunderName := generateFlunderName("rest-flunder")
|
||||
@ -382,19 +411,15 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
flunderName = generateFlunderName("dynamic-flunder")
|
||||
|
||||
// Rerun the Create/List/Delete tests using the Dynamic client.
|
||||
resources, err := client.Discovery().ServerPreferredNamespacedResources()
|
||||
framework.ExpectNoError(err, "getting server preferred namespaces resources for dynamic client")
|
||||
resources, discoveryErr := client.Discovery().ServerPreferredNamespacedResources()
|
||||
groupVersionResources, err := discovery.GroupVersionResources(resources)
|
||||
framework.ExpectNoError(err, "getting group version resources for dynamic client")
|
||||
gvr := schema.GroupVersionResource{Group: "wardle.k8s.io", Version: "v1alpha1", Resource: "flunders"}
|
||||
_, ok := groupVersionResources[gvr]
|
||||
if !ok {
|
||||
framework.Failf("could not find group version resource for dynamic client and wardle/flunders.")
|
||||
framework.Failf("could not find group version resource for dynamic client and wardle/flunders (discovery error: %v, discovery results: %#v)", discoveryErr, groupVersionResources)
|
||||
}
|
||||
clientPool := f.ClientPool
|
||||
dynamicClient, err := clientPool.ClientForGroupVersionResource(gvr)
|
||||
framework.ExpectNoError(err, "getting group version resources for dynamic client")
|
||||
apiResource := metav1.APIResource{Name: gvr.Resource, Namespaced: true}
|
||||
dynamicClient := f.DynamicClient.Resource(gvr).Namespace(namespace)
|
||||
|
||||
// kubectl create -f flunders-1.yaml
|
||||
// Request Body: {"apiVersion":"wardle.k8s.io/v1alpha1","kind":"Flunder","metadata":{"labels":{"sample-label":"true"},"name":"test-flunder","namespace":"default"}}
|
||||
@ -411,27 +436,23 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
unstruct := &unstructuredv1.Unstructured{}
|
||||
err = unstruct.UnmarshalJSON(jsonFlunder)
|
||||
framework.ExpectNoError(err, "unmarshalling test-flunder as unstructured for create using dynamic client")
|
||||
unstruct, err = dynamicClient.Resource(&apiResource, namespace).Create(unstruct)
|
||||
unstruct, err = dynamicClient.Create(unstruct)
|
||||
framework.ExpectNoError(err, "listing flunders using dynamic client")
|
||||
|
||||
// kubectl get flunders
|
||||
obj, err := dynamicClient.Resource(&apiResource, namespace).List(metav1.ListOptions{})
|
||||
unstructuredList, err := dynamicClient.List(metav1.ListOptions{})
|
||||
framework.ExpectNoError(err, "listing flunders using dynamic client")
|
||||
unstructuredList, ok := obj.(*unstructuredv1.UnstructuredList)
|
||||
validateErrorWithDebugInfo(f, err, pods, "casting flunders list(%T) as unstructuredList using dynamic client", obj)
|
||||
if len(unstructuredList.Items) != 1 {
|
||||
framework.Failf("failed to get back the correct flunders list %v from the dynamic client", unstructuredList)
|
||||
}
|
||||
|
||||
// kubectl delete flunder test-flunder
|
||||
err = dynamicClient.Resource(&apiResource, namespace).Delete(flunderName, &metav1.DeleteOptions{})
|
||||
err = dynamicClient.Delete(flunderName, &metav1.DeleteOptions{})
|
||||
validateErrorWithDebugInfo(f, err, pods, "deleting flunders(%v) using dynamic client", unstructuredList.Items)
|
||||
|
||||
// kubectl get flunders
|
||||
obj, err = dynamicClient.Resource(&apiResource, namespace).List(metav1.ListOptions{})
|
||||
unstructuredList, err = dynamicClient.List(metav1.ListOptions{})
|
||||
framework.ExpectNoError(err, "listing flunders using dynamic client")
|
||||
unstructuredList, ok = obj.(*unstructuredv1.UnstructuredList)
|
||||
validateErrorWithDebugInfo(f, err, pods, "casting flunders list(%T) as unstructuredList using dynamic client", obj)
|
||||
if len(unstructuredList.Items) != 0 {
|
||||
framework.Failf("failed to get back the correct deleted flunders list %v from the dynamic client", unstructuredList)
|
||||
}
|
||||
@ -439,6 +460,17 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
|
||||
cleanTest(client, aggrclient, namespace)
|
||||
}
|
||||
|
||||
// pollTimed will call Poll but time how long Poll actually took.
|
||||
// It will then framework.logf the msg with the duration of the Poll.
|
||||
// It is assumed that msg will contain one %s for the elapsed time.
|
||||
func pollTimed(interval, timeout time.Duration, condition wait.ConditionFunc, msg string) error {
|
||||
defer func(start time.Time, msg string) {
|
||||
elapsed := time.Since(start)
|
||||
framework.Logf(msg, elapsed)
|
||||
}(time.Now(), msg)
|
||||
return wait.Poll(interval, timeout, condition)
|
||||
}
|
||||
|
||||
func validateErrorWithDebugInfo(f *framework.Framework, err error, pods *v1.PodList, msg string, fields ...interface{}) {
|
||||
if err != nil {
|
||||
namespace := f.Namespace.Name
|
||||
|
166
vendor/k8s.io/kubernetes/test/e2e/apimachinery/crd_watch.go
generated
vendored
Normal file
166
vendor/k8s.io/kubernetes/test/e2e/apimachinery/crd_watch.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apimachinery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apiextensions-apiserver/test/integration/testserver"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = SIGDescribe("CustomResourceDefinition Watch", func() {
|
||||
|
||||
f := framework.NewDefaultFramework("crd-watch")
|
||||
|
||||
Context("CustomResourceDefinition Watch", func() {
|
||||
/*
|
||||
Testname: crd-watch
|
||||
Description: Create a Custom Resource Definition and make sure
|
||||
watches observe events on create/delete.
|
||||
*/
|
||||
It("watch on custom resource definition objects", func() {
|
||||
|
||||
framework.SkipUnlessServerVersionGTE(crdVersion, f.ClientSet.Discovery())
|
||||
|
||||
const (
|
||||
watchCRNameA = "name1"
|
||||
watchCRNameB = "name2"
|
||||
)
|
||||
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
apiExtensionClient, err := clientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("failed to initialize apiExtensionClient: %v", err)
|
||||
}
|
||||
|
||||
noxuDefinition := testserver.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
|
||||
noxuDefinition, err = testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, f.DynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("failed to create CustomResourceDefinition: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = testserver.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient)
|
||||
if err != nil {
|
||||
framework.Failf("failed to delete CustomResourceDefinition: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
ns := ""
|
||||
noxuResourceClient := newNamespacedCustomResourceClient(ns, f.DynamicClient, noxuDefinition)
|
||||
|
||||
watchA, err := watchCRWithName(noxuResourceClient, watchCRNameA)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
watchB, err := watchCRWithName(noxuResourceClient, watchCRNameB)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
testCrA := testserver.NewNoxuInstance(ns, watchCRNameA)
|
||||
testCrB := testserver.NewNoxuInstance(ns, watchCRNameB)
|
||||
|
||||
By("Creating first CR ")
|
||||
testCrA, err = instantiateCustomResource(testCrA, noxuResourceClient, noxuDefinition)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchA, watch.Added, testCrA)
|
||||
expectNoEvent(watchB, watch.Added, testCrA)
|
||||
|
||||
By("Creating second CR")
|
||||
testCrB, err = instantiateCustomResource(testCrB, noxuResourceClient, noxuDefinition)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchB, watch.Added, testCrB)
|
||||
expectNoEvent(watchA, watch.Added, testCrB)
|
||||
|
||||
By("Deleting first CR")
|
||||
err = deleteCustomResource(noxuResourceClient, watchCRNameA)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchA, watch.Deleted, nil)
|
||||
expectNoEvent(watchB, watch.Deleted, nil)
|
||||
|
||||
By("Deleting second CR")
|
||||
err = deleteCustomResource(noxuResourceClient, watchCRNameB)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchB, watch.Deleted, nil)
|
||||
expectNoEvent(watchA, watch.Deleted, nil)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func watchCRWithName(crdResourceClient dynamic.ResourceInterface, name string) (watch.Interface, error) {
|
||||
return crdResourceClient.Watch(
|
||||
metav1.ListOptions{
|
||||
FieldSelector: "metadata.name=" + name,
|
||||
TimeoutSeconds: int64ptr(600),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func instantiateCustomResource(instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1beta1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
|
||||
createdInstance, err := client.Create(instanceToCreate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createdObjectMeta, err := meta.Accessor(createdInstance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// it should have a UUID
|
||||
if len(createdObjectMeta.GetUID()) == 0 {
|
||||
return nil, fmt.Errorf("missing uuid: %#v", createdInstance)
|
||||
}
|
||||
createdTypeMeta, err := meta.TypeAccessor(createdInstance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if e, a := definition.Spec.Group+"/"+definition.Spec.Version, createdTypeMeta.GetAPIVersion(); e != a {
|
||||
return nil, fmt.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := definition.Spec.Names.Kind, createdTypeMeta.GetKind(); e != a {
|
||||
return nil, fmt.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
return createdInstance, nil
|
||||
}
|
||||
|
||||
func deleteCustomResource(client dynamic.ResourceInterface, name string) error {
|
||||
return client.Delete(name, &metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
func newNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.ResourceInterface {
|
||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural}
|
||||
|
||||
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
|
||||
return client.Resource(gvr).Namespace(ns)
|
||||
} else {
|
||||
return client.Resource(gvr)
|
||||
}
|
||||
|
||||
}
|
2
vendor/k8s.io/kubernetes/test/e2e/apimachinery/custom_resource_definition.go
generated
vendored
2
vendor/k8s.io/kubernetes/test/e2e/apimachinery/custom_resource_definition.go
generated
vendored
@ -55,7 +55,7 @@ var _ = SIGDescribe("CustomResourceDefinition resources", func() {
|
||||
randomDefinition := testserver.NewRandomNameCustomResourceDefinition(v1beta1.ClusterScoped)
|
||||
|
||||
//create CRD and waits for the resource to be recognized and available.
|
||||
_, err = testserver.CreateNewCustomResourceDefinition(randomDefinition, apiExtensionClient, f.ClientPool)
|
||||
randomDefinition, err = testserver.CreateNewCustomResourceDefinition(randomDefinition, apiExtensionClient, f.DynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("failed to create CustomResourceDefinition: %v", err)
|
||||
}
|
||||
|
3
vendor/k8s.io/kubernetes/test/e2e/apimachinery/etcd_failure.go
generated
vendored
3
vendor/k8s.io/kubernetes/test/e2e/apimachinery/etcd_failure.go
generated
vendored
@ -26,6 +26,7 @@ import (
|
||||
"k8s.io/kubernetes/test/e2e/apps"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
testutils "k8s.io/kubernetes/test/utils"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -47,7 +48,7 @@ var _ = SIGDescribe("Etcd failure [Disruptive]", func() {
|
||||
Client: f.ClientSet,
|
||||
Name: "baz",
|
||||
Namespace: f.Namespace.Name,
|
||||
Image: framework.GetPauseImageName(f.ClientSet),
|
||||
Image: imageutils.GetPauseImageName(),
|
||||
Replicas: 1,
|
||||
})).NotTo(HaveOccurred())
|
||||
})
|
||||
|
228
vendor/k8s.io/kubernetes/test/e2e/apimachinery/garbage_collector.go
generated
vendored
228
vendor/k8s.io/kubernetes/test/e2e/apimachinery/garbage_collector.go
generated
vendored
@ -18,6 +18,7 @@ package apimachinery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
@ -32,10 +33,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
"k8s.io/kubernetes/test/e2e/framework/metrics"
|
||||
|
||||
@ -88,8 +89,8 @@ func getOrphanOptions() *metav1.DeleteOptions {
|
||||
}
|
||||
|
||||
var (
|
||||
zero = int64(0)
|
||||
|
||||
zero = int64(0)
|
||||
lablecount = int64(0)
|
||||
CronJobGroupVersionResource = schema.GroupVersionResource{Group: batchv1beta1.GroupName, Version: "v1beta1", Resource: "cronjobs"}
|
||||
)
|
||||
|
||||
@ -175,7 +176,7 @@ func verifyRemainingDeploymentsReplicaSetsPods(
|
||||
}
|
||||
if len(deployments.Items) != deploymentNum {
|
||||
ret = false
|
||||
By(fmt.Sprintf("expected %d Deploymentss, got %d Deployments", deploymentNum, len(deployments.Items)))
|
||||
By(fmt.Sprintf("expected %d Deployments, got %d Deployments", deploymentNum, len(deployments.Items)))
|
||||
}
|
||||
pods, err := clientSet.CoreV1().Pods(f.Namespace.Name).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
@ -323,6 +324,14 @@ func newCronJob(name, schedule string) *batchv1beta1.CronJob {
|
||||
}
|
||||
}
|
||||
|
||||
// getUniqLabel returns a UniqLabel based on labeLkey and labelvalue.
|
||||
func getUniqLabel(labelkey, labelvalue string) map[string]string {
|
||||
count := atomic.AddInt64(&lablecount, 1)
|
||||
uniqlabelkey := fmt.Sprintf("%s-%05d", labelkey, count)
|
||||
uniqlabelvalue := fmt.Sprintf("%s-%05d", labelvalue, count)
|
||||
return map[string]string{uniqlabelkey: uniqlabelvalue}
|
||||
}
|
||||
|
||||
var _ = SIGDescribe("Garbage collector", func() {
|
||||
f := framework.NewDefaultFramework("gc")
|
||||
|
||||
@ -337,8 +346,7 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
|
||||
podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
|
||||
rcName := "simpletest.rc"
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels := map[string]string{"gctest": "delete_pods"}
|
||||
uniqLabels := getUniqLabel("gctest", "delete_pods")
|
||||
rc := newOwnerRC(f, rcName, 2, uniqLabels)
|
||||
By("create the rc")
|
||||
rc, err := rcClient.Create(rc)
|
||||
@ -396,8 +404,7 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
|
||||
podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
|
||||
rcName := "simpletest.rc"
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels := map[string]string{"gctest": "orphan_pods"}
|
||||
uniqLabels := getUniqLabel("gctest", "orphan_pods")
|
||||
rc := newOwnerRC(f, rcName, estimateMaximumPods(clientSet, 10, 100), uniqLabels)
|
||||
By("create the rc")
|
||||
rc, err := rcClient.Create(rc)
|
||||
@ -445,17 +452,13 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
framework.Failf("%v", err)
|
||||
}
|
||||
By("wait for 30 seconds to see if the garbage collector mistakenly deletes the pods")
|
||||
if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
|
||||
pods, err := podClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to list pods: %v", err)
|
||||
}
|
||||
if e, a := int(*(rc.Spec.Replicas)), len(pods.Items); e != a {
|
||||
return false, fmt.Errorf("expect %d pods, got %d pods", e, a)
|
||||
}
|
||||
return false, nil
|
||||
}); err != nil && err != wait.ErrWaitTimeout {
|
||||
framework.Failf("%v", err)
|
||||
time.Sleep(30 * time.Second)
|
||||
pods, err := podClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("Failed to list pods: %v", err)
|
||||
}
|
||||
if e, a := int(*(rc.Spec.Replicas)), len(pods.Items); e != a {
|
||||
framework.Failf("expect %d pods, got %d pods", e, a)
|
||||
}
|
||||
gatherMetrics(f)
|
||||
})
|
||||
@ -465,8 +468,7 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
|
||||
podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
|
||||
rcName := "simpletest.rc"
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels := map[string]string{"gctest": "orphan_pods_nil_option"}
|
||||
uniqLabels := getUniqLabel("gctest", "orphan_pods_nil_option")
|
||||
rc := newOwnerRC(f, rcName, 2, uniqLabels)
|
||||
By("create the rc")
|
||||
rc, err := rcClient.Create(rc)
|
||||
@ -494,17 +496,13 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
framework.Failf("failed to delete the rc: %v", err)
|
||||
}
|
||||
By("wait for 30 seconds to see if the garbage collector mistakenly deletes the pods")
|
||||
if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
|
||||
pods, err := podClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to list pods: %v", err)
|
||||
}
|
||||
if e, a := int(*(rc.Spec.Replicas)), len(pods.Items); e != a {
|
||||
return false, fmt.Errorf("expect %d pods, got %d pods", e, a)
|
||||
}
|
||||
return false, nil
|
||||
}); err != nil && err != wait.ErrWaitTimeout {
|
||||
framework.Failf("%v", err)
|
||||
time.Sleep(30 * time.Second)
|
||||
pods, err := podClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("Failed to list pods: %v", err)
|
||||
}
|
||||
if e, a := int(*(rc.Spec.Replicas)), len(pods.Items); e != a {
|
||||
framework.Failf("expect %d pods, got %d pods", e, a)
|
||||
}
|
||||
gatherMetrics(f)
|
||||
})
|
||||
@ -520,8 +518,7 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
deployClient := clientSet.ExtensionsV1beta1().Deployments(f.Namespace.Name)
|
||||
rsClient := clientSet.ExtensionsV1beta1().ReplicaSets(f.Namespace.Name)
|
||||
deploymentName := "simpletest.deployment"
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels := map[string]string{"gctest": "delete_rs"}
|
||||
uniqLabels := getUniqLabel("gctest", "delete_rs")
|
||||
deployment := newOwnerDeployment(f, deploymentName, uniqLabels)
|
||||
By("create the deployment")
|
||||
createdDeployment, err := deployClient.Create(deployment)
|
||||
@ -552,14 +549,17 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
err = wait.PollImmediate(500*time.Millisecond, 1*time.Minute, func() (bool, error) {
|
||||
return verifyRemainingDeploymentsReplicaSetsPods(f, clientSet, deployment, 0, 0, 0)
|
||||
})
|
||||
if err == wait.ErrWaitTimeout {
|
||||
err = fmt.Errorf("Failed to wait for all rs to be garbage collected: %v", err)
|
||||
if err != nil {
|
||||
errList := make([]error, 0)
|
||||
errList = append(errList, err)
|
||||
remainingRSs, err := rsClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("failed to list RSs post mortem: %v", err)
|
||||
errList = append(errList, fmt.Errorf("failed to list RSs post mortem: %v", err))
|
||||
} else {
|
||||
framework.Failf("remaining rs are: %#v", remainingRSs)
|
||||
errList = append(errList, fmt.Errorf("remaining rs are: %#v", remainingRSs))
|
||||
}
|
||||
aggregatedError := utilerrors.NewAggregate(errList)
|
||||
framework.Failf("Failed to wait for all rs to be garbage collected: %v", aggregatedError)
|
||||
|
||||
}
|
||||
|
||||
@ -577,8 +577,7 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
deployClient := clientSet.ExtensionsV1beta1().Deployments(f.Namespace.Name)
|
||||
rsClient := clientSet.ExtensionsV1beta1().ReplicaSets(f.Namespace.Name)
|
||||
deploymentName := "simpletest.deployment"
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels := map[string]string{"gctest": "orphan_rs"}
|
||||
uniqLabels := getUniqLabel("gctest", "orphan_rs")
|
||||
deployment := newOwnerDeployment(f, deploymentName, uniqLabels)
|
||||
By("create the deployment")
|
||||
createdDeployment, err := deployClient.Create(deployment)
|
||||
@ -605,24 +604,28 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
if err := deployClient.Delete(deployment.ObjectMeta.Name, deleteOptions); err != nil {
|
||||
framework.Failf("failed to delete the deployment: %v", err)
|
||||
}
|
||||
By("wait for 2 Minute to see if the garbage collector mistakenly deletes the rs")
|
||||
err = wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) {
|
||||
return verifyRemainingDeploymentsReplicaSetsPods(f, clientSet, deployment, 0, 1, 2)
|
||||
})
|
||||
By("wait for 30 seconds to see if the garbage collector mistakenly deletes the rs")
|
||||
time.Sleep(30 * time.Second)
|
||||
ok, err := verifyRemainingDeploymentsReplicaSetsPods(f, clientSet, deployment, 0, 1, 2)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed to wait to see if the garbage collecter mistakenly deletes the rs: %v", err)
|
||||
framework.Failf("Unexpected error while verifying remaining deployments, rs, and pods: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
errList := make([]error, 0)
|
||||
remainingRSs, err := rsClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("failed to list RSs post mortem: %v", err)
|
||||
errList = append(errList, fmt.Errorf("failed to list RSs post mortem: %v", err))
|
||||
} else {
|
||||
framework.Failf("remaining rs post mortem: %#v", remainingRSs)
|
||||
errList = append(errList, fmt.Errorf("remaining rs post mortem: %#v", remainingRSs))
|
||||
}
|
||||
remainingDSs, err := deployClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("failed to list Deployments post mortem: %v", err)
|
||||
errList = append(errList, fmt.Errorf("failed to list Deployments post mortem: %v", err))
|
||||
} else {
|
||||
framework.Failf("remaining deployment's post mortem: %#v", remainingDSs)
|
||||
errList = append(errList, fmt.Errorf("remaining deployment's post mortem: %#v", remainingDSs))
|
||||
}
|
||||
aggregatedError := utilerrors.NewAggregate(errList)
|
||||
framework.Failf("Failed to verify remaining deployments, rs, and pods: %v", aggregatedError)
|
||||
}
|
||||
rs, err := clientSet.ExtensionsV1beta1().ReplicaSets(f.Namespace.Name).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
@ -647,8 +650,7 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
|
||||
podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
|
||||
rcName := "simpletest.rc"
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels := map[string]string{"gctest": "delete_pods_foreground"}
|
||||
uniqLabels := getUniqLabel("gctest", "delete_pods_foreground")
|
||||
rc := newOwnerRC(f, rcName, estimateMaximumPods(clientSet, 10, 100), uniqLabels)
|
||||
By("create the rc")
|
||||
rc, err := rcClient.Create(rc)
|
||||
@ -738,18 +740,16 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
rc1Name := "simpletest-rc-to-be-deleted"
|
||||
replicas := int32(estimateMaximumPods(clientSet, 10, 100))
|
||||
halfReplicas := int(replicas / 2)
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels := map[string]string{"gctest": "valid_and_pending_owners"}
|
||||
rc1 := newOwnerRC(f, rc1Name, replicas, uniqLabels)
|
||||
uniqLabels_deleted := getUniqLabel("gctest_d", "valid_and_pending_owners_d")
|
||||
rc1 := newOwnerRC(f, rc1Name, replicas, uniqLabels_deleted)
|
||||
By("create the rc1")
|
||||
rc1, err := rcClient.Create(rc1)
|
||||
if err != nil {
|
||||
framework.Failf("Failed to create replication controller: %v", err)
|
||||
}
|
||||
rc2Name := "simpletest-rc-to-stay"
|
||||
// TODO: find better way to keep this label unique in the test
|
||||
uniqLabels = map[string]string{"another.key": "another.value"}
|
||||
rc2 := newOwnerRC(f, rc2Name, 0, uniqLabels)
|
||||
uniqLabels_stay := getUniqLabel("gctest_s", "valid_and_pending_owners_s")
|
||||
rc2 := newOwnerRC(f, rc2Name, 0, uniqLabels_stay)
|
||||
By("create the rc2")
|
||||
rc2, err = rcClient.Create(rc2)
|
||||
if err != nil {
|
||||
@ -917,16 +917,15 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
framework.Failf("failed to delete CustomResourceDefinition: %v", err)
|
||||
}
|
||||
}()
|
||||
client, err := apiextensionstestserver.CreateNewCustomResourceDefinition(definition, apiExtensionClient, f.ClientPool)
|
||||
definition, err = apiextensionstestserver.CreateNewCustomResourceDefinition(definition, apiExtensionClient, f.DynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("failed to create CustomResourceDefinition: %v", err)
|
||||
}
|
||||
|
||||
// Get a client for the custom resource.
|
||||
resourceClient := client.Resource(&metav1.APIResource{
|
||||
Name: definition.Spec.Names.Plural,
|
||||
Namespaced: false,
|
||||
}, api.NamespaceNone)
|
||||
gvr := schema.GroupVersionResource{Group: definition.Spec.Group, Version: definition.Spec.Version, Resource: definition.Spec.Names.Plural}
|
||||
resourceClient := f.DynamicClient.Resource(gvr)
|
||||
|
||||
apiVersion := definition.Spec.Group + "/" + definition.Spec.Version
|
||||
|
||||
// Create a custom owner resource.
|
||||
@ -999,8 +998,111 @@ var _ = SIGDescribe("Garbage collector", func() {
|
||||
}
|
||||
})
|
||||
|
||||
It("should support orphan deletion of custom resources", func() {
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
apiExtensionClient, err := apiextensionsclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("failed to initialize apiExtensionClient: %v", err)
|
||||
}
|
||||
|
||||
// Create a random custom resource definition and ensure it's available for
|
||||
// use.
|
||||
definition := apiextensionstestserver.NewRandomNameCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
|
||||
defer func() {
|
||||
err = apiextensionstestserver.DeleteCustomResourceDefinition(definition, apiExtensionClient)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
framework.Failf("failed to delete CustomResourceDefinition: %v", err)
|
||||
}
|
||||
}()
|
||||
definition, err = apiextensionstestserver.CreateNewCustomResourceDefinition(definition, apiExtensionClient, f.DynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("failed to create CustomResourceDefinition: %v", err)
|
||||
}
|
||||
|
||||
// Get a client for the custom resource.
|
||||
gvr := schema.GroupVersionResource{Group: definition.Spec.Group, Version: definition.Spec.Version, Resource: definition.Spec.Names.Plural}
|
||||
resourceClient := f.DynamicClient.Resource(gvr)
|
||||
|
||||
apiVersion := definition.Spec.Group + "/" + definition.Spec.Version
|
||||
|
||||
// Create a custom owner resource.
|
||||
ownerName := names.SimpleNameGenerator.GenerateName("owner")
|
||||
owner := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": apiVersion,
|
||||
"kind": definition.Spec.Names.Kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": ownerName,
|
||||
},
|
||||
},
|
||||
}
|
||||
persistedOwner, err := resourceClient.Create(owner)
|
||||
if err != nil {
|
||||
framework.Failf("failed to create owner resource %q: %v", ownerName, err)
|
||||
}
|
||||
framework.Logf("created owner resource %q", ownerName)
|
||||
|
||||
// Create a custom dependent resource.
|
||||
dependentName := names.SimpleNameGenerator.GenerateName("dependent")
|
||||
dependent := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": apiVersion,
|
||||
"kind": definition.Spec.Names.Kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": dependentName,
|
||||
"ownerReferences": []map[string]string{
|
||||
{
|
||||
"uid": string(persistedOwner.GetUID()),
|
||||
"apiVersion": apiVersion,
|
||||
"kind": definition.Spec.Names.Kind,
|
||||
"name": ownerName,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = resourceClient.Create(dependent)
|
||||
if err != nil {
|
||||
framework.Failf("failed to create dependent resource %q: %v", dependentName, err)
|
||||
}
|
||||
framework.Logf("created dependent resource %q", dependentName)
|
||||
|
||||
// Delete the owner and orphan the dependent.
|
||||
err = resourceClient.Delete(ownerName, getOrphanOptions())
|
||||
if err != nil {
|
||||
framework.Failf("failed to delete owner resource %q: %v", ownerName, err)
|
||||
}
|
||||
|
||||
By("wait for the owner to be deleted")
|
||||
if err := wait.Poll(5*time.Second, 120*time.Second, func() (bool, error) {
|
||||
_, err = resourceClient.Get(ownerName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return false, fmt.Errorf("Failed to get owner: %v", err)
|
||||
}
|
||||
return true, nil
|
||||
}); err != nil {
|
||||
framework.Failf("timeout in waiting for the owner to be deleted: %v", err)
|
||||
}
|
||||
|
||||
// Wait 30s and ensure the dependent is not deleted.
|
||||
By("wait for 30 seconds to see if the garbage collector mistakenly deletes the dependent crd")
|
||||
if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
|
||||
_, err := resourceClient.Get(dependentName, metav1.GetOptions{})
|
||||
return false, err
|
||||
}); err != nil && err != wait.ErrWaitTimeout {
|
||||
framework.Failf("failed to ensure the dependent is not deleted: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
It("should delete jobs and pods created by cronjob", func() {
|
||||
framework.SkipIfMissingResource(f.ClientPool, CronJobGroupVersionResource, f.Namespace.Name)
|
||||
framework.SkipIfMissingResource(f.DynamicClient, CronJobGroupVersionResource, f.Namespace.Name)
|
||||
|
||||
By("Create the cronjob")
|
||||
cronJob := newCronJob("simple", "*/1 * * * ?")
|
||||
|
2
vendor/k8s.io/kubernetes/test/e2e/apimachinery/generated_clientset.go
generated
vendored
2
vendor/k8s.io/kubernetes/test/e2e/apimachinery/generated_clientset.go
generated
vendored
@ -264,7 +264,7 @@ var _ = SIGDescribe("Generated clientset", func() {
|
||||
f := framework.NewDefaultFramework("clientset")
|
||||
|
||||
BeforeEach(func() {
|
||||
framework.SkipIfMissingResource(f.ClientPool, CronJobGroupVersionResource, f.Namespace.Name)
|
||||
framework.SkipIfMissingResource(f.DynamicClient, CronJobGroupVersionResource, f.Namespace.Name)
|
||||
})
|
||||
|
||||
It("should create v1beta1 cronJobs, delete cronJobs, watch cronJobs", func() {
|
||||
|
5
vendor/k8s.io/kubernetes/test/e2e/apimachinery/namespace.go
generated
vendored
5
vendor/k8s.io/kubernetes/test/e2e/apimachinery/namespace.go
generated
vendored
@ -29,6 +29,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -114,7 +115,7 @@ func ensurePodsAreRemovedWhenNamespaceIsDeleted(f *framework.Framework) {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: framework.GetPauseImageName(f.ClientSet),
|
||||
Image: imageutils.GetPauseImageName(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -135,7 +136,7 @@ func ensurePodsAreRemovedWhenNamespaceIsDeleted(f *framework.Framework) {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: framework.GetPauseImageName(f.ClientSet),
|
||||
Image: imageutils.GetPauseImageName(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
7
vendor/k8s.io/kubernetes/test/e2e/apimachinery/table_conversion.go
generated
vendored
7
vendor/k8s.io/kubernetes/test/e2e/apimachinery/table_conversion.go
generated
vendored
@ -32,13 +32,20 @@ import (
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
)
|
||||
|
||||
var serverPrintVersion = utilversion.MustParseSemantic("v1.10.0")
|
||||
|
||||
var _ = SIGDescribe("Servers with support for Table transformation", func() {
|
||||
f := framework.NewDefaultFramework("tables")
|
||||
|
||||
BeforeEach(func() {
|
||||
framework.SkipUnlessServerVersionGTE(serverPrintVersion, f.ClientSet.Discovery())
|
||||
})
|
||||
|
||||
It("should return pod details", func() {
|
||||
ns := f.Namespace.Name
|
||||
c := f.ClientSet
|
||||
|
383
vendor/k8s.io/kubernetes/test/e2e/apimachinery/watch.go
generated
vendored
Normal file
383
vendor/k8s.io/kubernetes/test/e2e/apimachinery/watch.go
generated
vendored
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apimachinery
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
const (
|
||||
watchConfigMapLabelKey = "watch-this-configmap"
|
||||
|
||||
multipleWatchersLabelValueA = "multiple-watchers-A"
|
||||
multipleWatchersLabelValueB = "multiple-watchers-B"
|
||||
fromResourceVersionLabelValue = "from-resource-version"
|
||||
watchRestartedLabelValue = "watch-closed-and-restarted"
|
||||
toBeChangedLabelValue = "label-changed-and-restored"
|
||||
)
|
||||
|
||||
var _ = SIGDescribe("Watchers", func() {
|
||||
f := framework.NewDefaultFramework("watch")
|
||||
|
||||
/*
|
||||
Testname: watch-configmaps-with-multiple-watchers
|
||||
Description: Ensure that multiple watchers are able to receive all add,
|
||||
update, and delete notifications on configmaps that match a label selector and do
|
||||
not receive notifications for configmaps which do not match that label selector.
|
||||
*/
|
||||
framework.ConformanceIt("should observe add, update, and delete watch notifications on configmaps", func() {
|
||||
c := f.ClientSet
|
||||
ns := f.Namespace.Name
|
||||
|
||||
By("creating a watch on configmaps with label A")
|
||||
watchA, err := watchConfigMaps(f, "", multipleWatchersLabelValueA)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("creating a watch on configmaps with label B")
|
||||
watchB, err := watchConfigMaps(f, "", multipleWatchersLabelValueB)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("creating a watch on configmaps with label A or B")
|
||||
watchAB, err := watchConfigMaps(f, "", multipleWatchersLabelValueA, multipleWatchersLabelValueB)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
testConfigMapA := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-watch-test-configmap-a",
|
||||
Labels: map[string]string{
|
||||
watchConfigMapLabelKey: multipleWatchersLabelValueA,
|
||||
},
|
||||
},
|
||||
}
|
||||
testConfigMapB := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-watch-test-configmap-b",
|
||||
Labels: map[string]string{
|
||||
watchConfigMapLabelKey: multipleWatchersLabelValueB,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
By("creating a configmap with label A and ensuring the correct watchers observe the notification")
|
||||
testConfigMapA, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMapA)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchA, watch.Added, testConfigMapA)
|
||||
expectEvent(watchAB, watch.Added, testConfigMapA)
|
||||
expectNoEvent(watchB, watch.Added, testConfigMapA)
|
||||
|
||||
By("modifying configmap A and ensuring the correct watchers observe the notification")
|
||||
testConfigMapA, err = updateConfigMap(c, ns, testConfigMapA.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "1")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchA, watch.Modified, testConfigMapA)
|
||||
expectEvent(watchAB, watch.Modified, testConfigMapA)
|
||||
expectNoEvent(watchB, watch.Modified, testConfigMapA)
|
||||
|
||||
By("modifying configmap A again and ensuring the correct watchers observe the notification")
|
||||
testConfigMapA, err = updateConfigMap(c, ns, testConfigMapA.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "2")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchA, watch.Modified, testConfigMapA)
|
||||
expectEvent(watchAB, watch.Modified, testConfigMapA)
|
||||
expectNoEvent(watchB, watch.Modified, testConfigMapA)
|
||||
|
||||
By("deleting configmap A and ensuring the correct watchers observe the notification")
|
||||
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMapA.GetName(), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchA, watch.Deleted, nil)
|
||||
expectEvent(watchAB, watch.Deleted, nil)
|
||||
expectNoEvent(watchB, watch.Deleted, nil)
|
||||
|
||||
By("creating a configmap with label B and ensuring the correct watchers observe the notification")
|
||||
testConfigMapB, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMapB)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchB, watch.Added, testConfigMapB)
|
||||
expectEvent(watchAB, watch.Added, testConfigMapB)
|
||||
expectNoEvent(watchA, watch.Added, testConfigMapB)
|
||||
|
||||
By("deleting configmap B and ensuring the correct watchers observe the notification")
|
||||
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMapB.GetName(), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectEvent(watchB, watch.Deleted, nil)
|
||||
expectEvent(watchAB, watch.Deleted, nil)
|
||||
expectNoEvent(watchA, watch.Deleted, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: watch-configmaps-from-resource-version
|
||||
Description: Ensure that a watch can be opened from a particular resource version
|
||||
in the past and only notifications happening after that resource version are observed.
|
||||
*/
|
||||
framework.ConformanceIt("should be able to start watching from a specific resource version", func() {
|
||||
c := f.ClientSet
|
||||
ns := f.Namespace.Name
|
||||
|
||||
testConfigMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-watch-test-resource-version",
|
||||
Labels: map[string]string{
|
||||
watchConfigMapLabelKey: fromResourceVersionLabelValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
By("creating a new configmap")
|
||||
testConfigMap, err := c.CoreV1().ConfigMaps(ns).Create(testConfigMap)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("modifying the configmap once")
|
||||
testConfigMapFirstUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "1")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("modifying the configmap a second time")
|
||||
testConfigMapSecondUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "2")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("deleting the configmap")
|
||||
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMap.GetName(), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("creating a watch on configmaps from the resource version returned by the first update")
|
||||
testWatch, err := watchConfigMaps(f, testConfigMapFirstUpdate.ObjectMeta.ResourceVersion, fromResourceVersionLabelValue)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Expecting to observe notifications for all changes to the configmap after the first update")
|
||||
expectEvent(testWatch, watch.Modified, testConfigMapSecondUpdate)
|
||||
expectEvent(testWatch, watch.Deleted, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: watch-configmaps-closed-and-restarted
|
||||
Description: Ensure that a watch can be reopened from the last resource version
|
||||
observed by the previous watch, and it will continue delivering notifications from
|
||||
that point in time.
|
||||
*/
|
||||
framework.ConformanceIt("should be able to restart watching from the last resource version observed by the previous watch", func() {
|
||||
c := f.ClientSet
|
||||
ns := f.Namespace.Name
|
||||
|
||||
testConfigMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-watch-test-watch-closed",
|
||||
Labels: map[string]string{
|
||||
watchConfigMapLabelKey: watchRestartedLabelValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
By("creating a watch on configmaps")
|
||||
testWatchBroken, err := watchConfigMaps(f, "", watchRestartedLabelValue)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("creating a new configmap")
|
||||
testConfigMap, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMap)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("modifying the configmap once")
|
||||
_, err = updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "1")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("closing the watch once it receives two notifications")
|
||||
expectEvent(testWatchBroken, watch.Added, testConfigMap)
|
||||
lastEvent, ok := waitForEvent(testWatchBroken, watch.Modified, nil, 1*time.Minute)
|
||||
if !ok {
|
||||
framework.Failf("Timed out waiting for second watch notification")
|
||||
}
|
||||
testWatchBroken.Stop()
|
||||
|
||||
By("modifying the configmap a second time, while the watch is closed")
|
||||
testConfigMapSecondUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "2")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("creating a new watch on configmaps from the last resource version observed by the first watch")
|
||||
lastEventConfigMap, ok := lastEvent.Object.(*v1.ConfigMap)
|
||||
if !ok {
|
||||
framework.Failf("Expected last notfication to refer to a configmap but got: %v", lastEvent)
|
||||
}
|
||||
testWatchRestarted, err := watchConfigMaps(f, lastEventConfigMap.ObjectMeta.ResourceVersion, watchRestartedLabelValue)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("deleting the configmap")
|
||||
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMap.GetName(), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Expecting to observe notifications for all changes to the configmap since the first watch closed")
|
||||
expectEvent(testWatchRestarted, watch.Modified, testConfigMapSecondUpdate)
|
||||
expectEvent(testWatchRestarted, watch.Deleted, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: watch-configmaps-label-changed
|
||||
Description: Ensure that a watched object stops meeting the requirements of
|
||||
a watch's selector, the watch will observe a delete, and will not observe
|
||||
notifications for that object until it meets the selector's requirements again.
|
||||
*/
|
||||
framework.ConformanceIt("should observe an object deletion if it stops meeting the requirements of the selector", func() {
|
||||
c := f.ClientSet
|
||||
ns := f.Namespace.Name
|
||||
|
||||
testConfigMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-watch-test-label-changed",
|
||||
Labels: map[string]string{
|
||||
watchConfigMapLabelKey: toBeChangedLabelValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
By("creating a watch on configmaps with a certain label")
|
||||
testWatch, err := watchConfigMaps(f, "", toBeChangedLabelValue)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("creating a new configmap")
|
||||
testConfigMap, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMap)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("modifying the configmap once")
|
||||
testConfigMapFirstUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "1")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("changing the label value of the configmap")
|
||||
_, err = updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
cm.ObjectMeta.Labels[watchConfigMapLabelKey] = "wrong-value"
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Expecting to observe a delete notification for the watched object")
|
||||
expectEvent(testWatch, watch.Added, testConfigMap)
|
||||
expectEvent(testWatch, watch.Modified, testConfigMapFirstUpdate)
|
||||
expectEvent(testWatch, watch.Deleted, nil)
|
||||
|
||||
By("modifying the configmap a second time")
|
||||
testConfigMapSecondUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "2")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Expecting not to observe a notification because the object no longer meets the selector's requirements")
|
||||
expectNoEvent(testWatch, watch.Modified, testConfigMapSecondUpdate)
|
||||
|
||||
By("changing the label value of the configmap back")
|
||||
testConfigMapLabelRestored, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
cm.ObjectMeta.Labels[watchConfigMapLabelKey] = toBeChangedLabelValue
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("modifying the configmap a third time")
|
||||
testConfigMapThirdUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
|
||||
setConfigMapData(cm, "mutation", "3")
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("deleting the configmap")
|
||||
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMap.GetName(), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Expecting to observe an add notification for the watched object when the label value was restored")
|
||||
expectEvent(testWatch, watch.Added, testConfigMapLabelRestored)
|
||||
expectEvent(testWatch, watch.Modified, testConfigMapThirdUpdate)
|
||||
expectEvent(testWatch, watch.Deleted, nil)
|
||||
})
|
||||
})
|
||||
|
||||
func watchConfigMaps(f *framework.Framework, resourceVersion string, labels ...string) (watch.Interface, error) {
|
||||
c := f.ClientSet
|
||||
ns := f.Namespace.Name
|
||||
opts := metav1.ListOptions{
|
||||
ResourceVersion: resourceVersion,
|
||||
LabelSelector: metav1.FormatLabelSelector(&metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: watchConfigMapLabelKey,
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: labels,
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
return c.CoreV1().ConfigMaps(ns).Watch(opts)
|
||||
}
|
||||
|
||||
func int64ptr(i int) *int64 {
|
||||
i64 := int64(i)
|
||||
return &i64
|
||||
}
|
||||
|
||||
func setConfigMapData(cm *v1.ConfigMap, key, value string) {
|
||||
if cm.Data == nil {
|
||||
cm.Data = make(map[string]string)
|
||||
}
|
||||
cm.Data[key] = value
|
||||
}
|
||||
|
||||
func expectEvent(w watch.Interface, eventType watch.EventType, object runtime.Object) {
|
||||
if event, ok := waitForEvent(w, eventType, object, 1*time.Minute); !ok {
|
||||
framework.Failf("Timed out waiting for expected watch notification: %v", event)
|
||||
}
|
||||
}
|
||||
|
||||
func expectNoEvent(w watch.Interface, eventType watch.EventType, object runtime.Object) {
|
||||
if event, ok := waitForEvent(w, eventType, object, 10*time.Second); ok {
|
||||
framework.Failf("Unexpected watch notification observed: %v", event)
|
||||
}
|
||||
}
|
||||
|
||||
func waitForEvent(w watch.Interface, expectType watch.EventType, expectObject runtime.Object, duration time.Duration) (watch.Event, bool) {
|
||||
stopTimer := time.NewTimer(duration)
|
||||
defer stopTimer.Stop()
|
||||
for {
|
||||
select {
|
||||
case actual, ok := <-w.ResultChan():
|
||||
if ok {
|
||||
framework.Logf("Got : %v %v", actual.Type, actual.Object)
|
||||
} else {
|
||||
framework.Failf("Watch closed unexpectedly")
|
||||
}
|
||||
if expectType == actual.Type && (expectObject == nil || apiequality.Semantic.DeepEqual(expectObject, actual.Object)) {
|
||||
return actual, true
|
||||
}
|
||||
case <-stopTimer.C:
|
||||
expected := watch.Event{
|
||||
Type: expectType,
|
||||
Object: expectObject,
|
||||
}
|
||||
return expected, false
|
||||
}
|
||||
}
|
||||
}
|
515
vendor/k8s.io/kubernetes/test/e2e/apimachinery/webhook.go
generated
vendored
515
vendor/k8s.io/kubernetes/test/e2e/apimachinery/webhook.go
generated
vendored
@ -23,10 +23,11 @@ import (
|
||||
"time"
|
||||
|
||||
"k8s.io/api/admissionregistration/v1beta1"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
crdclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
@ -51,12 +52,16 @@ const (
|
||||
roleBindingName = "webhook-auth-reader"
|
||||
|
||||
// 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"
|
||||
mutatingWebhookConfigName = "e2e-test-mutating-webhook-config"
|
||||
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"
|
||||
webhookForWebhooksConfigName = "e2e-test-webhook-for-webhooks-config"
|
||||
removableValidatingHookName = "e2e-test-should-be-removable-validating-webhook-config"
|
||||
removableMutatingHookName = "e2e-test-should-be-removable-mutating-webhook-config"
|
||||
crdWebhookConfigName = "e2e-test-webhook-config-crd"
|
||||
|
||||
skipNamespaceLabelKey = "skip-webhook-admission"
|
||||
skipNamespaceLabelValue = "yes"
|
||||
@ -118,9 +123,9 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
|
||||
return
|
||||
}
|
||||
defer testcrd.CleanUp()
|
||||
webhookCleanup := registerWebhookForCRD(f, context, testcrd)
|
||||
webhookCleanup := registerWebhookForCustomResource(f, context, testcrd)
|
||||
defer webhookCleanup()
|
||||
testCRDWebhook(f, testcrd.Crd, testcrd.DynamicClient)
|
||||
testCustomResourceWebhook(f, testcrd.Crd, testcrd.DynamicClient)
|
||||
})
|
||||
|
||||
It("Should unconditionally reject operations on fail closed webhook", func() {
|
||||
@ -141,15 +146,28 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
|
||||
testMutatingPodWebhook(f)
|
||||
})
|
||||
|
||||
It("Should mutate crd", func() {
|
||||
It("Should not be able to prevent deleting validating-webhook-configurations or mutating-webhook-configurations", func() {
|
||||
webhookCleanup := registerWebhookForWebhookConfigurations(f, context)
|
||||
defer webhookCleanup()
|
||||
testWebhookForWebhookConfigurations(f)
|
||||
})
|
||||
|
||||
It("Should mutate custom resource", func() {
|
||||
testcrd, err := framework.CreateTestCRD(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer testcrd.CleanUp()
|
||||
webhookCleanup := registerMutatingWebhookForCRD(f, context, testcrd)
|
||||
webhookCleanup := registerMutatingWebhookForCustomResource(f, context, testcrd)
|
||||
defer webhookCleanup()
|
||||
testMutatingCRDWebhook(f, testcrd.Crd, testcrd.DynamicClient)
|
||||
testMutatingCustomResourceWebhook(f, testcrd.Crd, testcrd.DynamicClient)
|
||||
})
|
||||
|
||||
It("Should deny crd creation", func() {
|
||||
crdWebhookCleanup := registerValidatingWebhookForCRD(f, context)
|
||||
defer crdWebhookCleanup()
|
||||
|
||||
testCRDDenyWebhook(f)
|
||||
})
|
||||
|
||||
// TODO: add more e2e tests for mutating webhooks
|
||||
@ -245,14 +263,18 @@ func deployWebhookAndService(f *framework.Framework, image string, context *cert
|
||||
Image: image,
|
||||
},
|
||||
}
|
||||
d := &extensions.Deployment{
|
||||
d := &apps.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deploymentName,
|
||||
Name: deploymentName,
|
||||
Labels: podLabels,
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Spec: apps.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Strategy: extensions.DeploymentStrategy{
|
||||
Type: extensions.RollingUpdateDeploymentStrategyType,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: podLabels,
|
||||
},
|
||||
Strategy: apps.DeploymentStrategy{
|
||||
Type: apps.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -266,7 +288,7 @@ func deployWebhookAndService(f *framework.Framework, image string, context *cert
|
||||
},
|
||||
},
|
||||
}
|
||||
deployment, err := client.ExtensionsV1beta1().Deployments(namespace).Create(d)
|
||||
deployment, err := client.AppsV1().Deployments(namespace).Create(d)
|
||||
framework.ExpectNoError(err, "creating deployment %s in namespace %s", deploymentName, namespace)
|
||||
By("Wait for the deployment to be ready")
|
||||
err = framework.WaitForDeploymentRevisionAndImage(client, namespace, deploymentName, "1", image)
|
||||
@ -375,7 +397,7 @@ func registerWebhook(f *framework.Framework, context *certContext) func() {
|
||||
})
|
||||
framework.ExpectNoError(err, "registering webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 1s.
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
return func() {
|
||||
@ -437,7 +459,7 @@ func registerMutatingWebhookForConfigMap(f *framework.Framework, context *certCo
|
||||
})
|
||||
framework.ExpectNoError(err, "registering mutating webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 1s.
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
return func() { client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(configName, nil) }
|
||||
}
|
||||
@ -493,7 +515,7 @@ func registerMutatingWebhookForPod(f *framework.Framework, context *certContext)
|
||||
})
|
||||
framework.ExpectNoError(err, "registering mutating webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 1s.
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
return func() { client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(configName, nil) }
|
||||
@ -525,7 +547,7 @@ func toBeMutatedPod(f *framework.Framework) *v1.Pod {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "example",
|
||||
Image: framework.GetPauseImageName(f.ClientSet),
|
||||
Image: imageutils.GetPauseImageName(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -709,6 +731,154 @@ func testFailClosedWebhook(f *framework.Framework) {
|
||||
}
|
||||
}
|
||||
|
||||
func registerWebhookForWebhookConfigurations(f *framework.Framework, context *certContext) func() {
|
||||
var err error
|
||||
client := f.ClientSet
|
||||
By("Registering a webhook on ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects, via the AdmissionRegistration API")
|
||||
|
||||
namespace := f.Namespace.Name
|
||||
configName := webhookForWebhooksConfigName
|
||||
failurePolicy := v1beta1.Fail
|
||||
|
||||
// This webhook will deny all requests to Delete admissionregistration objects
|
||||
_, err = client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configName,
|
||||
},
|
||||
Webhooks: []v1beta1.Webhook{
|
||||
{
|
||||
Name: "deny-webhook-configuration-deletions.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Delete},
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{"admissionregistration.k8s.io"},
|
||||
APIVersions: []string{"*"},
|
||||
Resources: []string{
|
||||
"validatingwebhookconfigurations",
|
||||
"mutatingwebhookconfigurations",
|
||||
},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
Path: strPtr("/always-deny"),
|
||||
},
|
||||
CABundle: context.signingCert,
|
||||
},
|
||||
FailurePolicy: &failurePolicy,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
framework.ExpectNoError(err, "registering webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
return func() {
|
||||
err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Delete(configName, nil)
|
||||
framework.ExpectNoError(err, "deleting webhook config %s with namespace %s", configName, namespace)
|
||||
}
|
||||
}
|
||||
|
||||
// This test assumes that the deletion-rejecting webhook defined in
|
||||
// registerWebhookForWebhookConfigurations is in place.
|
||||
func testWebhookForWebhookConfigurations(f *framework.Framework) {
|
||||
var err error
|
||||
client := f.ClientSet
|
||||
By("Creating a validating-webhook-configuration object")
|
||||
|
||||
namespace := f.Namespace.Name
|
||||
failurePolicy := v1beta1.Ignore
|
||||
|
||||
_, err = client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: removableValidatingHookName,
|
||||
},
|
||||
Webhooks: []v1beta1.Webhook{
|
||||
{
|
||||
Name: "should-be-removable-validating-webhook.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
// This will not match any real resources so this webhook should never be called.
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{""},
|
||||
APIVersions: []string{"v1"},
|
||||
Resources: []string{"invalid"},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
// This path not recognized by the webhook service,
|
||||
// so the call to this webhook will always fail,
|
||||
// but because the failure policy is ignore, it will
|
||||
// have no effect on admission requests.
|
||||
Path: strPtr(""),
|
||||
},
|
||||
CABundle: nil,
|
||||
},
|
||||
FailurePolicy: &failurePolicy,
|
||||
},
|
||||
},
|
||||
})
|
||||
framework.ExpectNoError(err, "registering webhook config %s with namespace %s", removableValidatingHookName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
By("Deleting the validating-webhook-configuration, which should be possible to remove")
|
||||
|
||||
err = client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Delete(removableValidatingHookName, nil)
|
||||
framework.ExpectNoError(err, "deleting webhook config %s with namespace %s", removableValidatingHookName, namespace)
|
||||
|
||||
By("Creating a mutating-webhook-configuration object")
|
||||
|
||||
_, err = client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&v1beta1.MutatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: removableMutatingHookName,
|
||||
},
|
||||
Webhooks: []v1beta1.Webhook{
|
||||
{
|
||||
Name: "should-be-removable-mutating-webhook.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
// This will not match any real resources so this webhook should never be called.
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{""},
|
||||
APIVersions: []string{"v1"},
|
||||
Resources: []string{"invalid"},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
// This path not recognized by the webhook service,
|
||||
// so the call to this webhook will always fail,
|
||||
// but because the failure policy is ignore, it will
|
||||
// have no effect on admission requests.
|
||||
Path: strPtr(""),
|
||||
},
|
||||
CABundle: nil,
|
||||
},
|
||||
FailurePolicy: &failurePolicy,
|
||||
},
|
||||
},
|
||||
})
|
||||
framework.ExpectNoError(err, "registering webhook config %s with namespace %s", removableMutatingHookName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
By("Deleting the mutating-webhook-configuration, which should be possible to remove")
|
||||
|
||||
err = client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(removableMutatingHookName, nil)
|
||||
framework.ExpectNoError(err, "deleting webhook config %s with namespace %s", removableMutatingHookName, namespace)
|
||||
}
|
||||
|
||||
func createNamespace(f *framework.Framework, ns *v1.Namespace) error {
|
||||
return wait.PollImmediate(100*time.Millisecond, 30*time.Second, func() (bool, error) {
|
||||
_, err := f.ClientSet.CoreV1().Namespaces().Create(ns)
|
||||
@ -734,7 +904,7 @@ func nonCompliantPod(f *framework.Framework) *v1.Pod {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "webhook-disallow",
|
||||
Image: framework.GetPauseImageName(f.ClientSet),
|
||||
Image: imageutils.GetPauseImageName(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -753,7 +923,7 @@ func hangingPod(f *framework.Framework) *v1.Pod {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "wait-forever",
|
||||
Image: framework.GetPauseImageName(f.ClientSet),
|
||||
Image: imageutils.GetPauseImageName(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -810,24 +980,24 @@ func updateConfigMap(c clientset.Interface, ns, name string, update updateConfig
|
||||
|
||||
func cleanWebhookTest(client clientset.Interface, namespaceName string) {
|
||||
_ = client.CoreV1().Services(namespaceName).Delete(serviceName, nil)
|
||||
_ = client.ExtensionsV1beta1().Deployments(namespaceName).Delete(deploymentName, nil)
|
||||
_ = client.AppsV1().Deployments(namespaceName).Delete(deploymentName, nil)
|
||||
_ = client.CoreV1().Secrets(namespaceName).Delete(secretName, 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
|
||||
By("Registering the crd webhook via the AdmissionRegistration API")
|
||||
By("Registering the custom resource webhook via the AdmissionRegistration API")
|
||||
|
||||
namespace := f.Namespace.Name
|
||||
configName := crdWebhookConfigName
|
||||
configName := crWebhookConfigName
|
||||
_, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configName,
|
||||
},
|
||||
Webhooks: []v1beta1.Webhook{
|
||||
{
|
||||
Name: "deny-unwanted-crd-data.k8s.io",
|
||||
Name: "deny-unwanted-custom-resource-data.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
Rule: v1beta1.Rule{
|
||||
@ -836,6 +1006,161 @@ func registerWebhookForCRD(f *framework.Framework, context *certContext, testcrd
|
||||
Resources: []string{testcrd.GetPluralName()},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
Path: strPtr("/custom-resource"),
|
||||
},
|
||||
CABundle: context.signingCert,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
framework.ExpectNoError(err, "registering custom resource webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
return func() {
|
||||
client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Delete(configName, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func registerMutatingWebhookForCustomResource(f *framework.Framework, context *certContext, testcrd *framework.TestCrd) func() {
|
||||
client := f.ClientSet
|
||||
By("Registering the mutating webhook for a custom resource via the AdmissionRegistration API")
|
||||
|
||||
namespace := f.Namespace.Name
|
||||
configName := crMutatingWebhookConfigName
|
||||
_, err := client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&v1beta1.MutatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configName,
|
||||
},
|
||||
Webhooks: []v1beta1.Webhook{
|
||||
{
|
||||
Name: "mutate-custom-resource-data-stage-1.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{testcrd.ApiGroup},
|
||||
APIVersions: []string{testcrd.ApiVersion},
|
||||
Resources: []string{testcrd.GetPluralName()},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
Path: strPtr("/mutating-custom-resource"),
|
||||
},
|
||||
CABundle: context.signingCert,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "mutate-custom-resource-data-stage-2.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{testcrd.ApiGroup},
|
||||
APIVersions: []string{testcrd.ApiVersion},
|
||||
Resources: []string{testcrd.GetPluralName()},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
Path: strPtr("/mutating-custom-resource"),
|
||||
},
|
||||
CABundle: context.signingCert,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
framework.ExpectNoError(err, "registering custom resource webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
return func() { client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(configName, nil) }
|
||||
}
|
||||
|
||||
func testCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.ResourceInterface) {
|
||||
By("Creating a custom resource that should be denied by the webhook")
|
||||
crInstance := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": crd.Spec.Names.Kind,
|
||||
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cr-instance-1",
|
||||
"namespace": f.Namespace.Name,
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"webhook-e2e-test": "webhook-disallow",
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err := customResourceClient.Create(crInstance)
|
||||
Expect(err).NotTo(BeNil())
|
||||
expectedErrMsg := "the custom resource contains unwanted data"
|
||||
if !strings.Contains(err.Error(), expectedErrMsg) {
|
||||
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testMutatingCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.ResourceInterface) {
|
||||
By("Creating a custom resource that should be mutated by the webhook")
|
||||
cr := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": crd.Spec.Names.Kind,
|
||||
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cr-instance-1",
|
||||
"namespace": f.Namespace.Name,
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"mutation-start": "yes",
|
||||
},
|
||||
},
|
||||
}
|
||||
mutatedCR, err := customResourceClient.Create(cr)
|
||||
Expect(err).To(BeNil())
|
||||
expectedCRData := map[string]interface{}{
|
||||
"mutation-start": "yes",
|
||||
"mutation-stage-1": "yes",
|
||||
"mutation-stage-2": "yes",
|
||||
}
|
||||
if !reflect.DeepEqual(expectedCRData, mutatedCR.Object["data"]) {
|
||||
framework.Failf("\nexpected %#v\n, got %#v\n", expectedCRData, mutatedCR.Object["data"])
|
||||
}
|
||||
}
|
||||
|
||||
func registerValidatingWebhookForCRD(f *framework.Framework, context *certContext) func() {
|
||||
client := f.ClientSet
|
||||
By("Registering the crd webhook via the AdmissionRegistration API")
|
||||
|
||||
namespace := f.Namespace.Name
|
||||
configName := crdWebhookConfigName
|
||||
|
||||
// This webhook will deny the creation of CustomResourceDefinitions which have the
|
||||
// label "webhook-e2e-test":"webhook-disallow"
|
||||
// NOTE: Because tests are run in parallel and in an unpredictable order, it is critical
|
||||
// that no other test attempts to create CRD with that label.
|
||||
_, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configName,
|
||||
},
|
||||
Webhooks: []v1beta1.Webhook{
|
||||
{
|
||||
Name: "deny-crd-with-unwanted-label.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{"apiextensions.k8s.io"},
|
||||
APIVersions: []string{"*"},
|
||||
Resources: []string{"customresourcedefinitions"},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
@ -849,118 +1174,62 @@ func registerWebhookForCRD(f *framework.Framework, context *certContext, testcrd
|
||||
})
|
||||
framework.ExpectNoError(err, "registering crd webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 1s.
|
||||
// The webhook configuration is honored in 10s.
|
||||
time.Sleep(10 * time.Second)
|
||||
return func() {
|
||||
client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Delete(configName, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func registerMutatingWebhookForCRD(f *framework.Framework, context *certContext, testcrd *framework.TestCrd) func() {
|
||||
client := f.ClientSet
|
||||
By("Registering the mutating webhook for crd via the AdmissionRegistration API")
|
||||
func testCRDDenyWebhook(f *framework.Framework) {
|
||||
By("Creating a custom resource definition that should be denied by the webhook")
|
||||
name := fmt.Sprintf("e2e-test-%s-%s-crd", f.BaseName, "deny")
|
||||
kind := fmt.Sprintf("E2e-test-%s-%s-crd", f.BaseName, "deny")
|
||||
group := fmt.Sprintf("%s-crd-test.k8s.io", f.BaseName)
|
||||
apiVersion := "v1"
|
||||
testcrd := &framework.TestCrd{
|
||||
Name: name,
|
||||
Kind: kind,
|
||||
ApiGroup: group,
|
||||
ApiVersion: apiVersion,
|
||||
}
|
||||
|
||||
namespace := f.Namespace.Name
|
||||
configName := crdMutatingWebhookConfigName
|
||||
_, err := client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&v1beta1.MutatingWebhookConfiguration{
|
||||
// Creating a custom resource definition for use by assorted tests.
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("failed to load config: %v", err)
|
||||
return
|
||||
}
|
||||
apiExtensionClient, err := crdclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("failed to initialize apiExtensionClient: %v", err)
|
||||
return
|
||||
}
|
||||
crd := &apiextensionsv1beta1.CustomResourceDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configName,
|
||||
},
|
||||
Webhooks: []v1beta1.Webhook{
|
||||
{
|
||||
Name: "mutate-crd-data-stage-1.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{testcrd.ApiGroup},
|
||||
APIVersions: []string{testcrd.ApiVersion},
|
||||
Resources: []string{testcrd.GetPluralName()},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
Path: strPtr("/mutating-crd"),
|
||||
},
|
||||
CABundle: context.signingCert,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "mutate-crd-data-stage-2.k8s.io",
|
||||
Rules: []v1beta1.RuleWithOperations{{
|
||||
Operations: []v1beta1.OperationType{v1beta1.Create},
|
||||
Rule: v1beta1.Rule{
|
||||
APIGroups: []string{testcrd.ApiGroup},
|
||||
APIVersions: []string{testcrd.ApiVersion},
|
||||
Resources: []string{testcrd.GetPluralName()},
|
||||
},
|
||||
}},
|
||||
ClientConfig: v1beta1.WebhookClientConfig{
|
||||
Service: &v1beta1.ServiceReference{
|
||||
Namespace: namespace,
|
||||
Name: serviceName,
|
||||
Path: strPtr("/mutating-crd"),
|
||||
},
|
||||
CABundle: context.signingCert,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
framework.ExpectNoError(err, "registering crd webhook config %s with namespace %s", configName, namespace)
|
||||
|
||||
// The webhook configuration is honored in 1s.
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
return func() { client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(configName, nil) }
|
||||
}
|
||||
|
||||
func testCRDWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, crdClient dynamic.ResourceInterface) {
|
||||
By("Creating a custom resource that should be denied by the webhook")
|
||||
crInstance := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": crd.Spec.Names.Kind,
|
||||
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cr-instance-1",
|
||||
"namespace": f.Namespace.Name,
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
Name: testcrd.GetMetaName(),
|
||||
Labels: map[string]string{
|
||||
"webhook-e2e-test": "webhook-disallow",
|
||||
},
|
||||
},
|
||||
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
|
||||
Group: testcrd.ApiGroup,
|
||||
Version: testcrd.ApiVersion,
|
||||
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
|
||||
Plural: testcrd.GetPluralName(),
|
||||
Singular: testcrd.Name,
|
||||
Kind: testcrd.Kind,
|
||||
ListKind: testcrd.GetListName(),
|
||||
},
|
||||
Scope: apiextensionsv1beta1.NamespaceScoped,
|
||||
},
|
||||
}
|
||||
_, err := crdClient.Create(crInstance)
|
||||
|
||||
// create CRD
|
||||
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
|
||||
Expect(err).NotTo(BeNil())
|
||||
expectedErrMsg := "the custom resource contains unwanted data"
|
||||
expectedErrMsg := "the crd contains unwanted label"
|
||||
if !strings.Contains(err.Error(), expectedErrMsg) {
|
||||
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testMutatingCRDWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, crdClient dynamic.ResourceInterface) {
|
||||
By("Creating a custom resource that should be mutated by the webhook")
|
||||
cr := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": crd.Spec.Names.Kind,
|
||||
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cr-instance-1",
|
||||
"namespace": f.Namespace.Name,
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"mutation-start": "yes",
|
||||
},
|
||||
},
|
||||
}
|
||||
mutatedCR, err := crdClient.Create(cr)
|
||||
Expect(err).To(BeNil())
|
||||
expectedCRData := map[string]interface{}{
|
||||
"mutation-start": "yes",
|
||||
"mutation-stage-1": "yes",
|
||||
"mutation-stage-2": "yes",
|
||||
}
|
||||
if !reflect.DeepEqual(expectedCRData, mutatedCR.Object["data"]) {
|
||||
framework.Failf("\nexpected %#v\n, got %#v\n", expectedCRData, mutatedCR.Object["data"])
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user