open-cluster-management.io/governance-policy-propagator@v0.13.0/test/e2e/case6_placement_propagation_test.go (about)

     1  // Copyright (c) 2021 Red Hat, Inc.
     2  // Copyright Contributors to the Open Cluster Management project
     3  
     4  package e2e
     5  
     6  import (
     7  	"context"
     8  
     9  	. "github.com/onsi/ginkgo/v2"
    10  	. "github.com/onsi/gomega"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  
    13  	policiesv1 "open-cluster-management.io/governance-policy-propagator/api/v1"
    14  	"open-cluster-management.io/governance-policy-propagator/controllers/common"
    15  	"open-cluster-management.io/governance-policy-propagator/test/utils"
    16  )
    17  
    18  var _ = Describe("Test policy propagation", func() {
    19  	const (
    20  		case6PolicyName string = "case6-test-policy"
    21  		case6PolicyYaml string = "../resources/case6_placement_propagation/case6-test-policy.yaml"
    22  	)
    23  
    24  	Describe("Create policy/pb/plc in ns:"+testNamespace+" and then update pb/plc", Ordered, func() {
    25  		BeforeAll(func() {
    26  			By("Creating " + case6PolicyYaml)
    27  			utils.Kubectl("apply",
    28  				"-f", case6PolicyYaml,
    29  				"-n", testNamespace, "--kubeconfig="+kubeconfigHub)
    30  			plc := utils.GetWithTimeout(
    31  				clientHubDynamic, gvrPolicy, case6PolicyName, testNamespace, true, defaultTimeoutSeconds,
    32  			)
    33  			Expect(plc).NotTo(BeNil())
    34  		})
    35  		It("should propagate to cluster ns managed1", func() {
    36  			By("Patching test-policy-plr with decision of cluster managed1")
    37  			plr := utils.GetWithTimeout(
    38  				clientHubDynamic,
    39  				gvrPlacementDecision,
    40  				case6PolicyName+"-plr-1",
    41  				testNamespace,
    42  				true,
    43  				defaultTimeoutSeconds,
    44  			)
    45  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "managed1")
    46  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
    47  				context.TODO(),
    48  				plr, metav1.UpdateOptions{},
    49  			)
    50  			Expect(err).ToNot(HaveOccurred())
    51  			plc := utils.GetWithTimeout(
    52  				clientHubDynamic, gvrPolicy, testNamespace+"."+case6PolicyName, "managed1", true, defaultTimeoutSeconds,
    53  			)
    54  			Expect(plc).ToNot(BeNil())
    55  			opt := metav1.ListOptions{
    56  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
    57  			}
    58  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 1, true, defaultTimeoutSeconds)
    59  		})
    60  		It("should propagate to cluster ns managed2", func() {
    61  			By("Patching test-policy-plr with decision of cluster managed2")
    62  			plr := utils.GetWithTimeout(
    63  				clientHubDynamic,
    64  				gvrPlacementDecision,
    65  				case6PolicyName+"-plr-1",
    66  				testNamespace,
    67  				true,
    68  				defaultTimeoutSeconds,
    69  			)
    70  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "managed2")
    71  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
    72  				context.TODO(), plr, metav1.UpdateOptions{},
    73  			)
    74  			Expect(err).ToNot(HaveOccurred())
    75  			plc := utils.GetWithTimeout(
    76  				clientHubDynamic, gvrPolicy, testNamespace+"."+case6PolicyName, "managed2", true, defaultTimeoutSeconds,
    77  			)
    78  			Expect(plc).ToNot(BeNil())
    79  			opt := metav1.ListOptions{
    80  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
    81  			}
    82  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 1, true, defaultTimeoutSeconds)
    83  		})
    84  		It("should propagate to cluster ns managed1 and managed2", func() {
    85  			By("Patching test-policy-plr with decision of both managed1 and managed2")
    86  			plr := utils.GetWithTimeout(
    87  				clientHubDynamic,
    88  				gvrPlacementDecision,
    89  				case6PolicyName+"-plr-1",
    90  				testNamespace,
    91  				true,
    92  				defaultTimeoutSeconds,
    93  			)
    94  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "managed1", "managed2")
    95  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
    96  				context.TODO(), plr, metav1.UpdateOptions{},
    97  			)
    98  			Expect(err).ToNot(HaveOccurred())
    99  			opt := metav1.ListOptions{
   100  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   101  			}
   102  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 2, true, defaultTimeoutSeconds)
   103  		})
   104  		It("should propagate to cluster ns managed1", func() {
   105  			By("Patching test-policy-plr with decision of cluster managed1")
   106  			plr := utils.GetWithTimeout(
   107  				clientHubDynamic,
   108  				gvrPlacementDecision,
   109  				case6PolicyName+"-plr-1",
   110  				testNamespace,
   111  				true,
   112  				defaultTimeoutSeconds,
   113  			)
   114  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "managed1")
   115  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
   116  				context.TODO(), plr, metav1.UpdateOptions{},
   117  			)
   118  			Expect(err).ToNot(HaveOccurred())
   119  			plc := utils.GetWithTimeout(
   120  				clientHubDynamic, gvrPolicy, testNamespace+"."+case6PolicyName, "managed1", true, defaultTimeoutSeconds,
   121  			)
   122  			Expect(plc).ToNot(BeNil())
   123  			plc = utils.GetWithTimeout(
   124  				clientHubDynamic,
   125  				gvrPolicy,
   126  				testNamespace+"."+case6PolicyName,
   127  				"managed2",
   128  				false,
   129  				defaultTimeoutSeconds,
   130  			)
   131  			Expect(plc).To(BeNil())
   132  			opt := metav1.ListOptions{
   133  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   134  			}
   135  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 1, true, defaultTimeoutSeconds)
   136  		})
   137  		It("should propagate to cluster ns managed1 and managed2", func() {
   138  			By("Patching test-policy-plr with decision of both managed1 and managed2")
   139  			plr := utils.GetWithTimeout(
   140  				clientHubDynamic,
   141  				gvrPlacementDecision,
   142  				case6PolicyName+"-plr-1",
   143  				testNamespace,
   144  				true,
   145  				defaultTimeoutSeconds,
   146  			)
   147  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "managed1", "managed2")
   148  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
   149  				context.TODO(), plr, metav1.UpdateOptions{},
   150  			)
   151  			Expect(err).ToNot(HaveOccurred())
   152  			opt := metav1.ListOptions{
   153  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   154  			}
   155  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 2, true, defaultTimeoutSeconds)
   156  		})
   157  		It("should remove policy from ns managed1 and managed2", func() {
   158  			By("Patching test-policy-pb with a non existing plr")
   159  			pb := utils.GetWithTimeout(
   160  				clientHubDynamic,
   161  				gvrPlacementBinding,
   162  				case6PolicyName+"-pb",
   163  				testNamespace,
   164  				true,
   165  				defaultTimeoutSeconds,
   166  			)
   167  			pb.Object["placementRef"] = &policiesv1.Subject{
   168  				APIGroup: "cluster.open-cluster-management.io",
   169  				Kind:     "Placement",
   170  				Name:     case6PolicyName + "-plr-nonexists",
   171  			}
   172  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   173  				context.TODO(), pb, metav1.UpdateOptions{},
   174  			)
   175  			Expect(err).ToNot(HaveOccurred())
   176  			opt := metav1.ListOptions{
   177  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   178  			}
   179  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, true, defaultTimeoutSeconds)
   180  		})
   181  		It("should propagate to cluster ns managed1 and managed2", func() {
   182  			By("Patching test-policy-pb with correct plr")
   183  			pb := utils.GetWithTimeout(
   184  				clientHubDynamic,
   185  				gvrPlacementBinding,
   186  				case6PolicyName+"-pb",
   187  				testNamespace,
   188  				true,
   189  				defaultTimeoutSeconds,
   190  			)
   191  			pb.Object["placementRef"] = &policiesv1.Subject{
   192  				APIGroup: "cluster.open-cluster-management.io",
   193  				Kind:     "Placement",
   194  				Name:     case6PolicyName + "-plr",
   195  			}
   196  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   197  				context.TODO(), pb, metav1.UpdateOptions{},
   198  			)
   199  			Expect(err).ToNot(HaveOccurred())
   200  			opt := metav1.ListOptions{
   201  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   202  			}
   203  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 2, true, defaultTimeoutSeconds)
   204  		})
   205  		It("should remove policy from ns managed1 and managed2", func() {
   206  			By("Patching test-policy-pb with a plc with wrong apigroup")
   207  			pb := utils.GetWithTimeout(
   208  				clientHubDynamic,
   209  				gvrPlacementBinding,
   210  				case6PolicyName+"-pb",
   211  				testNamespace,
   212  				true,
   213  				defaultTimeoutSeconds,
   214  			)
   215  			pb.Object["subjects"] = []policiesv1.Subject{
   216  				{
   217  					APIGroup: "policy1.open-cluster-management.io",
   218  					Kind:     "Policy",
   219  					Name:     case6PolicyName,
   220  				},
   221  			}
   222  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   223  				context.TODO(), pb, metav1.UpdateOptions{},
   224  			)
   225  			Expect(err).To(HaveOccurred())
   226  		})
   227  		It("should propagate to cluster ns managed1 and managed2", func() {
   228  			By("Patching test-policy-pb with correct plc")
   229  			pb := utils.GetWithTimeout(
   230  				clientHubDynamic,
   231  				gvrPlacementBinding,
   232  				case6PolicyName+"-pb",
   233  				testNamespace,
   234  				true,
   235  				defaultTimeoutSeconds,
   236  			)
   237  			pb.Object["subjects"] = []policiesv1.Subject{
   238  				{
   239  					APIGroup: "policy.open-cluster-management.io",
   240  					Kind:     "Policy",
   241  					Name:     case6PolicyName,
   242  				},
   243  			}
   244  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   245  				context.TODO(), pb, metav1.UpdateOptions{},
   246  			)
   247  			Expect(err).ToNot(HaveOccurred())
   248  			opt := metav1.ListOptions{
   249  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   250  			}
   251  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 2, true, defaultTimeoutSeconds)
   252  		})
   253  		It("should prevent user from creating subject with unsupported kind", func() {
   254  			By("Patching test-policy-pb with a plc with wrong kind")
   255  			pb := utils.GetWithTimeout(
   256  				clientHubDynamic,
   257  				gvrPlacementBinding,
   258  				case6PolicyName+"-pb",
   259  				testNamespace,
   260  				true,
   261  				defaultTimeoutSeconds,
   262  			)
   263  			pb.Object["subjects"] = []policiesv1.Subject{
   264  				{
   265  					APIGroup: "policy.open-cluster-management.io",
   266  					Kind:     "Policy1",
   267  					Name:     case6PolicyName,
   268  				},
   269  			}
   270  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   271  				context.TODO(), pb, metav1.UpdateOptions{},
   272  			)
   273  			Expect(err).To(HaveOccurred())
   274  		})
   275  		It("should propagate to cluster ns managed1 and managed2", func() {
   276  			By("Patching test-policy-pb with correct plc")
   277  			pb := utils.GetWithTimeout(
   278  				clientHubDynamic,
   279  				gvrPlacementBinding,
   280  				case6PolicyName+"-pb",
   281  				testNamespace,
   282  				true,
   283  				defaultTimeoutSeconds,
   284  			)
   285  			pb.Object["subjects"] = []policiesv1.Subject{
   286  				{
   287  					APIGroup: "policy.open-cluster-management.io",
   288  					Kind:     "Policy",
   289  					Name:     case6PolicyName,
   290  				},
   291  			}
   292  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   293  				context.TODO(), pb, metav1.UpdateOptions{},
   294  			)
   295  			Expect(err).ToNot(HaveOccurred())
   296  			opt := metav1.ListOptions{
   297  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   298  			}
   299  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 2, true, defaultTimeoutSeconds)
   300  		})
   301  		It("should remove policy from ns managed1 and managed2", func() {
   302  			By("Patching test-policy-pb with a plc with wrong name")
   303  			pb := utils.GetWithTimeout(
   304  				clientHubDynamic,
   305  				gvrPlacementBinding,
   306  				case6PolicyName+"-pb",
   307  				testNamespace,
   308  				true,
   309  				defaultTimeoutSeconds,
   310  			)
   311  			pb.Object["subjects"] = []policiesv1.Subject{
   312  				{
   313  					APIGroup: "policy.open-cluster-management.io",
   314  					Kind:     "Policy",
   315  					Name:     case6PolicyName + "1",
   316  				},
   317  			}
   318  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   319  				context.TODO(), pb, metav1.UpdateOptions{},
   320  			)
   321  			Expect(err).ToNot(HaveOccurred())
   322  			opt := metav1.ListOptions{
   323  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   324  			}
   325  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, true, defaultTimeoutSeconds)
   326  		})
   327  		It("should propagate to cluster ns managed1 and managed2", func() {
   328  			By("Patching test-policy-pb with correct plc")
   329  			pb := utils.GetWithTimeout(
   330  				clientHubDynamic,
   331  				gvrPlacementBinding,
   332  				case6PolicyName+"-pb",
   333  				testNamespace,
   334  				true,
   335  				defaultTimeoutSeconds,
   336  			)
   337  			pb.Object["subjects"] = []policiesv1.Subject{
   338  				{
   339  					APIGroup: "policy.open-cluster-management.io",
   340  					Kind:     "Policy",
   341  					Name:     case6PolicyName,
   342  				},
   343  			}
   344  			_, err := clientHubDynamic.Resource(gvrPlacementBinding).Namespace(testNamespace).Update(
   345  				context.TODO(), pb, metav1.UpdateOptions{},
   346  			)
   347  			Expect(err).ToNot(HaveOccurred())
   348  			opt := metav1.ListOptions{
   349  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   350  			}
   351  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 2, true, defaultTimeoutSeconds)
   352  		})
   353  		It("should remove policy from ns managed1 and managed2", func() {
   354  			By("Deleting decision for test-policy-plr")
   355  			utils.GetWithTimeout(
   356  				clientHubDynamic,
   357  				gvrPlacementDecision,
   358  				case6PolicyName+"-plr-1",
   359  				testNamespace,
   360  				true,
   361  				defaultTimeoutSeconds,
   362  			)
   363  			// remove the placementdecision will remove the policy from all managed clusters
   364  			utils.Kubectl("delete",
   365  				"placementdecision", case6PolicyName+"-plr-1",
   366  				"-n", testNamespace, "--kubeconfig="+kubeconfigHub)
   367  			opt := metav1.ListOptions{
   368  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   369  			}
   370  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, true, defaultTimeoutSeconds)
   371  		})
   372  		AfterAll(func() {
   373  			utils.Kubectl("delete",
   374  				"-f", case6PolicyYaml,
   375  				"-n", testNamespace,
   376  				"--kubeconfig="+kubeconfigHub)
   377  			opt := metav1.ListOptions{}
   378  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, false, 30)
   379  		})
   380  	})
   381  
   382  	Describe("Create policy/pb/plc in ns:"+testNamespace+" and then update policy", Ordered, func() {
   383  		BeforeAll(func() {
   384  			By("Creating " + case6PolicyYaml)
   385  			utils.Kubectl("apply",
   386  				"-f", case6PolicyYaml,
   387  				"-n", testNamespace,
   388  				"--kubeconfig="+kubeconfigHub)
   389  			plc := utils.GetWithTimeout(
   390  				clientHubDynamic, gvrPolicy, case6PolicyName, testNamespace, true, defaultTimeoutSeconds,
   391  			)
   392  			Expect(plc).NotTo(BeNil())
   393  		})
   394  		It("should propagate to cluster ns managed1", func() {
   395  			By("Patching test-policy-plr with decision of cluster managed1")
   396  			plr := utils.GetWithTimeout(
   397  				clientHubDynamic,
   398  				gvrPlacementDecision,
   399  				case6PolicyName+"-plr-1",
   400  				testNamespace,
   401  				true,
   402  				defaultTimeoutSeconds,
   403  			)
   404  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "managed1")
   405  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
   406  				context.TODO(), plr, metav1.UpdateOptions{},
   407  			)
   408  			Expect(err).ToNot(HaveOccurred())
   409  			plc := utils.GetWithTimeout(
   410  				clientHubDynamic, gvrPolicy, testNamespace+"."+case6PolicyName, "managed1", true, defaultTimeoutSeconds,
   411  			)
   412  			Expect(plc).ToNot(BeNil())
   413  			opt := metav1.ListOptions{
   414  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   415  			}
   416  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 1, true, defaultTimeoutSeconds)
   417  		})
   418  		It("should update replicated policy in ns managed1", func() {
   419  			By("Patching test-policy with spec.remediationAction = enforce")
   420  			rootPlc := utils.GetWithTimeout(
   421  				clientHubDynamic, gvrPolicy, case6PolicyName, testNamespace, true, defaultTimeoutSeconds,
   422  			)
   423  			Expect(rootPlc).NotTo(BeNil())
   424  			Expect(rootPlc.Object["spec"].(map[string]interface{})["remediationAction"]).To(Equal("inform"))
   425  			rootPlc.Object["spec"].(map[string]interface{})["remediationAction"] = "enforce"
   426  			rootPlc, err := clientHubDynamic.Resource(gvrPolicy).Namespace(testNamespace).Update(
   427  				context.TODO(), rootPlc, metav1.UpdateOptions{},
   428  			)
   429  			Expect(err).ToNot(HaveOccurred())
   430  			Eventually(func(g Gomega) interface{} {
   431  				replicatedPlc := utils.GetWithTimeout(
   432  					clientHubDynamic,
   433  					gvrPolicy,
   434  					testNamespace+"."+case6PolicyName,
   435  					"managed1",
   436  					true,
   437  					defaultTimeoutSeconds,
   438  				)
   439  
   440  				err := utils.RemovePolicyTemplateDBAnnotations(replicatedPlc)
   441  				g.Expect(err).ToNot(HaveOccurred())
   442  
   443  				return replicatedPlc.Object["spec"]
   444  			}, defaultTimeoutSeconds, 1).Should(utils.SemanticEqual(rootPlc.Object["spec"]))
   445  		})
   446  		It("should remove replicated policy in ns managed1", func() {
   447  			By("Patching test-policy with spec.disabled = true")
   448  			rootPlc := utils.GetWithTimeout(
   449  				clientHubDynamic, gvrPolicy, case6PolicyName, testNamespace, true, defaultTimeoutSeconds,
   450  			)
   451  			Expect(rootPlc).NotTo(BeNil())
   452  			Expect(rootPlc.Object["spec"].(map[string]interface{})["disabled"]).To(BeFalse())
   453  			rootPlc.Object["spec"].(map[string]interface{})["disabled"] = true
   454  			rootPlc, err := clientHubDynamic.Resource(gvrPolicy).Namespace(testNamespace).Update(
   455  				context.TODO(), rootPlc, metav1.UpdateOptions{},
   456  			)
   457  			Expect(err).ToNot(HaveOccurred())
   458  			Expect(rootPlc.Object["spec"].(map[string]interface{})["disabled"]).To(BeTrue())
   459  			opt := metav1.ListOptions{
   460  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   461  			}
   462  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, true, defaultTimeoutSeconds)
   463  		})
   464  		It("should be created in user ns", func() {
   465  			By("Creating " + case6PolicyYaml)
   466  			utils.Kubectl("apply",
   467  				"-f", case6PolicyYaml,
   468  				"-n", testNamespace,
   469  				"--kubeconfig="+kubeconfigHub)
   470  			plc := utils.GetWithTimeout(
   471  				clientHubDynamic, gvrPolicy, case6PolicyName, testNamespace, true, defaultTimeoutSeconds,
   472  			)
   473  			Expect(plc).NotTo(BeNil())
   474  		})
   475  		It("should propagate to cluster ns managed1", func() {
   476  			By("Patching test-policy-plr with decision of cluster managed1")
   477  			plr := utils.GetWithTimeout(
   478  				clientHubDynamic,
   479  				gvrPlacementDecision,
   480  				case6PolicyName+"-plr-1",
   481  				testNamespace,
   482  				true,
   483  				defaultTimeoutSeconds,
   484  			)
   485  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "managed1")
   486  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
   487  				context.TODO(), plr, metav1.UpdateOptions{},
   488  			)
   489  			Expect(err).ToNot(HaveOccurred())
   490  			plc := utils.GetWithTimeout(
   491  				clientHubDynamic,
   492  				gvrPolicy,
   493  				testNamespace+"."+case6PolicyName,
   494  				"managed1",
   495  				true,
   496  				defaultTimeoutSeconds,
   497  			)
   498  			Expect(plc).ToNot(BeNil())
   499  			opt := metav1.ListOptions{
   500  				LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + case6PolicyName,
   501  			}
   502  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 1, true, defaultTimeoutSeconds)
   503  		})
   504  		It("should update test-policy to a different policy template", func() {
   505  			By("Creating ../resources/case6_placement_propagation/case6-test-policy2.yaml")
   506  			utils.Kubectl("apply",
   507  				"-f", "../resources/case6_placement_propagation/case6-test-policy2.yaml",
   508  				"-n", testNamespace, "--kubeconfig="+kubeconfigHub)
   509  			rootPlc := utils.GetWithTimeout(
   510  				clientHubDynamic, gvrPolicy, case6PolicyName, testNamespace, true, defaultTimeoutSeconds,
   511  			)
   512  			Expect(rootPlc).NotTo(BeNil())
   513  			yamlPlc := utils.ParseYaml("../resources/case6_placement_propagation/case6-test-policy2.yaml")
   514  			Eventually(func(g Gomega) interface{} {
   515  				replicatedPlc := utils.GetWithTimeout(
   516  					clientHubDynamic,
   517  					gvrPolicy,
   518  					testNamespace+"."+case6PolicyName,
   519  					"managed1",
   520  					true,
   521  					defaultTimeoutSeconds,
   522  				)
   523  
   524  				err := utils.RemovePolicyTemplateDBAnnotations(replicatedPlc)
   525  				g.Expect(err).ToNot(HaveOccurred())
   526  
   527  				return replicatedPlc.Object["spec"]
   528  			}, defaultTimeoutSeconds, 1).Should(utils.SemanticEqual(yamlPlc.Object["spec"]))
   529  		})
   530  		AfterAll(func() {
   531  			utils.Kubectl("delete",
   532  				"-f", "../resources/case6_placement_propagation/case6-test-policy2.yaml",
   533  				"-n", testNamespace, "--kubeconfig="+kubeconfigHub)
   534  			opt := metav1.ListOptions{}
   535  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, false, 10)
   536  		})
   537  	})
   538  
   539  	Describe("Handling propagation to terminating clusters", Ordered, func() {
   540  		BeforeAll(func() {
   541  			By("Creating " + case6PolicyYaml)
   542  			utils.Kubectl("apply",
   543  				"-f", case6PolicyYaml,
   544  				"-n", testNamespace,
   545  				"--kubeconfig="+kubeconfigHub)
   546  			plc := utils.GetWithTimeout(
   547  				clientHubDynamic, gvrPolicy, case6PolicyName, testNamespace, true, defaultTimeoutSeconds,
   548  			)
   549  			Expect(plc).NotTo(BeNil())
   550  		})
   551  		It("sets up the terminating cluster", func() {
   552  			By("Creating the namespace and cluster")
   553  			// Note: the namespace is initially created with a finalizer
   554  			_, err := utils.KubectlWithOutput("apply", "-f",
   555  				"../resources/case6_placement_propagation/extra-cluster.yaml", "--kubeconfig="+kubeconfigHub)
   556  			Expect(err).ToNot(HaveOccurred())
   557  
   558  			By("Deleting the namespace")
   559  			out, err := utils.KubectlWithOutput("delete", "namespace", "test6-extra",
   560  				"--timeout=2s", "--kubeconfig="+kubeconfigHub)
   561  			Expect(err).To(HaveOccurred())
   562  			Expect(out).To(MatchRegexp("waiting for the condition"))
   563  		})
   564  		It("should fail to propagate to the terminating cluster", func() {
   565  			By("Patching test-policy-plr with decision of cluster test6-extra")
   566  			plr := utils.GetWithTimeout(
   567  				clientHubDynamic,
   568  				gvrPlacementDecision,
   569  				case6PolicyName+"-plr-1",
   570  				testNamespace,
   571  				true,
   572  				defaultTimeoutSeconds,
   573  			)
   574  			plr.Object["status"] = utils.GeneratePldStatus(plr.GetName(), plr.GetNamespace(), "test6-extra")
   575  			_, err := clientHubDynamic.Resource(gvrPlacementDecision).Namespace(testNamespace).UpdateStatus(
   576  				context.TODO(), plr, metav1.UpdateOptions{},
   577  			)
   578  			Expect(err).ToNot(HaveOccurred())
   579  
   580  			By("Verifying that the replicated policy is not created")
   581  			Consistently(func() interface{} {
   582  				return utils.GetWithTimeout(clientHubDynamic, gvrPolicy, testNamespace+"."+case6PolicyName,
   583  					"test6-extra", false, defaultTimeoutSeconds)
   584  			}, defaultTimeoutSeconds, 1).Should(BeNil())
   585  		})
   586  		It("should succeed when the cluster namespace is re-created", func() {
   587  			By("Removing the finalizer from the namespace")
   588  			utils.Kubectl("patch", "namespace", "test6-extra", "--type=json",
   589  				`-p=[{"op":"remove","path":"/metadata/finalizers"}]`, "--kubeconfig="+kubeconfigHub)
   590  
   591  			By("Verifying that the namespace is removed")
   592  			ns := utils.GetClusterLevelWithTimeout(clientHubDynamic, gvrNamespace, "test6-extra", false,
   593  				defaultTimeoutSeconds)
   594  			Expect(ns).To(BeNil())
   595  
   596  			By("Recreating the namespace")
   597  			utils.Kubectl("create", "namespace", "test6-extra", "--kubeconfig="+kubeconfigHub)
   598  
   599  			By("Verifying that the policy is now replicated")
   600  			pol := utils.GetWithTimeout(clientHubDynamic, gvrPolicy, testNamespace+"."+case6PolicyName,
   601  				"test6-extra", true, defaultTimeoutSeconds)
   602  			Expect(pol).NotTo(BeNil())
   603  		})
   604  		AfterAll(func() {
   605  			utils.Kubectl("delete",
   606  				"-f", case6PolicyYaml,
   607  				"-n", testNamespace,
   608  				"--kubeconfig="+kubeconfigHub)
   609  			opt := metav1.ListOptions{}
   610  			utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, false, 10)
   611  
   612  			utils.Kubectl("patch", "namespace", "test6-extra", "--type=json",
   613  				`-p=[{"op":"remove","path":"/metadata/finalizers"}]`, "--kubeconfig="+kubeconfigHub)
   614  			utils.Kubectl("delete", "namespace", "test6-extra", "--timeout=2s", "--kubeconfig="+kubeconfigHub)
   615  			utils.Kubectl("delete", "managedcluster", "test6-extra", "--kubeconfig="+kubeconfigHub)
   616  		})
   617  	})
   618  })