diff --git a/test/e2e/apps/BUILD b/test/e2e/apps/BUILD index 53e3b3a6184..8bee173757a 100644 --- a/test/e2e/apps/BUILD +++ b/test/e2e/apps/BUILD @@ -38,6 +38,7 @@ go_library( "//pkg/master/ports:go_default_library", "//pkg/scheduler/nodeinfo:go_default_library", "//staging/src/k8s.io/api/apps/v1:go_default_library", + "//staging/src/k8s.io/api/autoscaling/v1:go_default_library", "//staging/src/k8s.io/api/batch/v1:go_default_library", "//staging/src/k8s.io/api/batch/v1beta1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/test/e2e/apps/rc.go b/test/e2e/apps/rc.go index 2e788937ea5..e8cbd0150bd 100644 --- a/test/e2e/apps/rc.go +++ b/test/e2e/apps/rc.go @@ -18,16 +18,21 @@ package apps import ( "context" + "encoding/json" "fmt" "time" + autoscalingv1 "k8s.io/api/autoscaling/v1" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/dynamic" clientset "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/controller/replication" "k8s.io/kubernetes/test/e2e/framework" @@ -41,6 +46,14 @@ import ( var _ = SIGDescribe("ReplicationController", func() { f := framework.NewDefaultFramework("replication-controller") + var ns string + var dc dynamic.Interface + + ginkgo.BeforeEach(func() { + ns = f.Namespace.Name + dc = f.DynamicClient + }) + /* Release : v1.9 Testname: Replication Controller, run basic image @@ -83,6 +96,175 @@ var _ = SIGDescribe("ReplicationController", func() { framework.ConformanceIt("should release no longer matching pods", func() { testRCReleaseControlledNotMatching(f) }) + + ginkgo.It("should test the lifecycle of a ReplicationController", func() { + testRcName := "rc-test" + testRcNamespace := ns + testRcInitialReplicaCount := int32(1) + testRcMaxReplicaCount := int32(2) + rcResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "replicationcontrollers"} + + rcTest := v1.ReplicationController{ + ObjectMeta: metav1.ObjectMeta{ + Name: testRcName, + Labels: map[string]string{"test-rc-static": "true"}, + }, + Spec: v1.ReplicationControllerSpec{ + Replicas: &testRcInitialReplicaCount, + Selector: map[string]string{"test-rc-static": "true"}, + Template: &v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: testRcName, + Labels: map[string]string{"test-rc-static": "true"}, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{{ + Name: testRcName, + Image: "nginx", + }}, + }, + }, + }, + } + + ginkgo.By("creating a ReplicationController") + // Create a ReplicationController + _, err := f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).Create(context.TODO(), &rcTest, metav1.CreateOptions{}) + framework.ExpectNoError(err, "Failed to create ReplicationController") + + // setup a watch for the RC + rcWatchTimeoutSeconds := int64(180) + rcWatch, err := f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).Watch(context.TODO(), metav1.ListOptions{LabelSelector: "test-rc-static=true", TimeoutSeconds: &rcWatchTimeoutSeconds}) + framework.ExpectNoError(err, "Failed to setup watch on newly created ReplicationController") + + rcWatchChan := rcWatch.ResultChan() + + ginkgo.By("waiting for available Replicas") + for watchEvent := range rcWatchChan { + rc, ok := watchEvent.Object.(*v1.ReplicationController) + framework.ExpectEqual(ok, true, "Unable to convert type of ReplicationController watch watchEvent") + if rc.Status.Replicas == testRcInitialReplicaCount && rc.Status.ReadyReplicas == testRcInitialReplicaCount { + break + } + } + + rcLabelPatchPayload, err := json.Marshal(v1.ReplicationController{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"test-rc": "patched"}, + }, + }) + framework.ExpectNoError(err, "failed to marshal json of replicationcontroller label patch") + // Patch the ReplicationController + ginkgo.By("patching ReplicationController") + _, err = f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).Patch(context.TODO(), testRcName, types.StrategicMergePatchType, []byte(rcLabelPatchPayload), metav1.PatchOptions{}) + framework.ExpectNoError(err, "Failed to patch ReplicationController") + + rcStatusPatchPayload, err := json.Marshal(map[string]interface{}{ + "status": map[string]interface{}{ + "readyReplicas": 0, + "availableReplicas": 0, + }, + }) + framework.ExpectNoError(err, "Failed to marshal JSON of ReplicationController label patch") + + // Patch the ReplicationController's status + ginkgo.By("patching ReplicationController status") + rcStatus, err := f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).Patch(context.TODO(), testRcName, types.StrategicMergePatchType, []byte(rcStatusPatchPayload), metav1.PatchOptions{}, "status") + framework.ExpectNoError(err, "Failed to patch ReplicationControllerStatus") + framework.ExpectEqual(rcStatus.Status.ReadyReplicas, int32(0), "ReplicationControllerStatus's readyReplicas does not equal 0") + + ginkgo.By("fetching ReplicationController status") + rcStatusUnstructured, err := dc.Resource(rcResource).Namespace(testRcNamespace).Get(context.TODO(), testRcName, metav1.GetOptions{}, "status") + framework.ExpectNoError(err, "Failed to fetch ReplicationControllerStatus") + + rcStatusUjson, err := json.Marshal(rcStatusUnstructured) + framework.ExpectNoError(err, "Failed to marshal json of replicationcontroller label patch") + json.Unmarshal(rcStatusUjson, &rcStatus) + framework.ExpectEqual(rcStatus.Status.Replicas, testRcInitialReplicaCount, "ReplicationController ReplicaSet cound does not match initial Replica count") + + rcScalePatchPayload, err := json.Marshal(autoscalingv1.Scale{ + Spec: autoscalingv1.ScaleSpec{ + Replicas: testRcMaxReplicaCount, + }, + }) + framework.ExpectNoError(err, "Failed to marshal json of replicationcontroller label patch") + + // Patch the ReplicationController's scale + ginkgo.By("patching ReplicationController scale") + _, err = f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).Patch(context.TODO(), testRcName, types.StrategicMergePatchType, []byte(rcScalePatchPayload), metav1.PatchOptions{}, "scale") + framework.ExpectNoError(err, "Failed to patch ReplicationControllerScale") + + var rcFromWatch *v1.ReplicationController + ginkgo.By("waiting for ReplicationController's scale to be the max amount") + foundRcWithMaxScale := false + for watchEvent := range rcWatchChan { + rc, ok := watchEvent.Object.(*v1.ReplicationController) + framework.ExpectEqual(ok, true, "Unable to convert type of ReplicationController watch watchEvent") + if rc.ObjectMeta.Name == testRcName && rc.ObjectMeta.Namespace == testRcNamespace && rc.Status.Replicas == testRcMaxReplicaCount && rc.Status.ReadyReplicas == testRcMaxReplicaCount { + foundRcWithMaxScale = true + rcFromWatch = rc + break + } + } + framework.ExpectEqual(foundRcWithMaxScale, true, "failed to locate a ReplicationController with max scale") + framework.ExpectEqual(rcFromWatch.Status.Replicas, testRcMaxReplicaCount, "ReplicationController ReplicasSet Scale does not match the expected scale") + + // Get the ReplicationController + ginkgo.By("fetching ReplicationController; ensuring that it's patched") + rc, err := f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).Get(context.TODO(), testRcName, metav1.GetOptions{}) + framework.ExpectNoError(err, "failed to fetch ReplicationController") + framework.ExpectEqual(rc.ObjectMeta.Labels["test-rc"], "patched", "ReplicationController is missing a label from earlier patch") + + rcStatusUpdatePayload := rc + rcStatusUpdatePayload.Status.AvailableReplicas = 1 + rcStatusUpdatePayload.Status.ReadyReplicas = 1 + + // Replace the ReplicationController's status + ginkgo.By("updating ReplicationController status") + rcStatus, err = f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).UpdateStatus(context.TODO(), rcStatusUpdatePayload, metav1.UpdateOptions{}) + framework.ExpectNoError(err, "failed to update ReplicationControllerStatus") + framework.ExpectEqual(rcStatus.Status.ReadyReplicas, int32(1), "ReplicationControllerStatus readyReplicas does not equal 1") + + ginkgo.By(fmt.Sprintf("waiting for ReplicationController readyReplicas to be equal to %v", testRcMaxReplicaCount)) + for watchEvent := range rcWatchChan { + rc, ok := watchEvent.Object.(*v1.ReplicationController) + framework.ExpectEqual(ok, true, "unable to convert type of ReplicationController watch watchEvent") + if rc.Status.Replicas == testRcMaxReplicaCount && rc.Status.ReadyReplicas == testRcMaxReplicaCount { + break + } + } + + ginkgo.By("listing all ReplicationControllers") + rcs, err := f.ClientSet.CoreV1().ReplicationControllers("").List(context.TODO(), metav1.ListOptions{LabelSelector: "test-rc-static=true"}) + framework.ExpectNoError(err, "failed to list ReplicationController") + framework.ExpectEqual(len(rcs.Items) > 0, true) + + ginkgo.By("checking that ReplicationController has expected values") + foundRc := false + for _, rcItem := range rcs.Items { + if rcItem.ObjectMeta.Name == testRcName && + rcItem.ObjectMeta.Namespace == testRcNamespace && + rcItem.ObjectMeta.Labels["test-rc-static"] == "true" && + rcItem.ObjectMeta.Labels["test-rc"] == "patched" && + rcItem.Status.Replicas == testRcMaxReplicaCount && + rcItem.Status.ReadyReplicas == testRcMaxReplicaCount { + foundRc = true + } + } + framework.ExpectEqual(foundRc, true) + + // Delete ReplicationController + ginkgo.By("deleting ReplicationControllers by collection") + err = f.ClientSet.CoreV1().ReplicationControllers(testRcNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "test-rc-static=true"}) + framework.ExpectNoError(err, "Failed to delete ReplicationControllers") + + ginkgo.By("waiting for ReplicationController to have a DELETED watchEvent") + for watchEvent := range rcWatchChan { + if watchEvent.Type == "DELETED" { + break + } + } + }) }) func newRC(rsName string, replicas int32, rcPodLabels map[string]string, imageName string, image string, args []string) *v1.ReplicationController {