From 036ed8efbad8606d899bce47867ad6f261aed58d Mon Sep 17 00:00:00 2001 From: Dimitris Karakasilis Date: Wed, 4 Sep 2024 15:27:39 +0300 Subject: [PATCH] Add upgrade uki test (#2776) * [WIP] Add upgrade uki test Signed-off-by: Dimitris Karakasilis * Avoid hardcoding single entry Signed-off-by: Dimitris Karakasilis * Fix sed Signed-off-by: Dimitris Karakasilis * Remove irrelevant option because otherwise we get this error: Error: overlay-iso is only supported for iso artifacts Signed-off-by: Dimitris Karakasilis * Don't use earthly to build the upgrade image because the target needs to be adapted to accept a local dir and it's a mess in Earthly Signed-off-by: Dimitris Karakasilis * Fix image name Signed-off-by: Dimitris Karakasilis * Add TODO to test Signed-off-by: Dimitris Karakasilis * Temporarily change to kairos-agent dev branch Signed-off-by: Dimitris Karakasilis * Implement TODO Signed-off-by: Dimitris Karakasilis * Use new flag Signed-off-by: Dimitris Karakasilis * Add quotes to sed Signed-off-by: Dimitris Karakasilis * Make quotes optional Signed-off-by: Dimitris Karakasilis * Fix problem with special characters coming from the transfer of the text over ssh. `out` had special characters like ^F and ^A in it. Signed-off-by: Dimitris Karakasilis * Remove dev branch (we have the fix on master now) Signed-off-by: Dimitris Karakasilis * Make the test work also on Alpine because the device there appears as /dev/dm-0 Signed-off-by: Dimitris Karakasilis --------- Signed-off-by: Dimitris Karakasilis --- .github/workflows/reusable-uki-test.yaml | 30 ++++++++++++++++- Earthfile | 5 +-- tests/encryption_test.go | 11 ++++--- tests/uki_test.go | 41 ++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/.github/workflows/reusable-uki-test.yaml b/.github/workflows/reusable-uki-test.yaml index 4b0845347..ca89470ba 100644 --- a/.github/workflows/reusable-uki-test.yaml +++ b/.github/workflows/reusable-uki-test.yaml @@ -72,10 +72,35 @@ jobs: run: | earthly +uki-iso \ --BASE_IMAGE=$TEMP_IMAGE \ - --ENKI_OVERLAY_DIR=tests/assets/sysext/ --ENKI_KEYS_DIR=tests/assets/keys/ + --ENKI_OVERLAY_DIR=tests/assets/sysext/ \ + --ENKI_KEYS_DIR=tests/assets/keys/ \ + --ENKI_FLAGS="--single-efi-cmdline \"testentry: nothing\"" - name: Create datasource iso 🔧 run: | earthly +datasource-iso --CLOUD_CONFIG=tests/assets/uki-install.yaml + - name: Build uki upgrade image 🔧 + run: | + rm -rf /tmp/unpacked + sudo luet util unpack "${TEMP_IMAGE}" ./unpacked + new_version="mynewversion" + sudo sed -i 's/^KAIROS_VERSION=.*/KAIROS_VERSION="'$new_version'"/' ./unpacked/etc/os-release + echo "$new_version" > "${PWD}/build/expected_new_version" + + docker run --rm \ + -v $PWD/unpacked:/unpacked \ + -v $PWD/build:/result \ + -v $PWD/tests/assets/keys:/keys \ + quay.io/kairos/osbuilder-tools:latest build-uki dir:/unpacked \ + --output-dir /result --keys /keys --output-type container \ + --single-efi-cmdline "myentry: foobar" + + docker load -i build/*.tar + image=$(docker load -i build/*.tar | grep "Loaded image" | awk -F: '{ st = index($0,":");print substr($0,st+1)}' | xargs) + rand=$(head /dev/urandom | tr -dc a-z0-9 | head -c 7) + temp_image=ttl.sh/$(echo $image | sed "s/:latest/-${rand}:6h/") + docker tag $image $temp_image + docker push $temp_image + echo $temp_image > build/upgrade_image_name - name: Run tests 🔧 env: USE_QEMU: true @@ -88,6 +113,9 @@ jobs: run: | export ISO=$(ls $PWD/build/kairos_*.iso) export DATASOURCE=${PWD}/build/datasource.iso + export UPGRADE_IMAGE=$(cat "${PWD}/build/upgrade_image_name") + export EXPECTED_NEW_VERSION=$(cat "${PWD}/build/expected_new_version") + export EXPECTED_SINGLE_ENTRY="testentry" cp tests/go.* . go run github.com/onsi/ginkgo/v2/ginkgo -v --label-filter "uki" --fail-fast -r ./tests/ - name: Install kairos-agent (for versioneer) diff --git a/Earthfile b/Earthfile index e4aaba5d9..18fcd12cc 100644 --- a/Earthfile +++ b/Earthfile @@ -352,9 +352,10 @@ uki-iso: IF [ "$ENKI_OVERLAY_DIR" != "" ] COPY $ENKI_OVERLAY_DIR /overlay-iso - RUN --no-cache enki build-uki $BASE_IMAGE --output-dir /build/ -k /keys --output-type ${ENKI_OUTPUT_TYPE} --overlay-iso /overlay-iso ${ENKI_FLAGS} + + RUN --no-cache echo $ENKI_FLAGS | xargs enki build-uki $BASE_IMAGE --output-dir /build/ -k /keys --output-type ${ENKI_OUTPUT_TYPE} --overlay-iso /overlay-iso ELSE - RUN --no-cache enki build-uki $BASE_IMAGE --output-dir /build/ -k /keys --output-type ${ENKI_OUTPUT_TYPE} ${ENKI_FLAGS} + RUN --no-cache echo $ENKI_FLAGS | xargs enki build-uki $BASE_IMAGE --output-dir /build/ -k /keys --output-type ${ENKI_OUTPUT_TYPE} END diff --git a/tests/encryption_test.go b/tests/encryption_test.go index 9db420991..0bbadc80e 100644 --- a/tests/encryption_test.go +++ b/tests/encryption_test.go @@ -2,10 +2,6 @@ package mos_test import ( "fmt" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - . "github.com/spectrocloud/peg/matcher" - "gopkg.in/yaml.v3" "os" "os/exec" "path" @@ -13,6 +9,11 @@ import ( "strconv" "strings" "syscall" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/spectrocloud/peg/matcher" + "gopkg.in/yaml.v3" ) var installationOutput string @@ -316,7 +317,7 @@ install: out, err := vm.Sudo("blkid") Expect(err).ToNot(HaveOccurred(), out) Expect(out).To(MatchRegexp("TYPE=\"crypto_LUKS\" PARTLABEL=\"persistent\""), out) - Expect(out).To(MatchRegexp("/dev/mapper.*LABEL=\"COS_PERSISTENT\""), out) + Expect(out).To(MatchRegexp("/dev/(mapper|dm).*LABEL=\"COS_PERSISTENT\""), out) }) }) diff --git a/tests/uki_test.go b/tests/uki_test.go index 5e3da4150..f18e2b9e6 100644 --- a/tests/uki_test.go +++ b/tests/uki_test.go @@ -7,6 +7,7 @@ import ( "path/filepath" "strings" "time" + "unicode" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -20,6 +21,18 @@ var _ = Describe("kairos UKI test", Label("uki"), Ordered, func() { if os.Getenv("FIRMWARE") == "" { Fail("FIRMWARE environment variable set to a EFI firmware is needed for UKI test") } + + if os.Getenv("EXPECTED_NEW_VERSION") == "" { + Fail("EXPECTED_NEW_VERSION environment variable is needed for the UKI upgrade test") + } + + if os.Getenv("EXPECTED_SINGLE_ENTRY") == "" { + Fail("EXPECTED_SINGLE_ENTRY environment variable is needed for the UKI upgrade test") + } + + if os.Getenv("UPGRADE_IMAGE") == "" { + Fail("UPGRADE_IMAGE environment variable is needed for the UKI upgrade test") + } }) BeforeEach(func() { @@ -256,5 +269,33 @@ var _ = Describe("kairos UKI test", Label("uki"), Ordered, func() { out, err = vm.Sudo("ls /usr/local/after-reset-file") Expect(err).ToNot(HaveOccurred(), out) Expect(out).ToNot(MatchRegexp("No such file or directory")) + + By("upgrading a single boot entry") + upgradeImage := os.Getenv("UPGRADE_IMAGE") + out, err = vm.Sudo(fmt.Sprintf("kairos-agent --debug upgrade --source oci:%s --boot-entry %s", upgradeImage, os.Getenv("EXPECTED_SINGLE_ENTRY"))) + Expect(err).ToNot(HaveOccurred(), out) + out, err = vm.Sudo(fmt.Sprintf("kairos-agent --debug bootentry --select %s", os.Getenv("EXPECTED_SINGLE_ENTRY"))) + Expect(err).ToNot(HaveOccurred(), out) + vm.Reboot() + vm.EventuallyConnects(1200) + + By("checking if upgrade worked") + out, err = vm.Sudo("cat /etc/os-release") + Expect(err).ToNot(HaveOccurred(), out) + Expect(out).To(MatchRegexp(fmt.Sprintf("KAIROS_VERSION=\"?%s\"?", os.Getenv("EXPECTED_NEW_VERSION")))) + + out, err = vm.Sudo("cat /sys/firmware/efi/efivars/LoaderEntrySelected-*") + Expect(err).ToNot(HaveOccurred(), out) + selectedEntry := removeSpecialChars(out) + Expect(selectedEntry).To(Equal(fmt.Sprintf("%s.conf", strings.TrimSpace(os.Getenv("EXPECTED_SINGLE_ENTRY"))))) }) }) + +func removeSpecialChars(str string) string { + return strings.Map(func(r rune) rune { + if unicode.IsPrint(r) { + return r + } + return -1 + }, str) +}