github.com/rancher/elemental/tests@v0.0.0-20240517125144-ae048c615b3f/e2e/uninstall-operator_test.go (about)

     1  /*
     2  Copyright © 2024 SUSE LLC
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7      http://www.apache.org/licenses/LICENSE-2.0
     8  Unless required by applicable law or agreed to in writing, software
     9  distributed under the License is distributed on an "AS IS" BASIS,
    10  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  See the License for the specific language governing permissions and
    12  limitations under the License.
    13  */
    14  
    15  package e2e_test
    16  
    17  import (
    18  	"strings"
    19  	"sync"
    20  	"time"
    21  
    22  	. "github.com/onsi/ginkgo/v2"
    23  	. "github.com/onsi/gomega"
    24  	"github.com/rancher-sandbox/ele-testhelpers/kubectl"
    25  	"github.com/rancher-sandbox/ele-testhelpers/rancher"
    26  	"github.com/rancher-sandbox/ele-testhelpers/tools"
    27  	"github.com/rancher/elemental/tests/e2e/helpers/elemental"
    28  )
    29  
    30  func deleteFinalizers(ns, object, value string) {
    31  	_, err := kubectl.RunWithoutErr("patch", object,
    32  		"--namespace", ns, value, "--type", "merge",
    33  		"--patch", "{\"metadata\":{\"finalizers\":null}}")
    34  	Expect(err).To(Not(HaveOccurred()))
    35  
    36  }
    37  
    38  func testClusterAvailability(ns, cluster string) {
    39  	Eventually(func() string {
    40  		out, _ := kubectl.RunWithoutErr("get", "cluster.v1.provisioning.cattle.io",
    41  			"--namespace", ns, cluster,
    42  			"-o", "jsonpath={.metadata.name}")
    43  		return out
    44  	}, tools.SetTimeout(3*time.Minute), 5*time.Second).Should(Equal(clusterName))
    45  }
    46  
    47  var _ = Describe("E2E - Uninstall Elemental Operator", Label("uninstall-operator"), func() {
    48  	// Create kubectl context
    49  	// Default timeout is too small, so New() cannot be used
    50  	k := &kubectl.Kubectl{
    51  		Namespace:    "",
    52  		PollTimeout:  tools.SetTimeout(300 * time.Second),
    53  		PollInterval: 500 * time.Millisecond,
    54  	}
    55  
    56  	It("Uninstall Elemental Operator", func() {
    57  		// Report to Qase
    58  		testCaseID = 70
    59  
    60  		By("Testing cluster resource availability BEFORE operator uninstallation", func() {
    61  			testClusterAvailability(clusterNS, clusterName)
    62  		})
    63  
    64  		By("Uninstalling Operator via Helm", func() {
    65  			for _, chart := range []string{"elemental-operator", "elemental-operator-crds"} {
    66  				RunHelmCmdWithRetry(
    67  					"uninstall", chart,
    68  					"--namespace", "cattle-elemental-system",
    69  				)
    70  			}
    71  		})
    72  
    73  		By("Testing cluster resource availability AFTER operator uninstallation", func() {
    74  			testClusterAvailability(clusterNS, clusterName)
    75  		})
    76  
    77  		By("Checking that Elemental resources are gone", func() {
    78  			Eventually(func() string {
    79  				out, _ := kubectl.Run("get", "MachineInventorySelectorTemplate",
    80  					"--namespace", clusterNS,
    81  					"-o", "jsonpath={.items[*].metadata.name}")
    82  				return out
    83  			}, tools.SetTimeout(3*time.Minute), 5*time.Second).Should(ContainSubstring("NotFound"))
    84  		})
    85  
    86  		// NOTE: the operator cannot be reinstall now because there are still CRDs pending to be removed
    87  		By("Checking that Elemental operator CRDs cannot be reinstalled", func() {
    88  			chart := "elemental-operator-crds"
    89  			out, err := kubectl.RunHelmBinaryWithOutput("upgrade", "--install", chart,
    90  				operatorRepo+"/"+chart+"-chart",
    91  				"--namespace", "cattle-elemental-system",
    92  				"--create-namespace",
    93  				"--wait", "--wait-for-jobs",
    94  			)
    95  			Expect(err).To(HaveOccurred(), out)
    96  			Expect(out).To(ContainSubstring("CRDs from previous installations are pending to be removed"))
    97  		})
    98  
    99  		// NOTE: we have to run this in background to be able to apply the workaround!
   100  		var wg sync.WaitGroup
   101  		wg.Add(1)
   102  		go func(ns, name string) {
   103  			defer wg.Done()
   104  			defer GinkgoRecover()
   105  
   106  			By("Deleting cluster resource", func() {
   107  				Eventually(func() error {
   108  					_, err := kubectl.RunWithoutErr("delete", "cluster",
   109  						"--namespace", ns, name)
   110  					return err
   111  				}, tools.SetTimeout(2*time.Minute), 10*time.Second).Should(Not(HaveOccurred()))
   112  			})
   113  		}(clusterNS, clusterName)
   114  
   115  		// Removing finalizers from MachineInventory and Machine
   116  		By("Removing finalizers from MachineInventory/Machine", func() {
   117  			// NOTE: wait a bit for the cluster deletion to be started (it's running in background)
   118  			time.Sleep(1 * time.Minute)
   119  
   120  			machineList, err := kubectl.RunWithoutErr("get", "MachineInventory",
   121  				"--namespace", clusterNS, "-o", "jsonpath={.items[*].metadata.name}")
   122  			Expect(err).To(Not(HaveOccurred()))
   123  
   124  			for _, machine := range strings.Fields(machineList) {
   125  				internalMachine, err := elemental.GetInternalMachine(clusterNS, machine)
   126  				Expect(err).To(Not(HaveOccurred()))
   127  
   128  				// Delete blocking Finalizers
   129  				GinkgoWriter.Printf("Deleting Finalizers for MachineInventory '%s'...\n", machine)
   130  				deleteFinalizers(clusterNS, "MachineInventory", machine)
   131  
   132  				// Only if Machine is still present
   133  				if internalMachine != "" {
   134  					GinkgoWriter.Printf("Deleting Finalizers for Machine '%s'...\n", internalMachine)
   135  					deleteFinalizers(clusterNS, "Machine", internalMachine)
   136  				}
   137  			}
   138  		})
   139  
   140  		// Wait for cluster deletion to be completed
   141  		wg.Wait()
   142  
   143  		By("Testing cluster resource unavailability", func() {
   144  			out, err := kubectl.Run("get", "cluster.v1.provisioning.cattle.io",
   145  				"--namespace", clusterNS, clusterName,
   146  				"-o", "jsonpath={.metadata.name}")
   147  			Expect(err).To(HaveOccurred(), out)
   148  			Expect(out).To(ContainSubstring("NotFound"))
   149  		})
   150  	})
   151  
   152  	It("Re-install Elemental Operator", func() {
   153  		// Report to Qase
   154  		testCaseID = 62
   155  
   156  		By("Installing Operator via Helm", func() {
   157  			for _, chart := range []string{"elemental-operator-crds", "elemental-operator"} {
   158  				RunHelmCmdWithRetry("upgrade", "--install", chart,
   159  					operatorRepo+"/"+chart+"-chart",
   160  					"--namespace", "cattle-elemental-system",
   161  					"--create-namespace",
   162  					"--wait", "--wait-for-jobs",
   163  				)
   164  			}
   165  
   166  			// Wait for pod to be started
   167  			Eventually(func() error {
   168  				return rancher.CheckPod(k, [][]string{{"cattle-elemental-system", "app=elemental-operator"}})
   169  			}, tools.SetTimeout(4*time.Minute), 30*time.Second).Should(BeNil())
   170  		})
   171  
   172  		By("Creating a dumb MachineRegistration", func() {
   173  			err := kubectl.Apply(clusterNS, dumbRegistrationYaml)
   174  			Expect(err).To(Not(HaveOccurred()))
   175  		})
   176  
   177  		By("Creating cluster", func() {
   178  			// NOTE: we can re-use clusterYaml as it has already been configured correctly
   179  			err := kubectl.Apply(clusterNS, clusterYaml)
   180  			Expect(err).To(Not(HaveOccurred()))
   181  		})
   182  
   183  		By("Testing cluster resource availability", func() {
   184  			testClusterAvailability(clusterNS, clusterName)
   185  		})
   186  	})
   187  })