diff --git a/mantle/cmd/kola/testiso.go b/mantle/cmd/kola/testiso.go index 0d69c194c5..0dd4ad8e1f 100644 --- a/mantle/cmd/kola/testiso.go +++ b/mantle/cmd/kola/testiso.go @@ -338,47 +338,7 @@ func runTestIso(cmd *cobra.Command, args []string) error { return nil } -// Currently effective on aarch64: switches the boot order to boot from disk on reboot. For s390x and aarch64, bootindex -// is used to boot from the network device (boot once is not supported). For s390x, the boot ordering was not a problem as it -// would always read from disk first. For aarch64, the bootindex needs to be switched to boot from disk before a reboot -func switchBootOrder(tempdir string) error { - if tempdir == "" || (system.RpmArch() != "s390x" && system.RpmArch() != "aarch64") { - //Not applicable for iso installs and other arches - return nil - } - monitor, devs, err := platform.ListQMPDevices(tempdir) - if monitor != nil { - defer monitor.Disconnect() - } - if err != nil { - return errors.Wrapf(err, "Could not list devices") - } - var blkdev string - var netdev string - for _, dev := range devs.Return { - switch dev.Type { - case "child", "child": - netdev = filepath.Join("/machine/peripheral-anon", dev.Name) - break - case "child", "child", "child": - blkdev = filepath.Join("/machine/peripheral-anon", dev.Name) - break - default: - break - } - } - // unset bootindex for the network device - if err := platform.SetBootIndexForDevice(monitor, netdev, -1); err != nil { - return errors.Wrapf(err, "Could not set bootindex for netdev") - } - // set bootindex to 1 to boot from disk - if err := platform.SetBootIndexForDevice(monitor, blkdev, 1); err != nil { - return errors.Wrapf(err, "Could not set bootindex for blkdev") - } - return nil -} - -func awaitCompletion(inst *platform.QemuInstance, outdir string, tempdir string, qchan *os.File, expected []string) error { +func awaitCompletion(inst *platform.QemuInstance, outdir string, qchan *os.File, expected []string) error { errchan := make(chan error) go func() { time.Sleep(installTimeout) @@ -429,9 +389,9 @@ func awaitCompletion(inst *platform.QemuInstance, outdir string, tempdir string, errchan <- fmt.Errorf("Unexpected string from completion channel: %s expected: %s", line, exp) return } - // switch the boot order here, we are well into the installation process. Only used for PXE test now + // switch the boot order here, we are well into the installation process - only for aarch64 and s390x if line == liveOKSignal { - if err := switchBootOrder(tempdir); err != nil { + if err := inst.SwitchBootOrder(); err != nil { errchan <- errors.Wrapf(err, "switching boot order failed") return } @@ -494,7 +454,7 @@ func testPXE(inst platform.Install, outdir string, offline bool) error { } defer mach.Destroy() - return awaitCompletion(mach.QemuInst, outdir, mach.Tempdir, completionChannel, []string{liveOKSignal, signalCompleteString}) + return awaitCompletion(mach.QemuInst, outdir, completionChannel, []string{liveOKSignal, signalCompleteString}) } func testLiveIso(inst platform.Install, outdir string, offline bool) error { @@ -535,7 +495,7 @@ func testLiveIso(inst platform.Install, outdir string, offline bool) error { } defer mach.Destroy() - return awaitCompletion(mach.QemuInst, outdir, "", completionChannel, []string{liveOKSignal, signalCompleteString}) + return awaitCompletion(mach.QemuInst, outdir, completionChannel, []string{liveOKSignal, signalCompleteString}) } func testLiveLogin(outdir string) error { @@ -563,5 +523,5 @@ func testLiveLogin(outdir string) error { } defer mach.Destroy() - return awaitCompletion(mach, outdir, "", completionChannel, []string{"coreos-liveiso-success"}) + return awaitCompletion(mach, outdir, completionChannel, []string{"coreos-liveiso-success"}) } diff --git a/mantle/platform/metal.go b/mantle/platform/metal.go index 825b745c58..674c61b434 100644 --- a/mantle/platform/metal.go +++ b/mantle/platform/metal.go @@ -37,8 +37,6 @@ const ( // defaultQemuHostIPv4 is documented in `man qemu-kvm`, under the `-netdev` option defaultQemuHostIPv4 = "10.0.2.2" - targetDevice = "/dev/vda" - // rebootUnit is a copy of the system one without the ConditionPathExists rebootUnit = `[Unit] Description=Reboot after CoreOS Installer @@ -436,12 +434,6 @@ func cat(outfile string, infiles ...string) error { func (t *installerRun) run() (*QemuInstance, error) { builder := t.builder - // qmp device for switching boot order (needed for aarch64) - qmpPath := filepath.Join(t.tempdir, "qmp.sock") - qmpID := "pxe-qmp" - builder.Append("-chardev", fmt.Sprintf("socket,id=%s,path=%s,server,nowait", qmpID, qmpPath)) - builder.Append("-mon", fmt.Sprintf("chardev=%s,mode=control", qmpID)) - netdev := fmt.Sprintf("%s,netdev=mynet0,mac=52:54:00:12:34:56", t.pxe.networkdevice) if t.pxe.bootindex == "" { builder.Append("-boot", "once=n", "-option-rom", "/usr/share/qemu/pxe-rtl8139.rom") @@ -575,6 +567,14 @@ func (inst *Install) InstallViaISOEmbed(kargs []string, liveIgnition, targetIgni insecureOpt = "--insecure" } pointerIgnitionPath := "/var/opt/pointer.ign" + + targetDevice := "/dev/vda" + // For aarch64, the cdrom is a pci blk device /dev/vda + // TBD: use the serial identifier and use /dev/disk/by-id to install + if system.RpmArch() == "aarch64" { + targetDevice = "/dev/vdb" + } + installerUnit := fmt.Sprintf(` [Unit] After=network-online.target diff --git a/mantle/platform/qemu.go b/mantle/platform/qemu.go index 3c8b259449..e767af66e6 100644 --- a/mantle/platform/qemu.go +++ b/mantle/platform/qemu.go @@ -194,6 +194,47 @@ func (inst *QemuInstance) Destroy() { } } +// Currently effective on aarch64: switches the boot order to boot from disk on reboot. For s390x and aarch64, bootindex +// is used to boot from the network device (boot once is not supported). For s390x, the boot ordering was not a problem as it +// would always read from disk first. For aarch64, the bootindex needs to be switched to boot from disk before a reboot +func (inst *QemuInstance) SwitchBootOrder() error { + if system.RpmArch() != "s390x" && system.RpmArch() != "aarch64" { + //Not applicable for other arches + return nil + } + monitor, devs, err := listQMPDevices(inst.tempdir) + if monitor != nil { + defer monitor.Disconnect() + } + if err != nil { + return errors.Wrapf(err, "Could not list devices") + } + var blkdev string + var bootdev string + for _, dev := range devs.Return { + switch dev.Type { + // Boot device used for first boot - for aarch64 the cdrom is a pci blk device (used for ISO installs) + case "child", "child", "child": + bootdev = filepath.Join("/machine/peripheral-anon", dev.Name) + break + case "child", "child": + blkdev = filepath.Join("/machine/peripheral-anon", dev.Name) + break + default: + break + } + } + // unset bootindex for the network device + if err := setBootIndexForDevice(monitor, bootdev, -1); err != nil { + return errors.Wrapf(err, "Could not set bootindex for netdev") + } + // set bootindex to 1 to boot from disk + if err := setBootIndexForDevice(monitor, blkdev, 1); err != nil { + return errors.Wrapf(err, "Could not set bootindex for blkdev") + } + return nil +} + // QemuBuilder is a configurator that can then create a qemu instance type QemuBuilder struct { // ConfigFile is a path to Ignition configuration @@ -933,12 +974,8 @@ func (builder *QemuBuilder) setupIso() error { // 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). switch system.RpmArch() { - case "s390x", "ppc64le": + case "s390x", "ppc64le", "aarch64": builder.Append("-cdrom", builder.iso.path) - case "aarch64": - // TODO - can we boot from a virtual USB CDROM or a USB flash drive here? - // https://fedoraproject.org/wiki/Architectures/AArch64/Install_with_QEMU#Installing_F23_aarch64_from_CDROM seems to claim yes - return fmt.Errorf("Architecture aarch64 does not support ISO") default: bootindexStr := "" if builder.iso.bootindex != "" { @@ -1162,6 +1199,12 @@ func (builder *QemuBuilder) Exec() (*QemuInstance, error) { } + // Set up QMP (currently used to switch boot order after first boot on aarch64) + qmpPath := filepath.Join(builder.tempdir, "qmp.sock") + qmpID := "qemu-qmp" + builder.Append("-chardev", fmt.Sprintf("socket,id=%s,path=%s,server,nowait", qmpID, qmpPath)) + builder.Append("-mon", fmt.Sprintf("chardev=%s,mode=control", qmpID)) + // Set up the virtio channel to get Ignition failures by default journalPipeR, err := builder.VirtioChannelRead("com.coreos.ignition.journal") inst.journalPipe = journalPipeR diff --git a/mantle/platform/qmp_util.go b/mantle/platform/qmp_util.go index 9017bdf3ff..32b4df3cb0 100644 --- a/mantle/platform/qmp_util.go +++ b/mantle/platform/qmp_util.go @@ -53,7 +53,7 @@ func newQMPMonitor(sockaddr string) (*qmp.SocketMonitor, error) { } // Executes a query which provides the list of devices and their names -func ListQMPDevices(sockaddr string) (*qmp.SocketMonitor, *QOMDev, error) { +func listQMPDevices(sockaddr string) (*qmp.SocketMonitor, *QOMDev, error) { monitor, err := newQMPMonitor(sockaddr) if err != nil { return nil, nil, errors.Wrapf(err, "Could not open monitor") @@ -74,7 +74,7 @@ func ListQMPDevices(sockaddr string) (*qmp.SocketMonitor, *QOMDev, error) { } // Set the bootindex for the particular device -func SetBootIndexForDevice(monitor *qmp.SocketMonitor, device string, bootindex int) error { +func setBootIndexForDevice(monitor *qmp.SocketMonitor, device string, bootindex int) error { cmd := fmt.Sprintf(`{ "execute":"qom-set", "arguments": { "path":"%s", "property":"bootindex", "value":%d } }`, device, bootindex) if _, err := monitor.Run([]byte(cmd)); err != nil { return errors.Wrapf(err, "Running QMP command")