github.com/rancher/elemental/tests@v0.0.0-20240517125144-ae048c615b3f/e2e/install_test.go (about) 1 /* 2 Copyright © 2022 - 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 "os" 19 "os/exec" 20 "strings" 21 "time" 22 23 . "github.com/onsi/ginkgo/v2" 24 . "github.com/onsi/gomega" 25 "github.com/rancher-sandbox/ele-testhelpers/kubectl" 26 "github.com/rancher-sandbox/ele-testhelpers/rancher" 27 "github.com/rancher-sandbox/ele-testhelpers/tools" 28 ) 29 30 func rolloutDeployment(ns, d string) { 31 // NOTE: 1st or 2nd rollout command can sporadically fail, so better to use Eventually here 32 Eventually(func() string { 33 status, _ := kubectl.RunWithoutErr("rollout", "restart", "deployment/"+d, 34 "--namespace", ns) 35 return status 36 }, tools.SetTimeout(1*time.Minute), 20*time.Second).Should(ContainSubstring("restarted")) 37 38 // Wait for deployment to be restarted 39 Eventually(func() string { 40 status, _ := kubectl.RunWithoutErr("rollout", "status", "deployment/"+d, 41 "--namespace", ns) 42 return status 43 }, tools.SetTimeout(2*time.Minute), 30*time.Second).Should(ContainSubstring("successfully rolled out")) 44 } 45 46 var _ = Describe("E2E - Install Rancher Manager", Label("install"), func() { 47 // Create kubectl context 48 // Default timeout is too small, so New() cannot be used 49 k := &kubectl.Kubectl{ 50 Namespace: "", 51 PollTimeout: tools.SetTimeout(300 * time.Second), 52 PollInterval: 500 * time.Millisecond, 53 } 54 55 // Define local Kubeconfig file 56 localKubeconfig := os.Getenv("HOME") + "/.kube/config" 57 58 It("Install upstream K8s cluster", func() { 59 if strings.Contains(k8sUpstreamVersion, "rke2") { 60 // Report to Qase 61 testCaseID = 60 62 63 By("Installing RKE2", func() { 64 // Get RKE2 installation script 65 fileName := "rke2-install.sh" 66 Eventually(func() error { 67 return tools.GetFileFromURL("https://get.rke2.io", fileName, true) 68 }, tools.SetTimeout(2*time.Minute), 10*time.Second).ShouldNot(HaveOccurred()) 69 70 // Retry in case of (sporadic) failure... 71 count := 1 72 Eventually(func() error { 73 // Execute RKE2 installation 74 out, err := exec.Command("sudo", "--preserve-env=INSTALL_RKE2_VERSION", "sh", fileName).CombinedOutput() 75 GinkgoWriter.Printf("RKE2 installation loop %d:\n%s\n", count, out) 76 count++ 77 return err 78 }, tools.SetTimeout(2*time.Minute), 5*time.Second).Should(BeNil()) 79 }) 80 81 if clusterType == "hardened" { 82 By("Configuring hardened cluster", func() { 83 err := exec.Command("sudo", installHardenedScript).Run() 84 Expect(err).To(Not(HaveOccurred())) 85 }) 86 } 87 88 By("Starting RKE2", func() { 89 // Copy config file, this allows custom configuration for RKE2 installation 90 // NOTE: CopyFile cannot be used, as we need root permissions for this file 91 err := exec.Command("sudo", "mkdir", "-p", "/etc/rancher/rke2").Run() 92 Expect(err).To(Not(HaveOccurred())) 93 err = exec.Command("sudo", "cp", configRKE2Yaml, "/etc/rancher/rke2/config.yaml").Run() 94 Expect(err).To(Not(HaveOccurred())) 95 96 // Activate and start RKE2 97 err = exec.Command("sudo", "systemctl", "enable", "--now", "rke2-server.service").Run() 98 Expect(err).To(Not(HaveOccurred())) 99 100 // Delay few seconds before checking 101 time.Sleep(tools.SetTimeout(20 * time.Second)) 102 103 err = exec.Command("sudo", "ln", "-s", "/var/lib/rancher/rke2/bin/kubectl", "/usr/local/bin/kubectl").Run() 104 Expect(err).To(Not(HaveOccurred())) 105 }) 106 107 By("Waiting for RKE2 to be started", func() { 108 // Wait for all pods to be started 109 err := os.Setenv("KUBECONFIG", "/etc/rancher/rke2/rke2.yaml") 110 Expect(err).To(Not(HaveOccurred())) 111 112 checkList := [][]string{ 113 {"kube-system", "k8s-app=kube-dns"}, 114 {"kube-system", "app.kubernetes.io/name=rke2-ingress-nginx"}, 115 } 116 Eventually(func() error { 117 return rancher.CheckPod(k, checkList) 118 }, tools.SetTimeout(4*time.Minute), 30*time.Second).Should(BeNil()) 119 120 err = k.WaitLabelFilter("kube-system", "Ready", "rke2-ingress-nginx-controller", "app.kubernetes.io/name=rke2-ingress-nginx") 121 Expect(err).To(Not(HaveOccurred())) 122 }) 123 } else { 124 // Report to Qase 125 testCaseID = 59 126 127 By("Installing K3s", func() { 128 // Get K3s installation script 129 fileName := "k3s-install.sh" 130 Eventually(func() error { 131 return tools.GetFileFromURL("https://get.k3s.io", fileName, true) 132 }, tools.SetTimeout(2*time.Minute), 10*time.Second).ShouldNot(HaveOccurred()) 133 134 // Set command and arguments 135 installCmd := exec.Command("sh", fileName) 136 installCmd.Env = append(os.Environ(), "INSTALL_K3S_EXEC=--disable metrics-server") 137 138 // Retry in case of (sporadic) failure... 139 count := 1 140 Eventually(func() error { 141 // Execute K3s installation 142 out, err := installCmd.CombinedOutput() 143 GinkgoWriter.Printf("K3s installation loop %d:\n%s\n", count, out) 144 count++ 145 return err 146 }, tools.SetTimeout(2*time.Minute), 5*time.Second).Should(BeNil()) 147 }) 148 149 if clusterType == "hardened" { 150 By("Configuring hardened cluster", func() { 151 err := exec.Command("sudo", installHardenedScript).Run() 152 Expect(err).To(Not(HaveOccurred())) 153 }) 154 } 155 156 By("Starting K3s", func() { 157 err := exec.Command("sudo", "systemctl", "start", "k3s").Run() 158 Expect(err).To(Not(HaveOccurred())) 159 160 // Delay few seconds before checking 161 time.Sleep(tools.SetTimeout(20 * time.Second)) 162 }) 163 164 By("Waiting for K3s to be started", func() { 165 // Wait for all pods to be started 166 checkList := [][]string{ 167 {"kube-system", "app=local-path-provisioner"}, 168 {"kube-system", "k8s-app=kube-dns"}, 169 {"kube-system", "app.kubernetes.io/name=traefik"}, 170 {"kube-system", "svccontroller.k3s.cattle.io/svcname=traefik"}, 171 } 172 Eventually(func() error { 173 return rancher.CheckPod(k, checkList) 174 }, tools.SetTimeout(4*time.Minute), 30*time.Second).Should(BeNil()) 175 }) 176 } 177 178 By("Configuring Kubeconfig file", func() { 179 // Copy K3s file in ~/.kube/config 180 // NOTE: don't check for error, as it will happen anyway (only K3s or RKE2 is installed at a time) 181 file, _ := exec.Command("bash", "-c", "ls /etc/rancher/{k3s,rke2}/{k3s,rke2}.yaml").Output() 182 Expect(file).To(Not(BeEmpty())) 183 err := tools.CopyFile(strings.Trim(string(file), "\n"), localKubeconfig) 184 Expect(err).To(Not(HaveOccurred())) 185 186 err = os.Setenv("KUBECONFIG", localKubeconfig) 187 Expect(err).To(Not(HaveOccurred())) 188 }) 189 190 if caType == "private" { 191 By("Configuring Private CA", func() { 192 out, err := exec.Command(configPrivateCAScript).CombinedOutput() 193 GinkgoWriter.Printf("%s\n", out) 194 Expect(err).To(Not(HaveOccurred())) 195 }) 196 } else { 197 By("Installing CertManager", func() { 198 RunHelmCmdWithRetry("repo", "add", "jetstack", "https://charts.jetstack.io") 199 RunHelmCmdWithRetry("repo", "update") 200 201 // Set flags for cert-manager installation 202 flags := []string{ 203 "upgrade", "--install", "cert-manager", "jetstack/cert-manager", 204 "--namespace", "cert-manager", 205 "--create-namespace", 206 "--set", "installCRDs=true", 207 "--wait", "--wait-for-jobs", 208 } 209 210 if clusterType == "hardened" { 211 flags = append(flags, "--version", certManagerVersion) 212 } 213 214 RunHelmCmdWithRetry(flags...) 215 216 checkList := [][]string{ 217 {"cert-manager", "app.kubernetes.io/component=controller"}, 218 {"cert-manager", "app.kubernetes.io/component=webhook"}, 219 {"cert-manager", "app.kubernetes.io/component=cainjector"}, 220 } 221 Eventually(func() error { 222 return rancher.CheckPod(k, checkList) 223 }, tools.SetTimeout(4*time.Minute), 30*time.Second).Should(BeNil()) 224 }) 225 } 226 }) 227 228 It("Install Rancher Manager", func() { 229 // Report to Qase 230 testCaseID = 61 231 232 // Inject secret for Private CA 233 if caType == "private" { 234 // The namespace must exist before adding secret 235 err := exec.Command("kubectl", "create", "namespace", "cattle-system").Run() 236 Expect(err).To(Not(HaveOccurred())) 237 238 _, err = kubectl.RunWithoutErr("create", "secret", 239 "--namespace", "cattle-system", 240 "tls", "tls-rancher-ingress", 241 "--cert=tls.crt", 242 "--key=tls.key", 243 ) 244 Expect(err).To(Not(HaveOccurred())) 245 246 _, err = kubectl.RunWithoutErr("create", "secret", 247 "--namespace", "cattle-system", 248 "generic", "tls-ca", 249 "--from-file=cacerts.pem=./cacerts.pem", 250 ) 251 Expect(err).To(Not(HaveOccurred())) 252 } 253 254 err := rancher.DeployRancherManager(rancherHostname, rancherChannel, rancherVersion, rancherHeadVersion, caType, proxy) 255 Expect(err).To(Not(HaveOccurred())) 256 257 // Wait for all pods to be started 258 checkList := [][]string{ 259 {"cattle-system", "app=rancher"}, 260 {"cattle-system", "app=rancher-webhook"}, 261 {"cattle-fleet-local-system", "app=fleet-agent"}, 262 {"cattle-provisioning-capi-system", "control-plane=controller-manager"}, 263 } 264 Eventually(func() error { 265 return rancher.CheckPod(k, checkList) 266 }, tools.SetTimeout(10*time.Minute), 30*time.Second).Should(BeNil()) 267 268 // Check issuer for Private CA 269 if caType == "private" { 270 Eventually(func() error { 271 out, err := exec.Command("curl", "-vk", "https://"+rancherHostname).CombinedOutput() 272 if err != nil { 273 // Show only if there's no error 274 GinkgoWriter.Printf("%s\n", out) 275 } 276 return err 277 }, tools.SetTimeout(2*time.Minute), 5*time.Second).Should(Not(HaveOccurred())) 278 } 279 280 By("Configuring kubectl to use Rancher admin user", func() { 281 // Getting internal username for admin 282 internalUsername, err := kubectl.RunWithoutErr("get", "user", 283 "-o", "jsonpath={.items[?(@.username==\"admin\")].metadata.name}", 284 ) 285 Expect(err).To(Not(HaveOccurred())) 286 Expect(internalUsername).To(Not(BeEmpty())) 287 288 // Add token in Rancher Manager 289 err = tools.Sed("%ADMIN_USER%", internalUsername, ciTokenYaml) 290 Expect(err).To(Not(HaveOccurred())) 291 err = kubectl.Apply("default", ciTokenYaml) 292 Expect(err).To(Not(HaveOccurred())) 293 294 // Getting Rancher Manager local cluster CA 295 // NOTE: loop until the cmd return something, it could take some time 296 var rancherCA string 297 Eventually(func() error { 298 rancherCA, err = kubectl.RunWithoutErr("get", "secret", 299 "--namespace", "cattle-system", 300 "tls-rancher-ingress", 301 "-o", "jsonpath={.data.tls\\.crt}", 302 ) 303 return err 304 }, tools.SetTimeout(2*time.Minute), 5*time.Second).Should(Not(HaveOccurred())) 305 306 // Copy skel file for ~/.kube/config 307 err = tools.CopyFile(localKubeconfigYaml, localKubeconfig) 308 Expect(err).To(Not(HaveOccurred())) 309 310 // Create kubeconfig for local cluster 311 err = tools.Sed("%RANCHER_URL%", rancherHostname, localKubeconfig) 312 Expect(err).To(Not(HaveOccurred())) 313 err = tools.Sed("%RANCHER_CA%", rancherCA, localKubeconfig) 314 Expect(err).To(Not(HaveOccurred())) 315 316 // Set correct file permissions 317 _ = exec.Command("chmod", "0600", localKubeconfig).Run() 318 319 // Remove the "old" kubeconfig file to force the use of the new one 320 // NOTE: in fact move it, just to keep it in case of issue 321 // Also don't check the returned error, as it will always not equal 0 322 _ = exec.Command("bash", "-c", "sudo mv -f /etc/rancher/{k3s,rke2}/{k3s,rke2}.yaml ~/").Run() 323 }) 324 325 if testType == "ui" { 326 By("Workaround for upgrade test, restart Fleet controller and agent", func() { 327 for _, d := range [][]string{ 328 {"cattle-fleet-local-system", "fleet-agent"}, 329 {"cattle-fleet-system", "fleet-controller"}, 330 } { 331 rolloutDeployment(d[0], d[1]) 332 } 333 }) 334 } 335 }) 336 337 // Deploy operator in CLI test 338 It("Install Elemental Operator if needed", func() { 339 if testType == "cli" || testType == "multi" { 340 By("Installing Operator for CLI tests", func() { 341 // Report to Qase 342 testCaseID = 62 343 344 for _, chart := range []string{"elemental-operator-crds", "elemental-operator"} { 345 RunHelmCmdWithRetry("upgrade", "--install", chart, 346 operatorRepo+"/"+chart+"-chart", 347 "--namespace", "cattle-elemental-system", 348 "--create-namespace", 349 "--wait", "--wait-for-jobs", 350 ) 351 352 // Delay few seconds for all to be installed 353 time.Sleep(tools.SetTimeout(20 * time.Second)) 354 } 355 356 // Wait for pod to be started 357 Eventually(func() error { 358 return rancher.CheckPod(k, [][]string{{"cattle-elemental-system", "app=elemental-operator"}}) 359 }, tools.SetTimeout(4*time.Minute), 30*time.Second).Should(BeNil()) 360 }) 361 } 362 }) 363 })