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)) } diff --git a/test/test_owners.csv b/test/test_owners.csv index 79e5ffe50f5..ed4c87ab1e5 100644 --- a/test/test_owners.csv +++ b/test/test_owners.csv @@ -142,27 +142,43 @@ Federated Services Service creation should create matching services in underlyin Federated Services Service creation should succeed,rmmh,1 Federated ingresses Federated Ingresses Ingress connectivity and DNS should be able to connect to a federated ingress via its load balancer,rmmh,1 Federated ingresses Federated Ingresses should be created and deleted successfully,dchen1107,1 +Federated ingresses Federated Ingresses should be deleted from underlying clusters when OrphanDependents is false,nikhiljindal,0 Federated ingresses Federated Ingresses should create and update matching ingresses in underlying clusters,ghodss,1 +Federated ingresses Federated Ingresses should not be deleted from underlying clusters when OrphanDependents is nil,nikhiljindal,0 +Federated ingresses Federated Ingresses should not be deleted from underlying clusters when OrphanDependents is true,nikhiljindal,0 Federation API server authentication should accept cluster resources when the client has right authentication credentials,davidopp,1 Federation API server authentication should not accept cluster resources when the client has invalid authentication credentials,yujuhong,1 Federation API server authentication should not accept cluster resources when the client has no authentication credentials,nikhiljindal,1 Federation apiserver Admission control should not be able to create resources if namespace does not exist,alex-mohr,1 Federation apiserver Cluster objects should be created and deleted successfully,ghodss,1 Federation daemonsets DaemonSet objects should be created and deleted successfully,nikhiljindal,0 +Federation daemonsets DaemonSet objects should be deleted from underlying clusters when OrphanDependents is false,nikhiljindal,0 +Federation daemonsets DaemonSet objects should not be deleted from underlying clusters when OrphanDependents is nil,nikhiljindal,0 +Federation daemonsets DaemonSet objects should not be deleted from underlying clusters when OrphanDependents is true,nikhiljindal,0 Federation deployments Deployment objects should be created and deleted successfully,soltysh,1 +Federation deployments Federated Deployment should be deleted from underlying clusters when OrphanDependents is false,nikhiljindal,0 Federation deployments Federated Deployment should create and update matching deployments in underling clusters,soltysh,1 +Federation deployments Federated Deployment should not be deleted from underlying clusters when OrphanDependents is nil,nikhiljindal,0 +Federation deployments Federated Deployment should not be deleted from underlying clusters when OrphanDependents is true,nikhiljindal,0 Federation events Event objects should be created and deleted successfully,karlkfi,1 Federation namespace Namespace objects all resources in the namespace should be deleted when namespace is deleted,nikhiljindal,0 Federation namespace Namespace objects should be created and deleted successfully,xiang90,1 Federation namespace Namespace objects should be deleted from underlying clusters when OrphanDependents is false,nikhiljindal,0 +Federation namespace Namespace objects should not be deleted from underlying clusters when OrphanDependents is nil,nikhiljindal,0 Federation namespace Namespace objects should not be deleted from underlying clusters when OrphanDependents is true,nikhiljindal,0 +Federation replicasets Federated ReplicaSet should be deleted from underlying clusters when OrphanDependents is false,nikhiljindal,0 Federation replicasets Federated ReplicaSet should create and update matching replicasets in underling clusters,childsb,1 +Federation replicasets Federated ReplicaSet should not be deleted from underlying clusters when OrphanDependents is nil,nikhiljindal,0 +Federation replicasets Federated ReplicaSet should not be deleted from underlying clusters when OrphanDependents is true,nikhiljindal,0 Federation replicasets ReplicaSet objects should be created and deleted successfully,apelisse,1 Federation secrets Secret objects should be created and deleted successfully,pmorie,1 Federation secrets Secret objects should be deleted from underlying clusters when OrphanDependents is false,nikhiljindal,0 +Federation secrets Secret objects should not be deleted from underlying clusters when OrphanDependents is nil,nikhiljindal,0 Federation secrets Secret objects should not be deleted from underlying clusters when OrphanDependents is true,nikhiljindal,0 GCP Volumes GlusterFS should be mountable,rkouj,0 GCP Volumes NFSv4 should be mountable for NFSv4,rkouj,0 +GCP Volumes GlusterFS should be mountable,nikhiljindal,0 +GCP Volumes NFSv4 should be mountable for NFSv4,nikhiljindal,0 GKE local SSD should write and read from node local SSD,fabioy,0 GKE node pools should create a cluster with multiple node pools,fabioy,1 Garbage collector should delete pods created by rc when not orphaning,justinsb,1 @@ -172,6 +188,8 @@ Garbage collector should orphan pods created by rc if deleteOptions.OrphanDepend "Generated release_1_5 clientset should create v2alpha1 cronJobs, delete cronJobs, watch cronJobs",soltysh,1 HA-master pods survive addition/removal different zones,rkouj,0 HA-master pods survive addition/removal same zone,rkouj,0 +HA-master pods survive addition/removal different zones,nikhiljindal,0 +HA-master pods survive addition/removal same zone,nikhiljindal,0 Hazelcast should create and scale hazelcast,mikedanese,1 Horizontal pod autoscaling (scale resource: CPU) Deployment Should scale from 1 pod to 3 pods and from 3 to 5,jszczepkowski,0 Horizontal pod autoscaling (scale resource: CPU) Deployment Should scale from 5 pods to 3 pods and from 3 to 1,jszczepkowski,0