Skip to content

Commit

Permalink
Improve uki tests
Browse files Browse the repository at this point in the history
Signed-off-by: Itxaka <itxaka@kairos.io>
  • Loading branch information
Itxaka committed Sep 29, 2023
1 parent 3a54c8f commit 900a124
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 22 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/uki.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ jobs:
# Do fedora as its the smaller uki possible
# Use immmucore master as it has patches not released for uki
# Use kairos-agent uki_operations branch, which provides ongoing uki
earthly +uki-iso --FLAVOR=fedora --KAIROS_AGENT_DEV=true --KAIROS_AGENT_DEV_BRANCH=uki_operations --IMMUCORE_DEV=true --IMMUCORE_DEV_BRANCH=master
earthly +iso-uki --FLAVOR=fedora --KAIROS_AGENT_DEV=true --KAIROS_AGENT_DEV_BRANCH=uki_operations --IMMUCORE_DEV=true --IMMUCORE_DEV_BRANCH=master
- name: Run tests
env:
USE_QEMU: true
KVM: true
MEMORY: 4000
CPUS: 2
FIRMWARE: /usr/share/OVMF/OVMF_CODE.fd
FIRMWARE: /usr/share/OVMF/OVMF_CODE.secboot.fd
run: |
export UKI_DRIVE=${PWD}/build/disk.img
export ISO=$(ls $PWD/build/kairos-core-*fedora*.iso)
cp tests/go.* .
go run github.com/onsi/ginkgo/v2/ginkgo -v --label-filter "uki" --fail-fast -r ./tests/
Binary file added tests/assets/efivars.fd
Binary file not shown.
183 changes: 183 additions & 0 deletions tests/assets/efivars.json

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions tests/assets/efivars.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
2 Files provided for testing efivars

efivars.fd is the compiled efivars in a format that qemu can understand
efivars.json is the original json from where the efivars.fd file was created

efivars.fd can be recreated by using `virt-fw-vars` from the package `python3-virt-firmware` and is used to manipulate
efivars files and generate new ones from templates.

Assuming the OVMF package is installed and the default firmware and efivars files are at /usr/share/OVMF you can run the following to regenerate the efivars file

```bash
virt-fw-vars -i /usr/share/OVMF/OVMF_VARS.fd --set-json efivars.json -o efivars.fd
```

This uses `/usr/share/OVMF/OVMF_VARS.fd` as the base template (is empty), loads the vars from `efivars.json` and outputs the efivars.fd file


The current efivars sets the boot order to first boot from HD and then from DVD.
Enables SecureBoot wiht the default keys.
It also bundles the certs for our testing, available at $ROOT/tess/keys/ and what our test UKI EFI files are signed for.

This helps when testing install media as on the first boot there is nothing on disk so it falls back to DVD, then after the first reboot it boots from the installed system.
30 changes: 16 additions & 14 deletions tests/tests_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"testing"
"time"
Expand Down Expand Up @@ -191,22 +192,23 @@ func startVM() (context.Context, VM) {
func(m *types.MachineConfig) error {
FW := os.Getenv("FIRMWARE")
if FW != "" {
m.Args = append(m.Args,
"-bios", FW)
}
m.Args = append(m.Args, "-drive",
fmt.Sprintf("file=%s,if=pflash,format=raw,readonly=on", FW),
)

// Set custom vars file for efi config so we boot first from disk then from DVD
getwd, err := os.Getwd()
if err != nil {
return err
}
m.Args = append(m.Args, "-drive",
fmt.Sprintf("file=%s,if=pflash,format=raw", filepath.Join(getwd, "/assets/efivars.fd")),
)
// Needed to be set for secureboot!
m.Args = append(m.Args, "-machine", "q35,smm=on")

return nil
},
// UKI boot
func(m *types.MachineConfig) error {
drive := os.Getenv("UKI_DRIVE")
// UKI drive needs to be set with bootindex=0 to be able to boot from that disk directly
// Otherwise it won't boot
if drive != "" {
m.Args = append(m.Args,
"-drive", fmt.Sprintf("file=%s,if=none,index=0,media=disk,format=raw,id=disk1", drive),
"-device", "virtio-blk-pci,drive=disk1,bootindex=0")
}

return nil
},
types.WithDataSource(os.Getenv("DATASOURCE")),
Expand Down
46 changes: 41 additions & 5 deletions tests/uki_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ var _ = Describe("kairos UKI test", Label("uki"), Ordered, func() {
var vm VM

BeforeAll(func() {
if os.Getenv("UKI_DRIVE") == "" {
Fail("UKI_DRIVE environment variable set to a UKI disk is needed for UKI test")
}
if os.Getenv("FIRMWARE") == "" {
Fail("FIRMWARE environment variable set to a EFI firmware is needed for UKI test")
}
Expand All @@ -28,13 +25,52 @@ var _ = Describe("kairos UKI test", Label("uki"), Ordered, func() {

AfterEach(func() {
if CurrentSpecReport().Failed() {
gatherLogs(vm)
//gatherLogs(vm)
}

err := vm.Destroy(nil)
Expect(err).ToNot(HaveOccurred())
})
It("passes checks", func() {
By("Checking SecureBoot is enabled", func() {
out, err := vm.Sudo(`dmesg|grep -i secure| grep -i enabled`)
Expect(err).ToNot(HaveOccurred(), out)
})
By("Checking the boot mode (install)", func() {
out, err := vm.Sudo("stat /run/cos/uki_install_mode")
Expect(err).ToNot(HaveOccurred(), out)
})
By("Checking OEM/PERSISTENT are not mounted", func() {
out, err := vm.Sudo("mount")
Expect(err).ToNot(HaveOccurred())
Expect(out).ToNot(ContainSubstring("/dev/disk/by-label/COS_OEM"))
Expect(out).ToNot(ContainSubstring("/dev/disk/by-label/COS_PERSISTENT"))
})
By("installing kairos", func() {
out, err := vm.Sudo(`kairos-agent --debug uki install --device /dev/vda`)
Expect(err).ToNot(HaveOccurred(), out)
Expect(out).Should(ContainSubstring("Running after-install hook"))
vm.Sudo("sync")
})

By("waiting for VM to reboot", func() {
vm.Reboot()
vm.EventuallyConnects(1200)
})
By("Checking the boot mode (boot)", func() {
out, err := vm.Sudo("stat /run/cos/uki_boot_mode")
Expect(err).ToNot(HaveOccurred(), out)
})
By("Checking SecureBoot is enabled", func() {
out, err := vm.Sudo(`dmesg|grep -i secure| grep -i enabled`)
Expect(err).ToNot(HaveOccurred(), out)
})
By("Checking OEM/PERSISTENT are mounted", func() {
out, err := vm.Sudo("df -h") // Shows the disk by label which is easier to check
Expect(err).ToNot(HaveOccurred())
Expect(out).To(ContainSubstring("/dev/disk/by-label/COS_OEM"))
Expect(out).To(ContainSubstring("/dev/disk/by-label/COS_PERSISTENT"))
})

By("checking custom cmdline", func() {
out, err := vm.Sudo("cat /proc/cmdline")
Expand Down Expand Up @@ -81,7 +117,7 @@ var _ = Describe("kairos UKI test", Label("uki"), Ordered, func() {
By("checking corresponding state", func() {
out, err := vm.Sudo("kairos-agent state")
Expect(err).ToNot(HaveOccurred())
// TODO: make agetn report uki_mode or something?
// TODO: make agent report uki_mode or something?
Expect(out).To(ContainSubstring("boot: unknown"))
currentVersion, err := vm.Sudo(getVersionCmd)
Expect(err).ToNot(HaveOccurred(), currentVersion)
Expand Down

0 comments on commit 900a124

Please sign in to comment.