diff --git a/.cci.jenkinsfile b/.cci.jenkinsfile index 815ae1327c..2401f2e775 100644 --- a/.cci.jenkinsfile +++ b/.cci.jenkinsfile @@ -39,6 +39,7 @@ pod(image: 'registry.fedoraproject.org/fedora:31', runAsUser: 0, kvm: true, memo }, buildextend: { cosa_cmd("buildextend-metal") + cosa_cmd("buildextend-metal4k") cosa_cmd("buildextend-live") cosa_cmd("buildextend-openstack") cosa_cmd("buildextend-vmware") @@ -50,7 +51,9 @@ pod(image: 'registry.fedoraproject.org/fedora:31', runAsUser: 0, kvm: true, memo } stage("Image tests") { - shwrap("cd /srv && env TMPDIR=\$(pwd)/tmp/ cosa kola testiso -S") + shwrap("cd /srv && env TMPDIR=\$(pwd)/tmp/ kola testiso -S") + // and again this time with the 4k image + shwrap("cd /srv && env TMPDIR=\$(pwd)/tmp/ kola testiso -S --qemu-native-4k --no-pxe") } // Needs to be last because it's destructive diff --git a/mantle/cmd/kola/options.go b/mantle/cmd/kola/options.go index 7fd1a5caa5..5dfd4a2c59 100644 --- a/mantle/cmd/kola/options.go +++ b/mantle/cmd/kola/options.go @@ -164,8 +164,13 @@ func syncOptionsImpl(useCosa bool) error { if kola.QEMUOptions.Native4k && kola.QEMUOptions.Firmware == "bios" { return fmt.Errorf("native 4k requires uefi firmware") } + // default to BIOS, or UEFI for 4k if kola.QEMUOptions.Firmware == "" { - kola.QEMUOptions.Firmware = "bios" + if kola.QEMUOptions.Native4k { + kola.QEMUOptions.Firmware = "uefi" + } else { + kola.QEMUOptions.Firmware = "bios" + } } if err := validateOption("platform", kolaPlatform, kolaPlatforms); err != nil { diff --git a/mantle/cmd/kola/testiso.go b/mantle/cmd/kola/testiso.go index dbaeeebd31..b864d5f496 100644 --- a/mantle/cmd/kola/testiso.go +++ b/mantle/cmd/kola/testiso.go @@ -55,6 +55,7 @@ var ( legacy bool nolive bool nopxe bool + noiso bool console bool ) @@ -75,6 +76,7 @@ func init() { cmdTestIso.Flags().BoolVarP(&legacy, "legacy", "K", false, "Test legacy installer") cmdTestIso.Flags().BoolVarP(&nolive, "no-live", "L", false, "Skip testing live installer (PXE and ISO)") cmdTestIso.Flags().BoolVarP(&nopxe, "no-pxe", "P", false, "Skip testing live installer PXE") + cmdTestIso.Flags().BoolVarP(&noiso, "no-iso", "", false, "Skip testing live installer ISO") cmdTestIso.Flags().BoolVar(&console, "console", false, "Display qemu console to stdout") root.AddCommand(cmdTestIso) @@ -90,6 +92,7 @@ func runTestIso(cmd *cobra.Command, args []string) error { Console: console, Firmware: kola.QEMUOptions.Firmware, + Native4k: kola.QEMUOptions.Native4k, } if instInsecure { @@ -142,15 +145,17 @@ func runTestIso(cmd *cobra.Command, args []string) error { if err := testPXE(instPxe, completionfile); err != nil { return err } - fmt.Printf("Successfully tested PXE live installer for %s\n", kola.CosaBuild.Meta.OstreeVersion) + printSuccess("PXE") } - ranTest = true - instIso := baseInst // Pretend this is Rust and I wrote .copy() - if err := testLiveIso(instIso, completionfile); err != nil { - return err + if !noiso { + ranTest = true + instIso := baseInst // Pretend this is Rust and I wrote .copy() + if err := testLiveIso(instIso, completionfile); err != nil { + return err + } + printSuccess("ISO") } - fmt.Printf("Successfully tested ISO live installer for %s\n", kola.CosaBuild.Meta.OstreeVersion) } if !ranTest { @@ -160,6 +165,14 @@ func runTestIso(cmd *cobra.Command, args []string) error { return nil } +func printSuccess(mode string) { + metaltype := "metal" + if kola.QEMUOptions.Native4k { + metaltype = "metal4k" + } + fmt.Printf("Successfully tested %s live installer for %s on %s (%s)\n", mode, kola.CosaBuild.Meta.OstreeVersion, kola.QEMUOptions.Firmware, metaltype) +} + func testPXE(inst platform.Install, completionfile string) error { completionstamp := "coreos-installer-test-OK" diff --git a/mantle/platform/metal.go b/mantle/platform/metal.go index 717b140dec..30f68399e5 100644 --- a/mantle/platform/metal.go +++ b/mantle/platform/metal.go @@ -80,6 +80,7 @@ type Install struct { CosaBuild *sdk.LocalBuild Firmware string + Native4k bool Console bool Insecure bool QemuArgs []string @@ -187,7 +188,7 @@ func setupMetalImage(builddir, metalimg, destdir string) (string, error) { metalIsCompressed := !strings.HasSuffix(metalimg, ".raw") metalname := metalimg if !metalIsCompressed { - fmt.Println("Compressing metal image") + fmt.Printf("Compressing %s\n", metalimg) metalimgpath := filepath.Join(builddir, metalimg) srcf, err := os.Open(metalimgpath) if err != nil { @@ -215,11 +216,19 @@ func setupMetalImage(builddir, metalimg, destdir string) (string, error) { } } -func newQemuBuilder(firmware string, console bool) *QemuBuilder { +func newQemuBuilder(firmware string, console bool, native4k bool) *QemuBuilder { builder := NewBuilder() builder.Firmware = firmware - builder.AddDisk(&Disk{ + + sectorSize := 0 + if native4k { + sectorSize = 4096 + } + + builder.AddPrimaryDisk(&Disk{ Size: "12G", // Arbitrary + + SectorSize: sectorSize, }) // This applies just in the legacy case @@ -243,7 +252,7 @@ func (inst *Install) setup(kern *kernelSetup) (*installerRun, error) { return nil, fmt.Errorf("Missing initramfs artifact") } - builder := newQemuBuilder(inst.Firmware, inst.Console) + builder := newQemuBuilder(inst.Firmware, inst.Console, inst.Native4k) tempdir, err := ioutil.TempDir("", "kola-testiso") if err != nil { @@ -273,7 +282,12 @@ func (inst *Install) setup(kern *kernelSetup) (*installerRun, error) { } } - metalimg := inst.CosaBuild.Meta.BuildArtifacts.Metal.Path + var metalimg string + if inst.Native4k { + metalimg = inst.CosaBuild.Meta.BuildArtifacts.Metal4KNative.Path + } else { + metalimg = inst.CosaBuild.Meta.BuildArtifacts.Metal.Path + } metalname, err := setupMetalImage(builddir, metalimg, tftpdir) if err != nil { return nil, errors.Wrapf(err, "setting up metal image") @@ -535,7 +549,12 @@ func (inst *Install) InstallViaISOEmbed(kargs []string, liveIgniton, targetIgnit builddir := inst.CosaBuild.Dir srcisopath := filepath.Join(builddir, inst.CosaBuild.Meta.BuildArtifacts.LiveIso.Path) - metalimg := inst.CosaBuild.Meta.BuildArtifacts.Metal.Path + var metalimg string + if inst.Native4k { + metalimg = inst.CosaBuild.Meta.BuildArtifacts.Metal4KNative.Path + } else { + metalimg = inst.CosaBuild.Meta.BuildArtifacts.Metal.Path + } metalname, err := setupMetalImage(builddir, metalimg, tempdir) if err != nil { return nil, errors.Wrapf(err, "setting up metal image") @@ -647,7 +666,7 @@ WantedBy=multi-user.target return nil, errors.Wrapf(err, "running coreos-installer iso embed") } - qemubuilder := newQemuBuilder(inst.Firmware, inst.Console) + qemubuilder := newQemuBuilder(inst.Firmware, inst.Console, inst.Native4k) setBuilderLiveMemory(qemubuilder) qemubuilder.AddInstallIso(isoEmbeddedPath) qemubuilder.Append(inst.QemuArgs...) diff --git a/mantle/platform/qemu.go b/mantle/platform/qemu.go index 6d458404b1..d6879de9b7 100644 --- a/mantle/platform/qemu.go +++ b/mantle/platform/qemu.go @@ -147,6 +147,7 @@ type QemuBuilder struct { ConfigFile string // ForceConfigInjection is useful for booting `metal` images directly ForceConfigInjection bool + configInjected bool Memory int Processors int @@ -527,6 +528,7 @@ func (builder *QemuBuilder) addDiskImpl(disk *Disk, primary bool) error { dstFileName, disk.SectorSize); err != nil { return errors.Wrapf(err, "ignition injection with guestfs failed") } + builder.configInjected = true } } fd, err := os.OpenFile(dstFileName, os.O_RDWR, 0) @@ -555,6 +557,11 @@ func (builder *QemuBuilder) addDiskImpl(disk *Disk, primary bool) error { if disk.SectorSize != 0 { diskOpts = append(diskOpts, fmt.Sprintf("physical_block_size=%[1]d,logical_block_size=%[1]d", disk.SectorSize)) } + // Primary disk gets bootindex 1, all other disks have unspecified + // bootindex, which means lower priority. + if primary { + diskOpts = append(diskOpts, "bootindex=1") + } builder.addQcow2DiskFd(fd, channel, diskOpts) return nil } @@ -571,9 +578,14 @@ func (builder *QemuBuilder) AddDisk(disk *Disk) error { return builder.addDiskImpl(disk, false) } -// AddInstallIso adds an ISO image, configuring to boot from it once +// AddInstallIso adds an ISO image func (builder *QemuBuilder) AddInstallIso(path string) error { - builder.Append("-boot", "once=d", "-cdrom", path) + // We use bootindex=2 here: the idea is that during an ISO install, the + // primary disk isn't bootable, so the bootloader will fall back to the ISO + // boot. On reboot when the system is installed, the primary disk is + // selected. This allows us to have "boot once" functionality on both UEFI + // and BIOS (`-boot once=d` OTOH doesn't work with OVMF). + builder.Append("-drive", "file="+path+",format=raw,if=none,readonly=on,id=installiso", "-device", "ide-cd,drive=installiso,bootindex=2") return nil } @@ -706,7 +718,7 @@ func (builder *QemuBuilder) Exec() (*QemuInstance, error) { argv = append(argv, "-nographic") // Handle Ignition - if builder.ConfigFile != "" { + if builder.ConfigFile != "" && !builder.configInjected { if builder.supportsFwCfg() { builder.Append("-fw_cfg", "name=opt/com.coreos/config,file="+builder.ConfigFile) } else if !builder.primaryDiskAdded {