From 14246a94946ce1a93f1fc8b00be3ea50bb90a42b Mon Sep 17 00:00:00 2001 From: nikhiljindal Date: Wed, 9 Nov 2016 17:50:25 -0800 Subject: [PATCH] Updating federation e2e tests to verify cascading deletion --- test/e2e/federated-ingress.go | 99 ++++++++++++++++++----- test/e2e/federated-namespace.go | 40 ++++++---- test/e2e/federated-secret.go | 49 ++++++++---- test/e2e/federation-daemonset.go | 98 ++++++++++++++++++++++- test/e2e/federation-deployment.go | 126 ++++++++++++++++++++++++++---- test/e2e/federation-replicaset.go | 118 ++++++++++++++++++++++++---- 6 files changed, 450 insertions(+), 80 deletions(-) diff --git a/test/e2e/federated-ingress.go b/test/e2e/federated-ingress.go index b82bbc51f24..4cc309432e5 100644 --- a/test/e2e/federated-ingress.go +++ b/test/e2e/federated-ingress.go @@ -22,6 +22,7 @@ import ( "os" "reflect" "strconv" + "strings" "time" fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5" @@ -53,13 +54,8 @@ var _ = framework.KubeDescribe("Federated ingresses [Feature:Federation]", func( Describe("Federated Ingresses", func() { AfterEach(func() { nsName := f.FederationNamespace.Name - // Delete registered ingresses. - ingressList, err := f.FederationClientset_1_5.Extensions().Ingresses(nsName).List(v1.ListOptions{}) - Expect(err).NotTo(HaveOccurred()) - for _, ingress := range ingressList.Items { - err := f.FederationClientset_1_5.Extensions().Ingresses(nsName).Delete(ingress.Name, &v1.DeleteOptions{}) - Expect(err).NotTo(HaveOccurred()) - } + // Delete all ingresses. + deleteAllIngressesOrFail(f.FederationClientset_1_5, nsName) }) It("should be created and deleted successfully", func() { @@ -97,26 +93,43 @@ var _ = framework.KubeDescribe("Federated ingresses [Feature:Federation]", func( }) AfterEach(func() { + // Delete all ingresses. + nsName := f.FederationNamespace.Name + deleteAllIngressesOrFail(f.FederationClientset_1_5, nsName) unregisterClusters(clusters, f) }) It("should create and update matching ingresses in underlying clusters", func() { ingress := createIngressOrFail(f.FederationClientset_1_5, ns) - defer func() { // Cleanup - By(fmt.Sprintf("Deleting ingress %q in namespace %q", ingress.Name, ns)) - err := f.FederationClientset_1_5.Ingresses(ns).Delete(ingress.Name, &v1.DeleteOptions{}) - framework.ExpectNoError(err, "Error deleting ingress %q/%q in federation", ns, ingress.Name) - for clusterName, cluster := range clusters { - err := cluster.Ingresses(ns).Delete(ingress.Name, &v1.DeleteOptions{}) - framework.ExpectNoError(err, "Error deleting ingress %q/%q in cluster %q", ns, ingress.Name, clusterName) - } - }() // wait for ingress shards being created waitForIngressShardsOrFail(ns, ingress, clusters) ingress = updateIngressOrFail(f.FederationClientset_1_5, ns) waitForIngressShardsUpdatedOrFail(ns, ingress, clusters) }) + It("should be deleted from underlying clusters when OrphanDependents is false", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := false + verifyCascadingDeletionForIngress(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that ingresses were deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is true", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := true + verifyCascadingDeletionForIngress(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that ingresses were not deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is nil", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + verifyCascadingDeletionForIngress(f.FederationClientset_1_5, clusters, nil, nsName) + By(fmt.Sprintf("Verified that ingresses were not deleted from underlying clusters")) + }) + var _ = Describe("Ingress connectivity and DNS", func() { var ( @@ -147,7 +160,7 @@ var _ = framework.KubeDescribe("Federated ingresses [Feature:Federation]", func( By("No service to delete. Service is nil") } if jig.ing != nil { - deleteIngressOrFail(f.FederationClientset_1_5, ns, jig.ing.Name) + deleteIngressOrFail(f.FederationClientset_1_5, ns, jig.ing.Name, nil) for clusterName, cluster := range clusters { deleteClusterIngressOrFail(clusterName, cluster.Clientset, ns, jig.ing.Name) } @@ -182,6 +195,13 @@ var _ = framework.KubeDescribe("Federated ingresses [Feature:Federation]", func( }) }) +// Deletes all Ingresses in the given namespace name. +func deleteAllIngressesOrFail(clientset *fedclientset.Clientset, nsName string) { + orphanDependents := false + err := clientset.Extensions().Ingresses(nsName).DeleteCollection(&v1.DeleteOptions{OrphanDependents: &orphanDependents}, v1.ListOptions{}) + Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Error in deleting ingresses in namespace: %s", nsName)) +} + /* equivalent returns true if the two ingress spec are equivalent. */ @@ -189,6 +209,36 @@ func equivalentIngress(federatedIngress, clusterIngress v1beta1.Ingress) bool { return reflect.DeepEqual(clusterIngress.Spec, federatedIngress.Spec) } +// verifyCascadingDeletionForIngress verifies that ingresses are deleted from +// underlying clusters when orphan dependents is false and they are not deleted +// when orphan dependents is true. +func verifyCascadingDeletionForIngress(clientset *fedclientset.Clientset, clusters map[string]*cluster, orphanDependents *bool, nsName string) { + ingress := createIngressOrFail(clientset, nsName) + ingressName := ingress.Name + // Check subclusters if the ingress was created there. + By(fmt.Sprintf("Waiting for ingress %s to be created in all underlying clusters", ingressName)) + waitForIngressShardsOrFail(nsName, ingress, clusters) + + By(fmt.Sprintf("Deleting ingress %s", ingressName)) + deleteIngressOrFail(clientset, nsName, ingressName, orphanDependents) + + By(fmt.Sprintf("Verifying ingresses %s in underlying clusters", ingressName)) + errMessages := []string{} + // ingress should be present in underlying clusters unless orphanDependents is false. + shouldExist := orphanDependents == nil || *orphanDependents == true + for clusterName, clusterClientset := range clusters { + _, err := clusterClientset.Extensions().Ingresses(nsName).Get(ingressName) + if shouldExist && errors.IsNotFound(err) { + errMessages = append(errMessages, fmt.Sprintf("unexpected NotFound error for ingress %s in cluster %s, expected ingress to exist", ingressName, clusterName)) + } else if !shouldExist && !errors.IsNotFound(err) { + errMessages = append(errMessages, fmt.Sprintf("expected NotFound error for ingress %s in cluster %s, got error: %v", ingressName, clusterName, err)) + } + } + if len(errMessages) != 0 { + framework.Failf("%s", strings.Join(errMessages, "; ")) + } +} + /* waitForIngressOrFail waits until a ingress is either present or absent in the cluster specified by clientset. If the condition is not met within timout, it fails the calling test. @@ -268,12 +318,23 @@ func waitForIngressShardsGoneOrFail(namespace string, ingress *v1beta1.Ingress, } } -func deleteIngressOrFail(clientset *fedclientset.Clientset, namespace string, ingressName string) { +func deleteIngressOrFail(clientset *fedclientset.Clientset, namespace string, ingressName string, orphanDependents *bool) { if clientset == nil || len(namespace) == 0 || len(ingressName) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to deleteIngressOrFail: clientset: %v, namespace: %v, ingress: %v", clientset, namespace, ingressName)) } - err := clientset.Ingresses(namespace).Delete(ingressName, v1.NewDeleteOptions(0)) + err := clientset.Ingresses(namespace).Delete(ingressName, &v1.DeleteOptions{OrphanDependents: orphanDependents}) framework.ExpectNoError(err, "Error deleting ingress %q from namespace %q", ingressName, namespace) + // Wait for the ingress to be deleted. + err = wait.Poll(framework.Poll, wait.ForeverTestTimeout, func() (bool, error) { + _, err := clientset.Extensions().Ingresses(namespace).Get(ingressName) + if err != nil && errors.IsNotFound(err) { + return true, nil + } + return false, err + }) + if err != nil { + framework.Failf("Error in deleting ingress %s: %v", ingressName, err) + } } // TODO: quinton: This is largely a cut 'n paste of the above. Yuck! Refactor as soon as we have a common interface implmented by both fedclientset.Clientset and kubeclientset.Clientset diff --git a/test/e2e/federated-namespace.go b/test/e2e/federated-namespace.go index 30f16699032..5b5be964d34 100644 --- a/test/e2e/federated-namespace.go +++ b/test/e2e/federated-namespace.go @@ -59,11 +59,11 @@ var _ = framework.KubeDescribe("Federation namespace [Feature:Federation]", func AfterEach(func() { framework.SkipUnlessFederated(f.ClientSet) - deleteAllTestNamespaces(false, + deleteAllTestNamespaces(nil, f.FederationClientset_1_5.Core().Namespaces().List, f.FederationClientset_1_5.Core().Namespaces().Delete) for _, cluster := range clusters { - deleteAllTestNamespaces(false, + deleteAllTestNamespaces(nil, cluster.Core().Namespaces().List, cluster.Core().Namespaces().Delete) } @@ -76,22 +76,30 @@ var _ = framework.KubeDescribe("Federation namespace [Feature:Federation]", func nsName := createNamespace(f.FederationClientset_1_5.Core().Namespaces()) By(fmt.Sprintf("Deleting namespace %s", nsName)) - deleteAllTestNamespaces(false, + deleteAllTestNamespaces(nil, f.FederationClientset_1_5.Core().Namespaces().List, f.FederationClientset_1_5.Core().Namespaces().Delete) By(fmt.Sprintf("Verified that deletion succeeded")) }) + It("should be deleted from underlying clusters when OrphanDependents is false", func() { framework.SkipUnlessFederated(f.ClientSet) - - verifyNsCascadingDeletion(f.FederationClientset_1_5.Core().Namespaces(), clusters, false) + orphanDependents := false + verifyNsCascadingDeletion(f.FederationClientset_1_5.Core().Namespaces(), clusters, &orphanDependents) By(fmt.Sprintf("Verified that namespaces were deleted from underlying clusters")) }) It("should not be deleted from underlying clusters when OrphanDependents is true", func() { framework.SkipUnlessFederated(f.ClientSet) + orphanDependents := true + verifyNsCascadingDeletion(f.FederationClientset_1_5.Core().Namespaces(), clusters, &orphanDependents) + By(fmt.Sprintf("Verified that namespaces were not deleted from underlying clusters")) + }) - verifyNsCascadingDeletion(f.FederationClientset_1_5.Core().Namespaces(), clusters, true) + It("should not be deleted from underlying clusters when OrphanDependents is nil", func() { + framework.SkipUnlessFederated(f.ClientSet) + + verifyNsCascadingDeletion(f.FederationClientset_1_5.Core().Namespaces(), clusters, nil) By(fmt.Sprintf("Verified that namespaces were not deleted from underlying clusters")) }) @@ -119,7 +127,7 @@ var _ = framework.KubeDescribe("Federation namespace [Feature:Federation]", func } By(fmt.Sprintf("Deleting namespace %s", nsName)) - deleteAllTestNamespaces(false, + deleteAllTestNamespaces(nil, f.FederationClientset_1_5.Core().Namespaces().List, f.FederationClientset_1_5.Core().Namespaces().Delete) @@ -133,10 +141,10 @@ var _ = framework.KubeDescribe("Federation namespace [Feature:Federation]", func }) }) -// Verifies that namespaces are deleted from underlying clusters when orphan dependents is false -// and they are not deleted when orphan dependents is true. -func verifyNsCascadingDeletion(nsClient clientset.NamespaceInterface, - clusters map[string]*cluster, orphanDependents bool) { +// verifyNsCascadingDeletion verifies that namespaces are deleted from +// underlying clusters when orphan dependents is false and they are not +// deleted when orphan dependents is true. +func verifyNsCascadingDeletion(nsClient clientset.NamespaceInterface, clusters map[string]*cluster, orphanDependents *bool) { nsName := createNamespace(nsClient) // Check subclusters if the namespace was created there. By(fmt.Sprintf("Waiting for namespace %s to be created in all underlying clusters", nsName)) @@ -159,11 +167,13 @@ func verifyNsCascadingDeletion(nsClient clientset.NamespaceInterface, By(fmt.Sprintf("Verifying namespaces %s in underlying clusters", nsName)) errMessages := []string{} + // namespace should be present in underlying clusters unless orphanDependents is false. + shouldExist := orphanDependents == nil || *orphanDependents == true for clusterName, clusterClientset := range clusters { _, err := clusterClientset.Core().Namespaces().Get(nsName) - if orphanDependents && errors.IsNotFound(err) { + if shouldExist && errors.IsNotFound(err) { errMessages = append(errMessages, fmt.Sprintf("unexpected NotFound error for namespace %s in cluster %s, expected namespace to exist", nsName, clusterName)) - } else if !orphanDependents && (err == nil || !errors.IsNotFound(err)) { + } else if !shouldExist && !errors.IsNotFound(err) { errMessages = append(errMessages, fmt.Sprintf("expected NotFound error for namespace %s in cluster %s, got error: %v", nsName, clusterName, err)) } } @@ -185,7 +195,7 @@ func createNamespace(nsClient clientset.NamespaceInterface) string { return ns.Name } -func deleteAllTestNamespaces(orphanDependents bool, lister func(api_v1.ListOptions) (*api_v1.NamespaceList, error), deleter func(string, *api_v1.DeleteOptions) error) { +func deleteAllTestNamespaces(orphanDependents *bool, lister func(api_v1.ListOptions) (*api_v1.NamespaceList, error), deleter func(string, *api_v1.DeleteOptions) error) { list, err := lister(api_v1.ListOptions{}) if err != nil { framework.Failf("Failed to get all namespaes: %v", err) @@ -194,7 +204,7 @@ func deleteAllTestNamespaces(orphanDependents bool, lister func(api_v1.ListOptio for _, namespace := range list.Items { if strings.HasPrefix(namespace.Name, namespacePrefix) { By(fmt.Sprintf("Deleting ns: %s, found by listing", namespace.Name)) - err := deleter(namespace.Name, &api_v1.DeleteOptions{OrphanDependents: &orphanDependents}) + err := deleter(namespace.Name, &api_v1.DeleteOptions{OrphanDependents: orphanDependents}) if err != nil { framework.Failf("Failed to set %s for deletion: %v", namespace.Name, err) } diff --git a/test/e2e/federated-secret.go b/test/e2e/federated-secret.go index f4bf0c56b11..ae7a5dba2d0 100644 --- a/test/e2e/federated-secret.go +++ b/test/e2e/federated-secret.go @@ -55,16 +55,17 @@ var _ = framework.KubeDescribe("Federation secrets [Feature:Federation]", func() AfterEach(func() { framework.SkipUnlessFederated(f.ClientSet) + // Delete all secrets. + nsName := f.FederationNamespace.Name + deleteAllSecretsOrFail(f.FederationClientset_1_5, nsName) unregisterClusters(clusters, f) + }) It("should be created and deleted successfully", func() { framework.SkipUnlessFederated(f.ClientSet) nsName := f.FederationNamespace.Name secret := createSecretOrFail(f.FederationClientset_1_5, nsName) - defer func() { // Cleanup - deleteSecretOrFail(f.FederationClientset_1_5, nsName, secret.Name, true) - }() // wait for secret shards being created waitForSecretShardsOrFail(nsName, secret, clusters) secret = updateSecretOrFail(f.FederationClientset_1_5, nsName, secret.Name) @@ -74,23 +75,42 @@ var _ = framework.KubeDescribe("Federation secrets [Feature:Federation]", func() It("should be deleted from underlying clusters when OrphanDependents is false", func() { framework.SkipUnlessFederated(f.ClientSet) nsName := f.FederationNamespace.Name - verifyCascadingDeletion(f.FederationClientset_1_5, clusters, false, nsName) + orphanDependents := false + verifyCascadingDeletionForSecret(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) By(fmt.Sprintf("Verified that secrets were deleted from underlying clusters")) }) It("should not be deleted from underlying clusters when OrphanDependents is true", func() { framework.SkipUnlessFederated(f.ClientSet) nsName := f.FederationNamespace.Name - verifyCascadingDeletion(f.FederationClientset_1_5, clusters, true, nsName) + orphanDependents := true + verifyCascadingDeletionForSecret(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that secrets were not deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is nil", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + verifyCascadingDeletionForSecret(f.FederationClientset_1_5, clusters, nil, nsName) By(fmt.Sprintf("Verified that secrets were not deleted from underlying clusters")) }) }) }) -// Verifies that secrets are deleted from underlying clusters when orphan dependents is false -// and they are not deleted when orphan dependents is true. -func verifyCascadingDeletion(clientset *fedclientset.Clientset, - clusters map[string]*cluster, orphanDependents bool, nsName string) { +// deleteAllSecretsOrFail deletes all secrets in the given namespace name. +func deleteAllSecretsOrFail(clientset *fedclientset.Clientset, nsName string) { + SecretList, err := clientset.Core().Secrets(nsName).List(v1.ListOptions{}) + Expect(err).NotTo(HaveOccurred()) + orphanDependents := false + for _, Secret := range SecretList.Items { + deleteSecretOrFail(clientset, nsName, Secret.Name, &orphanDependents) + } +} + +// verifyCascadingDeletionForSecret verifies that secrets are deleted from +// underlying clusters when orphan dependents is false and they are not +// deleted when orphan dependents is true. +func verifyCascadingDeletionForSecret(clientset *fedclientset.Clientset, clusters map[string]*cluster, orphanDependents *bool, nsName string) { secret := createSecretOrFail(clientset, nsName) secretName := secret.Name // Check subclusters if the secret was created there. @@ -104,7 +124,6 @@ func verifyCascadingDeletion(clientset *fedclientset.Clientset, } return false, nil } - } return true, nil }) @@ -115,11 +134,13 @@ func verifyCascadingDeletion(clientset *fedclientset.Clientset, By(fmt.Sprintf("Verifying secrets %s in underlying clusters", secretName)) errMessages := []string{} + // secret should be present in underlying clusters unless orphanDependents is false. + shouldExist := orphanDependents == nil || *orphanDependents == true for clusterName, clusterClientset := range clusters { _, err := clusterClientset.Core().Secrets(nsName).Get(secretName) - if orphanDependents && errors.IsNotFound(err) { + if shouldExist && errors.IsNotFound(err) { errMessages = append(errMessages, fmt.Sprintf("unexpected NotFound error for secret %s in cluster %s, expected secret to exist", secretName, clusterName)) - } else if !orphanDependents && (err == nil || !errors.IsNotFound(err)) { + } else if !shouldExist && !errors.IsNotFound(err) { errMessages = append(errMessages, fmt.Sprintf("expected NotFound error for secret %s in cluster %s, got error: %v", secretName, clusterName, err)) } } @@ -146,9 +167,9 @@ func createSecretOrFail(clientset *fedclientset.Clientset, nsName string) *v1.Se return secret } -func deleteSecretOrFail(clientset *fedclientset.Clientset, nsName string, secretName string, orphanDependents bool) { +func deleteSecretOrFail(clientset *fedclientset.Clientset, nsName string, secretName string, orphanDependents *bool) { By(fmt.Sprintf("Deleting secret %q in namespace %q", secretName, nsName)) - err := clientset.Core().Secrets(nsName).Delete(secretName, &v1.DeleteOptions{OrphanDependents: &orphanDependents}) + err := clientset.Core().Secrets(nsName).Delete(secretName, &v1.DeleteOptions{OrphanDependents: orphanDependents}) framework.ExpectNoError(err, "Error deleting secret %q in namespace %q", secretName, nsName) // Wait for the secret to be deleted. diff --git a/test/e2e/federation-daemonset.go b/test/e2e/federation-daemonset.go index d6a5c858bd5..b5facdcaafe 100644 --- a/test/e2e/federation-daemonset.go +++ b/test/e2e/federation-daemonset.go @@ -18,6 +18,7 @@ package e2e import ( "fmt" + "strings" "time" . "github.com/onsi/ginkgo" @@ -39,7 +40,7 @@ const ( ) // Create/delete daemonset api objects -var _ = framework.KubeDescribe("Federation daemonsets [Feature:Federation12]", func() { +var _ = framework.KubeDescribe("Federation daemonsets [Feature:Federation]", func() { var clusters map[string]*cluster // All clusters, keyed by cluster name f := framework.NewDefaultFederatedFramework("federated-daemonset") @@ -54,6 +55,9 @@ var _ = framework.KubeDescribe("Federation daemonsets [Feature:Federation12]", f AfterEach(func() { framework.SkipUnlessFederated(f.ClientSet) + // Delete all daemonsets. + nsName := f.FederationNamespace.Name + deleteAllDaemonSetsOrFail(f.FederationClientset_1_5, nsName) unregisterClusters(clusters, f) }) @@ -71,9 +75,83 @@ var _ = framework.KubeDescribe("Federation daemonsets [Feature:Federation12]", f daemonset = updateDaemonSetOrFail(f.FederationClientset_1_5, nsName) waitForDaemonSetShardsUpdatedOrFail(nsName, daemonset, clusters) }) + + It("should be deleted from underlying clusters when OrphanDependents is false", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := false + verifyCascadingDeletionForDS(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that daemonsets were deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is true", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := true + verifyCascadingDeletionForDS(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that daemonsets were not deleted from underlying clusters")) + }) + It("should not be deleted from underlying clusters when OrphanDependents is nil", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + verifyCascadingDeletionForDS(f.FederationClientset_1_5, clusters, nil, nsName) + By(fmt.Sprintf("Verified that daemonsets were not deleted from underlying clusters")) + }) }) }) +// deleteAllDaemonSetsOrFail deletes all DaemonSets in the given namespace name. +func deleteAllDaemonSetsOrFail(clientset *fedclientset.Clientset, nsName string) { + DaemonSetList, err := clientset.Extensions().DaemonSets(nsName).List(v1.ListOptions{}) + Expect(err).NotTo(HaveOccurred()) + orphanDependents := false + for _, daemonSet := range DaemonSetList.Items { + deleteDaemonSetOrFail(clientset, nsName, daemonSet.Name, &orphanDependents) + } +} + +// verifyCascadingDeletionForDS verifies that daemonsets are deleted from +// underlying clusters when orphan dependents is false and they are not +// deleted when orphan dependents is true. +func verifyCascadingDeletionForDS(clientset *fedclientset.Clientset, clusters map[string]*cluster, orphanDependents *bool, nsName string) { + daemonset := createDaemonSetOrFail(clientset, nsName) + daemonsetName := daemonset.Name + // Check subclusters if the daemonset was created there. + By(fmt.Sprintf("Waiting for daemonset %s to be created in all underlying clusters", daemonsetName)) + err := wait.Poll(5*time.Second, 2*time.Minute, func() (bool, error) { + for _, cluster := range clusters { + _, err := cluster.Extensions().DaemonSets(nsName).Get(daemonsetName) + if err != nil && errors.IsNotFound(err) { + return false, nil + } + if err != nil { + return false, err + } + } + return true, nil + }) + framework.ExpectNoError(err, "Not all daemonsets created") + + By(fmt.Sprintf("Deleting daemonset %s", daemonsetName)) + deleteDaemonSetOrFail(clientset, nsName, daemonsetName, orphanDependents) + + By(fmt.Sprintf("Verifying daemonsets %s in underlying clusters", daemonsetName)) + errMessages := []string{} + // daemon set should be present in underlying clusters unless orphanDependents is false. + shouldExist := orphanDependents == nil || *orphanDependents == true + for clusterName, clusterClientset := range clusters { + _, err := clusterClientset.Extensions().DaemonSets(nsName).Get(daemonsetName) + if shouldExist && errors.IsNotFound(err) { + errMessages = append(errMessages, fmt.Sprintf("unexpected NotFound error for daemonset %s in cluster %s, expected daemonset to exist", daemonsetName, clusterName)) + } else if !shouldExist && !errors.IsNotFound(err) { + errMessages = append(errMessages, fmt.Sprintf("expected NotFound error for daemonset %s in cluster %s, got error: %v", daemonsetName, clusterName, err)) + } + } + if len(errMessages) != 0 { + framework.Failf("%s", strings.Join(errMessages, "; ")) + } +} + func createDaemonSetOrFail(clientset *fedclientset.Clientset, namespace string) *v1beta1.DaemonSet { if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to createDaemonSetOrFail: clientset: %v, namespace: %v", clientset, namespace)) @@ -108,6 +186,24 @@ func createDaemonSetOrFail(clientset *fedclientset.Clientset, namespace string) return daemonset } +func deleteDaemonSetOrFail(clientset *fedclientset.Clientset, nsName string, daemonsetName string, orphanDependents *bool) { + By(fmt.Sprintf("Deleting daemonset %q in namespace %q", daemonsetName, nsName)) + err := clientset.Extensions().DaemonSets(nsName).Delete(daemonsetName, &v1.DeleteOptions{OrphanDependents: orphanDependents}) + framework.ExpectNoError(err, "Error deleting daemonset %q in namespace %q", daemonsetName, nsName) + + // Wait for the daemonset to be deleted. + err = wait.Poll(5*time.Second, wait.ForeverTestTimeout, func() (bool, error) { + _, err := clientset.Extensions().DaemonSets(nsName).Get(daemonsetName) + if err != nil && errors.IsNotFound(err) { + return true, nil + } + return false, err + }) + if err != nil { + framework.Failf("Error in deleting daemonset %s: %v", daemonsetName, err) + } +} + func updateDaemonSetOrFail(clientset *fedclientset.Clientset, namespace string) *v1beta1.DaemonSet { if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to updateDaemonSetOrFail: clientset: %v, namespace: %v", clientset, namespace)) diff --git a/test/e2e/federation-deployment.go b/test/e2e/federation-deployment.go index 54900aad6e0..9ee527fdeb3 100644 --- a/test/e2e/federation-deployment.go +++ b/test/e2e/federation-deployment.go @@ -19,9 +19,10 @@ package e2e import ( "fmt" "os" + "strings" "time" - "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5" + fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5" fedutil "k8s.io/kubernetes/federation/pkg/federation-controller/util" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/v1" @@ -49,14 +50,9 @@ var _ = framework.KubeDescribe("Federation deployments [Feature:Federation]", fu AfterEach(func() { framework.SkipUnlessFederated(f.ClientSet) - // Delete registered deployments. + // Delete all deployments. nsName := f.FederationNamespace.Name - deploymentList, err := f.FederationClientset_1_5.Extensions().Deployments(nsName).List(v1.ListOptions{}) - Expect(err).NotTo(HaveOccurred()) - for _, deployment := range deploymentList.Items { - err := f.FederationClientset_1_5.Extensions().Deployments(nsName).Delete(deployment.Name, &v1.DeleteOptions{}) - Expect(err).NotTo(HaveOccurred()) - } + deleteAllDeploymentsOrFail(f.FederationClientset_1_5, nsName) }) It("should be created and deleted successfully", func() { @@ -89,6 +85,8 @@ var _ = framework.KubeDescribe("Federation deployments [Feature:Federation]", fu }) AfterEach(func() { + nsName := f.FederationNamespace.Name + deleteAllDeploymentsOrFail(f.FederationClientset_1_5, nsName) unregisterClusters(clusters, f) }) @@ -111,25 +109,101 @@ var _ = framework.KubeDescribe("Federation deployments [Feature:Federation]", fu waitForDeploymentOrFail(f.FederationClientset_1_5, nsName, dep.Name, clusters) By(fmt.Sprintf("Successfuly updated and synced deployment %q/%q to clusters", nsName, dep.Name)) }) + + It("should be deleted from underlying clusters when OrphanDependents is false", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := false + verifyCascadingDeletionForDeployment(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that deployments were deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is true", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := true + verifyCascadingDeletionForDeployment(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that deployments were not deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is nil", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + verifyCascadingDeletionForDeployment(f.FederationClientset_1_5, clusters, nil, nsName) + By(fmt.Sprintf("Verified that deployments were not deleted from underlying clusters")) + }) + }) }) -func waitForDeploymentOrFail(c *federation_release_1_5.Clientset, namespace string, replicaSetName string, clusters map[string]*cluster) { - err := waitForDeployment(c, namespace, replicaSetName, clusters) - framework.ExpectNoError(err, "Failed to verify deployment %q/%q, err: %v", namespace, replicaSetName, err) +// deleteAllDeploymentsOrFail deletes all deployments in the given namespace name. +func deleteAllDeploymentsOrFail(clientset *fedclientset.Clientset, nsName string) { + deploymentList, err := clientset.Extensions().Deployments(nsName).List(v1.ListOptions{}) + Expect(err).NotTo(HaveOccurred()) + orphanDependents := false + for _, deployment := range deploymentList.Items { + deleteDeploymentOrFail(clientset, nsName, deployment.Name, &orphanDependents) + } } -func waitForDeployment(c *federation_release_1_5.Clientset, namespace string, replicaSetName string, clusters map[string]*cluster) error { +// verifyCascadingDeletionForDeployment verifies that deployments are deleted +// from underlying clusters when orphan dependents is false and they are not +// deleted when orphan dependents is true. +func verifyCascadingDeletionForDeployment(clientset *fedclientset.Clientset, clusters map[string]*cluster, orphanDependents *bool, nsName string) { + deployment := createDeploymentOrFail(clientset, nsName) + deploymentName := deployment.Name + // Check subclusters if the deployment was created there. + By(fmt.Sprintf("Waiting for deployment %s to be created in all underlying clusters", deploymentName)) + err := wait.Poll(5*time.Second, 2*time.Minute, func() (bool, error) { + for _, cluster := range clusters { + _, err := cluster.Extensions().Deployments(nsName).Get(deploymentName) + if err != nil && errors.IsNotFound(err) { + return false, nil + } + if err != nil { + return false, err + } + } + return true, nil + }) + framework.ExpectNoError(err, "Not all deployments created") + + By(fmt.Sprintf("Deleting deployment %s", deploymentName)) + deleteDeploymentOrFail(clientset, nsName, deploymentName, orphanDependents) + + By(fmt.Sprintf("Verifying deployments %s in underlying clusters", deploymentName)) + errMessages := []string{} + // deployment should be present in underlying clusters unless orphanDependents is false. + shouldExist := orphanDependents == nil || *orphanDependents == true + for clusterName, clusterClientset := range clusters { + _, err := clusterClientset.Extensions().Deployments(nsName).Get(deploymentName) + if shouldExist && errors.IsNotFound(err) { + errMessages = append(errMessages, fmt.Sprintf("unexpected NotFound error for deployment %s in cluster %s, expected deployment to exist", deploymentName, clusterName)) + } else if shouldExist && !errors.IsNotFound(err) { + errMessages = append(errMessages, fmt.Sprintf("expected NotFound error for deployment %s in cluster %s, got error: %v", deploymentName, clusterName, err)) + } + } + if len(errMessages) != 0 { + framework.Failf("%s", strings.Join(errMessages, "; ")) + } +} + +func waitForDeploymentOrFail(c *fedclientset.Clientset, namespace string, deploymentName string, clusters map[string]*cluster) { + err := waitForDeployment(c, namespace, deploymentName, clusters) + framework.ExpectNoError(err, "Failed to verify deployment %q/%q, err: %v", namespace, deploymentName, err) +} + +func waitForDeployment(c *fedclientset.Clientset, namespace string, deploymentName string, clusters map[string]*cluster) error { err := wait.Poll(10*time.Second, FederatedDeploymentTimeout, func() (bool, error) { - fdep, err := c.Deployments(namespace).Get(replicaSetName) + fdep, err := c.Deployments(namespace).Get(deploymentName) if err != nil { return false, err } specReplicas, statusReplicas := int32(0), int32(0) for _, cluster := range clusters { - dep, err := cluster.Deployments(namespace).Get(replicaSetName) + dep, err := cluster.Deployments(namespace).Get(deploymentName) if err != nil && !errors.IsNotFound(err) { - By(fmt.Sprintf("Failed getting deployment: %q/%q/%q, err: %v", cluster.name, namespace, replicaSetName, err)) + By(fmt.Sprintf("Failed getting deployment: %q/%q/%q, err: %v", cluster.name, namespace, deploymentName, err)) return false, err } if err == nil { @@ -158,7 +232,7 @@ func equivalentDeployment(fedDeployment, localDeployment *v1beta1.Deployment) bo reflect.DeepEqual(fedDeployment.Spec, localDeploymentSpec) } -func createDeploymentOrFail(clientset *federation_release_1_5.Clientset, namespace string) *v1beta1.Deployment { +func createDeploymentOrFail(clientset *fedclientset.Clientset, namespace string) *v1beta1.Deployment { if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to createDeploymentOrFail: clientset: %v, namespace: %v", clientset, namespace)) } @@ -172,7 +246,7 @@ func createDeploymentOrFail(clientset *federation_release_1_5.Clientset, namespa return deployment } -func updateDeploymentOrFail(clientset *federation_release_1_5.Clientset, namespace string) *v1beta1.Deployment { +func updateDeploymentOrFail(clientset *fedclientset.Clientset, namespace string) *v1beta1.Deployment { if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to updateDeploymentOrFail: clientset: %v, namespace: %v", clientset, namespace)) } @@ -187,6 +261,24 @@ func updateDeploymentOrFail(clientset *federation_release_1_5.Clientset, namespa return newRs } +func deleteDeploymentOrFail(clientset *fedclientset.Clientset, nsName string, deploymentName string, orphanDependents *bool) { + By(fmt.Sprintf("Deleting deployment %q in namespace %q", deploymentName, nsName)) + err := clientset.Extensions().Deployments(nsName).Delete(deploymentName, &v1.DeleteOptions{OrphanDependents: orphanDependents}) + framework.ExpectNoError(err, "Error deleting deployment %q in namespace %q", deploymentName, nsName) + + // Wait for the deployment to be deleted. + err = wait.Poll(5*time.Second, wait.ForeverTestTimeout, func() (bool, error) { + _, err := clientset.Extensions().Deployments(nsName).Get(deploymentName) + if err != nil && errors.IsNotFound(err) { + return true, nil + } + return false, err + }) + if err != nil { + framework.Failf("Error in deleting deployment %s: %v", deploymentName, err) + } +} + func newDeploymentForFed(namespace string, name string, replicas int32) *v1beta1.Deployment { return &v1beta1.Deployment{ ObjectMeta: v1.ObjectMeta{ diff --git a/test/e2e/federation-replicaset.go b/test/e2e/federation-replicaset.go index afeae884e9a..c7473a4d75e 100644 --- a/test/e2e/federation-replicaset.go +++ b/test/e2e/federation-replicaset.go @@ -19,9 +19,10 @@ package e2e import ( "fmt" "os" + "strings" "time" - "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5" + fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_5" fedutil "k8s.io/kubernetes/federation/pkg/federation-controller/util" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/v1" @@ -49,14 +50,9 @@ var _ = framework.KubeDescribe("Federation replicasets [Feature:Federation]", fu AfterEach(func() { framework.SkipUnlessFederated(f.ClientSet) - // Delete registered replicasets. + // Delete all replicasets. nsName := f.FederationNamespace.Name - replicasetList, err := f.FederationClientset_1_5.Extensions().ReplicaSets(nsName).List(v1.ListOptions{}) - Expect(err).NotTo(HaveOccurred()) - for _, replicaset := range replicasetList.Items { - err := f.FederationClientset_1_5.Extensions().ReplicaSets(nsName).Delete(replicaset.Name, &v1.DeleteOptions{}) - Expect(err).NotTo(HaveOccurred()) - } + deleteAllReplicaSetsOrFail(f.FederationClientset_1_5, nsName) }) It("should be created and deleted successfully", func() { @@ -89,6 +85,9 @@ var _ = framework.KubeDescribe("Federation replicasets [Feature:Federation]", fu }) AfterEach(func() { + // Delete all replicasets. + nsName := f.FederationNamespace.Name + deleteAllReplicaSetsOrFail(f.FederationClientset_1_5, nsName) unregisterClusters(clusters, f) }) @@ -111,15 +110,88 @@ var _ = framework.KubeDescribe("Federation replicasets [Feature:Federation]", fu waitForReplicaSetOrFail(f.FederationClientset_1_5, nsName, rs.Name, clusters) By(fmt.Sprintf("Successfuly updated and synced replicaset %q/%q to clusters", nsName, rs.Name)) }) + + It("should be deleted from underlying clusters when OrphanDependents is false", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := false + verifyCascadingDeletionForReplicaSet(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that replica sets were deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is true", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + orphanDependents := true + verifyCascadingDeletionForReplicaSet(f.FederationClientset_1_5, clusters, &orphanDependents, nsName) + By(fmt.Sprintf("Verified that replica sets were not deleted from underlying clusters")) + }) + + It("should not be deleted from underlying clusters when OrphanDependents is nil", func() { + framework.SkipUnlessFederated(f.ClientSet) + nsName := f.FederationNamespace.Name + verifyCascadingDeletionForReplicaSet(f.FederationClientset_1_5, clusters, nil, nsName) + By(fmt.Sprintf("Verified that replica sets were not deleted from underlying clusters")) + }) }) }) -func waitForReplicaSetOrFail(c *federation_release_1_5.Clientset, namespace string, replicaSetName string, clusters map[string]*cluster) { - err := waitForReplicaSet(c, namespace, replicaSetName, clusters) - framework.ExpectNoError(err, "Failed to verify replicaset %q/%q, err: %v", namespace, replicaSetName, err) +// deleteAllReplicaSetsOrFail deletes all replicasets in the given namespace name. +func deleteAllReplicaSetsOrFail(clientset *fedclientset.Clientset, nsName string) { + replicasetList, err := clientset.Extensions().ReplicaSets(nsName).List(v1.ListOptions{}) + Expect(err).NotTo(HaveOccurred()) + orphanDependents := false + for _, replicaset := range replicasetList.Items { + deleteReplicaSetOrFail(clientset, nsName, replicaset.Name, &orphanDependents) + } } -func waitForReplicaSet(c *federation_release_1_5.Clientset, namespace string, replicaSetName string, clusters map[string]*cluster) error { +// verifyCascadingDeletionForReplicaSet verifies that replicaSets are deleted +// from underlying clusters when orphan dependents is false and they are not +// deleted when orphan dependents is true. +func verifyCascadingDeletionForReplicaSet(clientset *fedclientset.Clientset, clusters map[string]*cluster, orphanDependents *bool, nsName string) { + replicaSet := createReplicaSetOrFail(clientset, nsName) + replicaSetName := replicaSet.Name + // Check subclusters if the replicaSet was created there. + By(fmt.Sprintf("Waiting for replica sets %s to be created in all underlying clusters", replicaSetName)) + err := wait.Poll(5*time.Second, 2*time.Minute, func() (bool, error) { + for _, cluster := range clusters { + _, err := cluster.Extensions().ReplicaSets(nsName).Get(replicaSetName) + if err != nil && errors.IsNotFound(err) { + return false, nil + } + if err != nil { + return false, err + } + } + return true, nil + }) + framework.ExpectNoError(err, "Not all replica sets created") + + By(fmt.Sprintf("Deleting replica set %s", replicaSetName)) + deleteReplicaSetOrFail(clientset, nsName, replicaSetName, orphanDependents) + + By(fmt.Sprintf("Verifying replica sets %s in underlying clusters", replicaSetName)) + errMessages := []string{} + for clusterName, clusterClientset := range clusters { + _, err := clusterClientset.Extensions().ReplicaSets(nsName).Get(replicaSetName) + if (orphanDependents == nil || *orphanDependents == true) && errors.IsNotFound(err) { + errMessages = append(errMessages, fmt.Sprintf("unexpected NotFound error for replica set %s in cluster %s, expected replica set to exist", replicaSetName, clusterName)) + } else if (orphanDependents != nil && *orphanDependents == false) && (err == nil || !errors.IsNotFound(err)) { + errMessages = append(errMessages, fmt.Sprintf("expected NotFound error for replica set %s in cluster %s, got error: %v", replicaSetName, clusterName, err)) + } + } + if len(errMessages) != 0 { + framework.Failf("%s", strings.Join(errMessages, "; ")) + } +} + +func waitForReplicaSetOrFail(c *fedclientset.Clientset, namespace string, replicaSetName string, clusters map[string]*cluster) { + err := waitForReplicaSet(c, namespace, replicaSetName, clusters) + framework.ExpectNoError(err, "Failed to verify replica set %q/%q, err: %v", namespace, replicaSetName, err) +} + +func waitForReplicaSet(c *fedclientset.Clientset, namespace string, replicaSetName string, clusters map[string]*cluster) error { err := wait.Poll(10*time.Second, FederatedReplicaSetTimeout, func() (bool, error) { frs, err := c.ReplicaSets(namespace).Get(replicaSetName) if err != nil { @@ -158,7 +230,7 @@ func equivalentReplicaSet(fedReplicaSet, localReplicaSet *v1beta1.ReplicaSet) bo reflect.DeepEqual(fedReplicaSet.Spec, localReplicaSetSpec) } -func createReplicaSetOrFail(clientset *federation_release_1_5.Clientset, namespace string) *v1beta1.ReplicaSet { +func createReplicaSetOrFail(clientset *fedclientset.Clientset, namespace string) *v1beta1.ReplicaSet { if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to createReplicaSetOrFail: clientset: %v, namespace: %v", clientset, namespace)) } @@ -172,7 +244,25 @@ func createReplicaSetOrFail(clientset *federation_release_1_5.Clientset, namespa return replicaset } -func updateReplicaSetOrFail(clientset *federation_release_1_5.Clientset, namespace string) *v1beta1.ReplicaSet { +func deleteReplicaSetOrFail(clientset *fedclientset.Clientset, nsName string, replicaSetName string, orphanDependents *bool) { + By(fmt.Sprintf("Deleting replica set %q in namespace %q", replicaSetName, nsName)) + err := clientset.Extensions().ReplicaSets(nsName).Delete(replicaSetName, &v1.DeleteOptions{OrphanDependents: orphanDependents}) + framework.ExpectNoError(err, "Error deleting replica set %q in namespace %q", replicaSetName, nsName) + + // Wait for the replicaSet to be deleted. + err = wait.Poll(5*time.Second, wait.ForeverTestTimeout, func() (bool, error) { + _, err := clientset.Extensions().ReplicaSets(nsName).Get(replicaSetName) + if err != nil && errors.IsNotFound(err) { + return true, nil + } + return false, err + }) + if err != nil { + framework.Failf("Error in deleting replica set %s: %v", replicaSetName, err) + } +} + +func updateReplicaSetOrFail(clientset *fedclientset.Clientset, namespace string) *v1beta1.ReplicaSet { if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to updateReplicaSetOrFail: clientset: %v, namespace: %v", clientset, namespace)) }