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  })