github.com/rancher/elemental/tests@v0.0.0-20240517125144-ae048c615b3f/e2e/airgap_test.go (about) 1 /* 2 Copyright © 2022 - 2023 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 "regexp" 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 var _ = Describe("E2E - Build the airgap archive", Label("prepare-archive"), func() { 31 It("Execute the script to build the archive", func() { 32 // Force to latest if nothing is defined 33 if certManagerVersion == "" { 34 certManagerVersion = "latest" 35 } 36 37 // Could be useful for manual debugging! 38 GinkgoWriter.Printf("Executed command: %s %s %s %s %s %s\n", airgapBuildScript, k8sUpstreamVersion, certManagerVersion, rancherChannel, k8sDownstreamVersion, operatorRepo) 39 out, err := exec.Command(airgapBuildScript, k8sUpstreamVersion, certManagerVersion, rancherChannel, k8sDownstreamVersion, operatorRepo).CombinedOutput() 40 Expect(err).To(Not(HaveOccurred()), string(out)) 41 }) 42 }) 43 44 var _ = Describe("E2E - Deploy K3S/Rancher in airgap environment", Label("airgap-rancher"), func() { 45 It("Create the rancher-manager machine", func() { 46 By("Updating the default network configuration", func() { 47 // Don't check return code, as the default network could be already removed 48 for _, c := range []string{"net-destroy", "net-undefine"} { 49 _ = exec.Command("sudo", "virsh", c, "default").Run() 50 } 51 52 // Wait a bit between virsh commands 53 time.Sleep(30 * time.Second) 54 err := exec.Command("sudo", "virsh", "net-create", netDefaultFileName).Run() 55 Expect(err).To(Not(HaveOccurred())) 56 }) 57 58 By("Creating the Rancher Manager VM", func() { 59 err := exec.Command("sudo", "virt-install", 60 "--name", "rancher-manager", 61 "--memory", "16384", 62 "--vcpus", "4", 63 "--disk", "path="+os.Getenv("HOME")+"/rancher-image.qcow2,bus=sata", 64 "--import", 65 "--os-variant", "opensuse-unknown", 66 "--network=default,mac=52:54:00:00:00:10", 67 "--noautoconsole").Run() 68 Expect(err).To(Not(HaveOccurred())) 69 }) 70 }) 71 72 It("Install K3S/Rancher in the rancher-manager machine", func() { 73 airgapRepo := os.Getenv("HOME") + "/airgap_rancher" 74 archiveFile := "airgap_rancher.zst" 75 certPath := "/quay.io/jetstack/" 76 optRancher := "/opt/rancher" 77 password := "root" 78 rancherManager := "rancher-manager.test" 79 rancherPath := "/rancher/" 80 repoServer := rancherManager + ":5000" 81 userName := "root" 82 83 // For ssh access 84 client := &tools.Client{ 85 Host: "192.168.122.102:22", 86 Username: userName, 87 Password: password, 88 } 89 90 // Create kubectl context 91 // Default timeout is too small, so New() cannot be used 92 k := &kubectl.Kubectl{ 93 Namespace: "", 94 PollTimeout: tools.SetTimeout(300 * time.Second), 95 PollInterval: 500 * time.Millisecond, 96 } 97 98 By("Sending the archive file into the rancher server", func() { 99 // Destination archive file 100 destFile := optRancher + "/" + archiveFile 101 102 // Make sure SSH is available 103 CheckSSH(client) 104 105 // Create the destination repository 106 _, err := client.RunSSH("mkdir -p " + optRancher) 107 Expect(err).To(Not(HaveOccurred())) 108 109 // Send the airgap archive 110 err = client.SendFile(os.Getenv("HOME")+"/"+archiveFile, destFile, "0644") 111 Expect(err).To(Not(HaveOccurred())) 112 113 // Extract the airgap archive 114 _, err = client.RunSSH("tar -I pzstd -vxf " + destFile + " -C " + optRancher) 115 Expect(err).To(Not(HaveOccurred())) 116 117 // Delete the archive file, not needed anymore, this will save some storage too! 118 _, err = client.RunSSH("rm -f " + destFile) 119 Expect(err).To(Not(HaveOccurred())) 120 }) 121 122 By("Deploying airgap infrastructure by executing the deploy script", func() { 123 value := regexp.MustCompile(`v(.*)\+.*`).FindStringSubmatch(k8sUpstreamVersion) 124 cmd := optRancher + "/k3s_" + value[1] + "/deploy-airgap " + k8sUpstreamVersion 125 126 // Could be useful for manual debugging! 127 GinkgoWriter.Printf("Executed command: %s\n", cmd) 128 out, err := client.RunSSH(cmd) 129 Expect(err).To(Not(HaveOccurred()), string(out)) 130 }) 131 132 By("Getting the kubeconfig file of the airgap cluster", func() { 133 // Define local Kubeconfig file 134 localKubeconfig := os.Getenv("HOME") + "/.kube/config" 135 136 err := os.Mkdir(os.Getenv("HOME")+"/.kube", 0755) 137 Expect(err).To(Not(HaveOccurred())) 138 139 err = client.GetFile(localKubeconfig, "/etc/rancher/k3s/k3s.yaml", 0644) 140 Expect(err).To(Not(HaveOccurred())) 141 // NOTE: not sure that this is need because we have the config file in ~/.kube/ 142 143 err = os.Setenv("KUBECONFIG", localKubeconfig) 144 Expect(err).To(Not(HaveOccurred())) 145 146 // Replace localhost with the IP of the VM 147 err = tools.Sed("127.0.0.1", "192.168.122.102", localKubeconfig) 148 Expect(err).To(Not(HaveOccurred())) 149 }) 150 151 By("Installing kubectl", func() { 152 // TODO: Variable for kubectl version 153 err := exec.Command("curl", "-sLO", "https://dl.k8s.io/release/v1.28.2/bin/linux/amd64/kubectl").Run() 154 Expect(err).To(Not(HaveOccurred())) 155 err = exec.Command("chmod", "+x", "kubectl").Run() 156 Expect(err).To(Not(HaveOccurred())) 157 err = exec.Command("sudo", "mv", "kubectl", "/usr/local/bin/").Run() 158 Expect(err).To(Not(HaveOccurred())) 159 }) 160 161 By("Installing CertManager", func() { 162 // Get the version 163 certManagerChart, err := exec.Command("bash", "-c", "ls "+airgapRepo+"/helm/cert-manager-*.tgz").Output() 164 Expect(err).To(Not(HaveOccurred())) 165 166 // Set flags for cert-manager installation 167 flags := []string{ 168 "upgrade", "--install", "cert-manager", string(certManagerChart), 169 "--namespace", "cert-manager", 170 "--create-namespace", 171 "--set", "image.repository=" + repoServer + certPath + "cert-manager-controller", 172 "--set", "webhook.image.repository=" + repoServer + certPath + "cert-manager-webhook", 173 "--set", "cainjector.image.repository=" + repoServer + certPath + "cert-manager-cainjector", 174 "--set", "startupapicheck.image.repository=" + repoServer + certPath + "cert-manager-startupapicheck", 175 "--set", "installCRDs=true", 176 "--wait", "--wait-for-jobs", 177 } 178 179 RunHelmCmdWithRetry(flags...) 180 181 checkList := [][]string{ 182 {"cert-manager", "app.kubernetes.io/component=controller"}, 183 {"cert-manager", "app.kubernetes.io/component=webhook"}, 184 {"cert-manager", "app.kubernetes.io/component=cainjector"}, 185 } 186 err = rancher.CheckPod(k, checkList) 187 Expect(err).To(Not(HaveOccurred())) 188 }) 189 190 By("Installing Rancher", func() { 191 // TODO: Use the DeployRancherManager function from install.go 192 rancherManagerChart, err := exec.Command("bash", "-c", "ls "+airgapRepo+"/helm/rancher-*.tgz").Output() 193 Expect(err).To(Not(HaveOccurred())) 194 195 // Set flags for Rancher Manager installation 196 flags := []string{ 197 "upgrade", "--install", "rancher", string(rancherManagerChart), 198 "--namespace", "cattle-system", 199 "--create-namespace", 200 "--set", "hostname=" + rancherManager, 201 "--set", "bootstrapPassword=rancherpassword", 202 "--set", "extraEnv[0].name=CATTLE_SERVER_URL", 203 "--set", "extraEnv[0].value=https://" + rancherManager, 204 "--set", "replicas=1", 205 "--set", "useBundledSystemChart=true", 206 "--set", "rancherImage=" + repoServer + rancherPath + "rancher", 207 "--set", "systemDefaultRegistry=" + repoServer, 208 "--wait", "--wait-for-jobs", 209 } 210 211 RunHelmCmdWithRetry(flags...) 212 213 // Wait for all pods to be started 214 checkList := [][]string{ 215 {"cattle-system", "app=rancher"}, 216 {"cattle-fleet-local-system", "app=fleet-agent"}, 217 {"cattle-system", "app=rancher-webhook"}, 218 } 219 err = rancher.CheckPod(k, checkList) 220 Expect(err).To(Not(HaveOccurred())) 221 }) 222 223 By("Installing Elemental Operator", func() { 224 // Install Elemental Operator CRDs first 225 // Set flags for Elemental Operator CRDs installation 226 elementalCrdsChart, err := exec.Command("bash", "-c", "ls "+airgapRepo+"/helm/elemental-operator-crds-chart-*.tgz").Output() 227 Expect(err).To(Not(HaveOccurred())) 228 229 flags := []string{ 230 "upgrade", "--install", "elemental-crds", string(elementalCrdsChart), 231 "--namespace", "cattle-elemental-system", 232 "--create-namespace", 233 } 234 235 RunHelmCmdWithRetry(flags...) 236 time.Sleep(20 * time.Second) 237 238 // Set flags for Elemental Operator installation 239 elementalChart, err := exec.Command("bash", "-c", "ls "+airgapRepo+"/helm/elemental-operator-chart-*.tgz").Output() 240 Expect(err).To(Not(HaveOccurred())) 241 242 flags = []string{ 243 "upgrade", "--install", "elemental", string(elementalChart), 244 "--namespace", "cattle-elemental-system", 245 "--create-namespace", 246 "--set", "image.repository=" + repoServer + rancherPath + "elemental-operator", 247 "--set", "seedImage.repository=" + repoServer + rancherPath + "seedimage-builder", 248 "--set", "channel.image=" + repoServer + rancherPath + "elemental-channel-" + rancherManager, 249 "--set", "registryUrl=", 250 "--wait", "--wait-for-jobs", 251 } 252 253 RunHelmCmdWithRetry(flags...) 254 255 // Wait for pod to be started 256 err = rancher.CheckPod(k, [][]string{{"cattle-elemental-system", "app=elemental-operator"}}) 257 Expect(err).To(Not(HaveOccurred())) 258 }) 259 }) 260 })