Skip to content

Commit

Permalink
ci: add airgap e2e test (#1034)
Browse files Browse the repository at this point in the history
  • Loading branch information
juadk committed Oct 12, 2023
1 parent fd5eef4 commit 3b0d8e2
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 27 deletions.
154 changes: 154 additions & 0 deletions .github/workflows/airgap-e2e.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: Elemental Airgap E2E tests with Rancher Manager

on:
pull_request:
#test
workflow_dispatch:
inputs:
qase_run_id:
description: Case run ID where the results will be reported
required: false
type: string
cert-manager_version:
description: Version of cert-manager to use
type: string
destroy_runner:
description: Destroy the auto-generated self-hosted runner
default: true
type: boolean
operator_repo:
description: Elemental operator repository to use
type: string
default: oci://registry.opensuse.org/isv/rancher/elemental/dev/charts/rancher
os_to_test:
description: OS repository to test (dev/staging/stable)
type: string
default: dev
rancher_version:
description: Rancher Manager channel/version to use for installation
default: stable/latest
type: string

jobs:
create-runner:
runs-on: ubuntu-latest
outputs:
uuid: ${{ steps.generator.outputs.uuid }}
runner: ${{ steps.generator.outputs.runner }}
public_dns: ${{ steps.dns.outputs.public_dns }}
steps:
# actions/checkout MUST come before auth
- name: Checkout
uses: actions/checkout@v3
- name: Generate UUID and Runner hostname
id: generator
run: |
UUID=$(uuidgen)
echo "uuid=${UUID}" >> ${GITHUB_OUTPUT}
echo "runner=elemental-ci-${UUID}" >> ${GITHUB_OUTPUT}
- name: Authenticate to GCP
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- name: Setup gcloud
uses: google-github-actions/setup-gcloud@v1
- name: Create runner
run: |
gcloud compute instances create ${{ steps.generator.outputs.runner }} \
--source-instance-template elemental-e2e-ci-runner-spot-x86-64-template-n2-standard-16-v4 \
--zone us-central1-a
- name: Create PAT token secret
run: |
echo -n ${{ secrets.SELF_HOSTED_RUNNER_PAT_TOKEN }} \
| gcloud secrets create PAT_TOKEN_${{ steps.generator.outputs.uuid }} --data-file=-
- name: Get public dns name in GCP
id: dns
run: |
# Do a timed out loop here, as gcloud can sometimes fail
typeset -i i=0
while true; do
# Get public IP
PUBLIC_IP=$(gcloud compute instances list 2> /dev/null \
| awk '/${{ steps.generator.outputs.runner }}/ {print $6}')
# Exit if we reach the timeout or if IP is set
if (( ++i > 10 )) || [[ -n "${PUBLIC_IP}" ]]; then
break
fi
# Wait a little before retrying
sleep 2
done
# Get the public DNS
PUBLIC_DNS=$(host -l ${PUBLIC_IP} 2> /dev/null \
| awk '{sub(/\.$/, ""); print $5}')
echo "public_dns=${PUBLIC_DNS}" >> ${GITHUB_OUTPUT}
# Raise an error if either IP and/or DNS are empty
if [[ -z "${PUBLIC_IP}" || -z "${PUBLIC_DNS}" ]]; then
echo "PUBLIC_IP and/or PUBLIC_DNS are empty!" >&2
false
fi
e2e:
needs: create-runner
runs-on: ${{ needs.create-runner.outputs.uuid }}
env:
ARCH: amd64
CERT_MANAGER_VERSION: v1.12.2
# Distribution to use to host Rancher Manager (K3s)
K8S_UPSTREAM_VERSION: 1.26.7
# QASE variables
QASE_API_TOKEN: ${{ secrets.qase_api_token }}
QASE_RUN_ID: ${{ inputs.qase_run_id }}
# For Rancher Manager
RANCHER_VERSION: stable/2.7.6
TIMEOUT_SCALE: 3
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v3
with:
go-version-file: tests/go.mod
- name: Prepare the archive file to send to air-gapped nodes
run: |
cd tests && make e2e-prepare-archive && make e2e-airgap-rancher

# - name: Deploy a node to join Rancher manager
# if: inputs.test_type == 'ui'
# env:
# ISO_BOOT: ${{ inputs.iso_boot }}
# VM_INDEX: 1
# VM_MEM: 8192
# HOST_MEMORY_RESERVED: 49152
# run: |
# cd tests && (
# # Removing 'downloads' is needed to avoid this error during 'make':
# # 'pattern all: open .../elemental/tests/cypress/downloads: permission denied'
# sudo rm -rf cypress/latest/downloads
# make e2e-ui-rancher
# )
#
# - name: Configure Rancher & Libvirt
# if: inputs.test_type == 'cli'
# run: cd tests && make e2e-configure-rancher
# delete-runner:
# if: always() && needs.create-runner.result == 'success' && inputs.destroy_runner == true
# needs: [create-runner, e2e]
# runs-on: ubuntu-latest
# steps:
# # actions/checkout MUST come before auth
# - name: Checkout
# uses: actions/checkout@v3
# - name: Authenticate to GCP
# uses: google-github-actions/auth@v1
# with:
# credentials_json: ${{ secrets.credentials }}
# - name: Setup gcloud
# uses: google-github-actions/setup-gcloud@v1
# - name: Delete PAT token secret
# run: |
# gcloud --quiet secrets delete PAT_TOKEN_${{ needs.create-runner.outputs.uuid }}
# - name: Delete runner
# run: |
# gcloud --quiet compute instances delete ${{ needs.create-runner.outputs.runner }} \
# --delete-disks all \
# --zone ${{ inputs.zone }}
4 changes: 4 additions & 0 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ generate-readme:
@./scripts/generate-readme > README.md

# E2E tests
e2e-airgap-rancher: deps
ginkgo --label-filter airgap-rancher -r -v ./e2e
e2e-bootstrap-node: deps
ginkgo --timeout $(GINKGO_TIMEOUT)s --label-filter bootstrap -r -v ./e2e

Expand Down Expand Up @@ -72,6 +74,8 @@ e2e-install-backup-restore: deps
e2e-iso-image: deps
ginkgo --label-filter iso-image -r -v ./e2e

e2e-prepare-archive: deps
ginkgo --label-filter prepare-archive -r -v ./e2e
e2e-ui-rancher: deps
ginkgo --label-filter ui -r -v ./e2e

Expand Down
15 changes: 15 additions & 0 deletions tests/assets/net-default-airgap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<network xmlns:dnsmasq='http://libvirt.org/schemas/network/dnsmasq/1.0'>
<name>default</name>
<bridge name='virbr0' stp='on' delay='0'/>
<dns>
<host ip='192.168.122.102'>
<hostname>rancher-manager.test</hostname>
</host>
</dns>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.100' end='192.168.122.254'/>
<host mac='52:54:00:00:00:01' name='rancher-manager' ip='192.168.122.102'/>
</dhcp>
</ip>
</network>
72 changes: 72 additions & 0 deletions tests/e2e/airgap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright © 2022 - 2023 SUSE LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package e2e_test

import (
"os/exec"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("E2E - Build the airgap archive", Label("prepare-archive"), func() {
It("Execute the script to build the archive", func() {
err := exec.Command("sudo", airgapBuildScript, k8sUpstreamVersion, certManagerVersion, rancherVersion).Run()
Expect(err).To(Not(HaveOccurred()))
})
})

var _ = Describe("E2E - Deploy K3S/Rancher in airgap environment", Label("airgap-rancher"), func() {
It("Create the rancher-manager machine", func() {
By("Updating the default network configuration", func() {
// Don't check return code, as the default network could be already removed
for _, c := range []string{"net-destroy", "net-undefine"} {
_ = exec.Command("sudo", "virsh", c, "default").Run()
}

// Wait a bit between virsh commands
time.Sleep(1 * time.Minute)
err := exec.Command("sudo", "virsh", "net-create", netDefaultAirgapFileName).Run()
Expect(err).To(Not(HaveOccurred()))
})

By("Downloading the qcow2 image from GCP storage", func() {
err := exec.Command("/opt/google-cloud-sdk/bin/gcloud", "storage", "cp", "gs://elemental-airgap-image/rancher-image.qcow2", "/home/gh-runner/rancher-image.qcow2").Run()
Expect(err).To(Not(HaveOccurred()))
})

By("Creating the VM", func() {
err := exec.Command("sudo", "virt-install",
"--name", "rancher-manager",
"--memory", "4096",
"--vcpus", "2",
"--disk", "path=/home/gh-runner/rancher-image.qcow2,bus=sata",
"--import",
"--os-variant", "opensuse-unknown",
"--network=default,mac=52:54:00:00:00:01",
"--noautoconsole").Run()
Expect(err).To(Not(HaveOccurred()))
})
})

It("Install K3S/Rancher in the rancher-manager machine", func() {
By("Add the default route", func() {
})

By("Copy and execute the deploy script", func() {
})
})
})
2 changes: 1 addition & 1 deletion tests/e2e/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ var _ = Describe("E2E - Install Rancher Manager", Label("install"), func() {
}

if clusterType == "hardened" {
flags = append(flags, "--version", CertManagerVersion)
flags = append(flags, "--version", certManagerVersion)
}

RunHelmCmdWithRetry(flags...)
Expand Down
54 changes: 28 additions & 26 deletions tests/e2e/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,37 +30,39 @@ import (
)

const (
appYaml = "../assets/hello-world_app.yaml"
backupYaml = "../assets/backup.yaml"
clusterYaml = "../assets/cluster.yaml"
ciTokenYaml = "../assets/local-kubeconfig-token-skel.yaml"
configPrivateCAScript = "../scripts/config-private-ca"
dumbRegistrationYaml = "../assets/dumb_machineRegistration.yaml"
emulateTPMYaml = "../assets/emulateTPM.yaml"
getOSScript = "../scripts/get-name-from-managedosversion"
httpSrv = "http://192.168.122.1:8000"
installConfigYaml = "../../install-config.yaml"
installHardenedScript = "../scripts/config-hardened"
installVMScript = "../scripts/install-vm"
localKubeconfigYaml = "../assets/local-kubeconfig-skel.yaml"
netDefaultFileName = "../assets/net-default.xml"
numberOfNodesMax = 30
registrationYaml = "../assets/machineRegistration.yaml"
resetMachineInv = "../assets/reset_machine_inventory.yaml"
restoreYaml = "../assets/restore.yaml"
seedImageYaml = "../assets/seedImage.yaml"
selectorYaml = "../assets/selector.yaml"
upgradeSkelYaml = "../assets/upgrade_skel.yaml"
userName = "root"
userPassword = "r0s@pwd1"
vmNameRoot = "node"
airgapBuildScript = "../scripts/build-airgap"
appYaml = "../assets/hello-world_app.yaml"
backupYaml = "../assets/backup.yaml"
clusterYaml = "../assets/cluster.yaml"
ciTokenYaml = "../assets/local-kubeconfig-token-skel.yaml"
configPrivateCAScript = "../scripts/config-private-ca"
dumbRegistrationYaml = "../assets/dumb_machineRegistration.yaml"
emulateTPMYaml = "../assets/emulateTPM.yaml"
getOSScript = "../scripts/get-name-from-managedosversion"
httpSrv = "http://192.168.122.1:8000"
installConfigYaml = "../../install-config.yaml"
installHardenedScript = "../scripts/config-hardened"
installVMScript = "../scripts/install-vm"
localKubeconfigYaml = "../assets/local-kubeconfig-skel.yaml"
netDefaultFileName = "../assets/net-default.xml"
netDefaultAirgapFileName = "../assets/net-default-airgap.xml"
numberOfNodesMax = 30
registrationYaml = "../assets/machineRegistration.yaml"
resetMachineInv = "../assets/reset_machine_inventory.yaml"
restoreYaml = "../assets/restore.yaml"
seedImageYaml = "../assets/seedImage.yaml"
selectorYaml = "../assets/selector.yaml"
upgradeSkelYaml = "../assets/upgrade_skel.yaml"
userName = "root"
userPassword = "r0s@pwd1"
vmNameRoot = "node"
)

var (
arch string
backupRestoreVersion string
caType string
CertManagerVersion string
certManagerVersion string
clusterName string
clusterNS string
clusterType string
Expand Down Expand Up @@ -199,7 +201,7 @@ var _ = BeforeSuite(func() {
arch = os.Getenv("ARCH")
backupRestoreVersion = os.Getenv("BACKUP_RESTORE_VERSION")
caType = os.Getenv("CA_TYPE")
CertManagerVersion = os.Getenv("CERT_MANAGER_VERSION")
certManagerVersion = os.Getenv("CERT_MANAGER_VERSION")
clusterName = os.Getenv("CLUSTER_NAME")
clusterNS = os.Getenv("CLUSTER_NS")
clusterType = os.Getenv("CLUSTER_TYPE")
Expand Down
Loading

0 comments on commit 3b0d8e2

Please sign in to comment.