cmd/runqemubuildlet: add darwin support
This is used to replace env/darwin/aws/start-snapshot.sh on CI
instances.
Run like so:
Buildlet 1:
$ ./runqemubuildlet -guest-os=darwin -macos-version=12 -osk=<OSK VAL> -guest-index=1 -buildlet-healthz-url="http://192.168.64.101:8080/healthz"
Buildlet 2:
$ ./runqemubuildlet -guest-os=darwin -macos-version=12 -osk=<OSK VAL> -guest-index=2 -buildlet-healthz-url="http://192.168.64.102:8080/healthz"
For golang/go#48945.
Change-Id: Ic0010bcd0062c7b77d09bf2addb1297e7d116474
Reviewed-on: https://go-review.googlesource.com/c/build/+/449877
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Jenny Rakoczy <jenny@golang.org>
Run-TryBot: Michael Pratt <mpratt@google.com>
diff --git a/cmd/runqemubuildlet/darwin.go b/cmd/runqemubuildlet/darwin.go
new file mode 100644
index 0000000..577d4c8
--- /dev/null
+++ b/cmd/runqemubuildlet/darwin.go
@@ -0,0 +1,91 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.16
+// +build go1.16
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+)
+
+// defaultDarwinDir returns a default path for a darwin VM.
+//
+// The directory should contain the darwin VM image, and QEMU
+// (sysroot-macos-x86_64).
+func defaultDarwinDir() string {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ log.Printf("os.UserHomeDir() = %q, %v", home, err)
+ return ""
+ }
+ return home
+}
+
+// darwinCmd returns a qemu command for running a darwin VM, ready
+// to be started.
+func darwinCmd(base string) *exec.Cmd {
+ if *macosVersion == 0 {
+ log.Fatalf("-macos-version required")
+ }
+ if *osk == "" {
+ log.Fatalf("-osk required")
+ }
+
+ sysroot := filepath.Join(base, "sysroot-macos-x86_64")
+ ovmfCode := filepath.Join(sysroot, "share/qemu/edk2-x86_64-code.fd")
+
+ disk := filepath.Join(base, "macos.qcow2")
+
+ // vmnet-shared requires that we run QEMU as root.
+ //
+ // These arguments should be kept in sync with env/darwin/aws/qemu.sh.
+ args := []string{
+ "env",
+ fmt.Sprintf("DYLD_LIBRARY_PATH=%s", filepath.Join(sysroot, "lib")),
+ filepath.Join(sysroot, "bin/qemu-system-x86_64"),
+ // Discard disk changes on exit.
+ "-snapshot",
+ "-m", "4096",
+ "-cpu", "host",
+ "-machine", "q35",
+ "-usb",
+ "-device", "usb-kbd",
+ "-device", "usb-tablet",
+ // macOS only likes a power-of-two number of cores, but odd socket count is
+ // fine.
+ "-smp", "cpus=6,sockets=3,cores=2,threads=1",
+ "-device", "usb-ehci,id=ehci",
+ "-device", "nec-usb-xhci,id=xhci",
+ "-global", "nec-usb-xhci.msi=off",
+ "-device", fmt.Sprintf("isa-applesmc,osk=%s", *osk),
+ "-drive", fmt.Sprintf("if=pflash,format=raw,readonly=on,file=%s", ovmfCode),
+ "-smbios", "type=2",
+ "-device", "ich9-intel-hda",
+ "-device", "hda-duplex",
+ "-device", "ich9-ahci,id=sata",
+ "-drive", fmt.Sprintf("id=MacHDD,if=none,format=qcow2,file=%s", disk),
+ "-device", "ide-hd,bus=sata.2,drive=MacHDD",
+ "-monitor", "stdio",
+ "-device", "VGA,vgamem_mb=128",
+ "-M", "accel=hvf",
+ "-display", fmt.Sprintf("vnc=127.0.0.1:%d", *guestIndex),
+ // DHCP range is a dummy range. The actual guest IP is assigned statically
+ // based on the MAC address matching an entry in /etc/bootptab.
+ "-netdev", "vmnet-shared,id=net0,start-address=192.168.64.1,end-address=192.168.64.100,subnet-mask=255.255.255.0",
+ }
+ if *macosVersion >= 11 {
+ args = append(args, "-device", fmt.Sprintf("virtio-net-pci,netdev=net0,id=net0,mac=52:54:00:c9:18:0%d", *guestIndex))
+ } else {
+ args = append(args, "-device", fmt.Sprintf("vmxnet3,netdev=net0,id=net0,mac=52:54:00:c9:18:0%d", *guestIndex))
+ }
+
+ cmd := exec.Command("sudo", args...)
+ return cmd
+}
diff --git a/cmd/runqemubuildlet/main.go b/cmd/runqemubuildlet/main.go
index e7baeff..e001c47 100644
--- a/cmd/runqemubuildlet/main.go
+++ b/cmd/runqemubuildlet/main.go
@@ -23,11 +23,19 @@
var (
// Common flags
- guestOS = flag.String("guest-os", "windows", "Guest OS to run (one of: windows)")
+ guestOS = flag.String("guest-os", "windows", "Guest OS to run (one of: windows or darwin)")
healthzURL = flag.String("buildlet-healthz-url", "http://localhost:8080/healthz", "URL to buildlet /healthz endpoint.")
// -guest-os=windows flags
windows10Path = flag.String("windows-10-path", defaultWindowsDir(), "Path to Windows image and QEMU dependencies.")
+
+ // -guest-os=darwin flags
+ darwinPath = flag.String("darwin-path", defaultDarwinDir(), "Path to darwin image and QEMU dependencies.")
+ // Using an int for this isn't great, but the only thing we need to do
+ // is check if the version is >= 11.
+ macosVersion = flag.Int("macos-version", 0, "macOS major version of guest image (e.g., 10, 11, 12, or 13)")
+ guestIndex = flag.Int("guest-index", 1, "Index indicating which of the two instances on this host that this is (one of: 1 or 2)")
+ osk = flag.String("osk", "", "Apple OSK key value")
)
func main() {
@@ -39,6 +47,8 @@
for ctx.Err() == nil {
var cmd *exec.Cmd
switch *guestOS {
+ case "darwin":
+ cmd = darwinCmd(*darwinPath)
case "windows":
cmd = windows10Cmd(*windows10Path)
default:
diff --git a/env/darwin/aws/README.md b/env/darwin/aws/README.md
index 0ad5d84..5e7ed05 100644
--- a/env/darwin/aws/README.md
+++ b/env/darwin/aws/README.md
@@ -144,8 +144,8 @@
1. Available as `Sysroot-macos-x86_64` in
https://github.com/utmapp/UTM/actions?query=event%3Arelease builds.
3. Copy `bootptab` to `/etc/bootptab`.
-4. Restart the system DHCP server to pick up the new `bootptab`: `sudo /bin/launchctl unload -w /System/Library/LaunchDaemons/bootps.plist && sudo /bin/launchctl load -w /System/Library/LaunchDaemons/bootps.plist`.
-4. Copy `qemu.sh` and `start-snapshot.sh` to `$HOME`.
+4. Restart the system DHCP server to pick up the new `bootptab`: `sudo /bin/launchctl unload -w /System/Library/LaunchDaemons/bootps.plist; sudo /bin/launchctl load -w /System/Library/LaunchDaemons/bootps.plist`.
+4. Build `golang.org/x/build/cmd/runqemubuildlet` and copy it to `$HOME`.
5. Create `$HOME/loop1.sh`:
```sh
@@ -153,7 +153,7 @@
while true; do
echo "Running QEMU..."
- $HOME/start-snapshot.sh $HOME/macos.qcow2 ${OSK_VALUE?} 1
+ $HOME/runqemubuildlet -guest-os=darwin -macos-version=${MACOS_VERSION?} -osk=${OSK_VALUE?} -guest-index=1 -buildlet-healthz-url="http://192.168.64.101:8080/healthz"
done
```
@@ -164,7 +164,7 @@
while true; do
echo "Running QEMU..."
- $HOME/start-snapshot.sh $HOME/macos.qcow2 ${OSK_VALUE?} 2
+ $HOME/runqemubuildlet -guest-os=darwin -macos-version=${MACOS_VERSION?} -osk=${OSK_VALUE?} -guest-index=2 -buildlet-healthz-url="http://192.168.64.102:8080/healthz"
done
```
diff --git a/env/darwin/aws/qemu.sh b/env/darwin/aws/qemu.sh
index 499fba9..fb1f35a 100755
--- a/env/darwin/aws/qemu.sh
+++ b/env/darwin/aws/qemu.sh
@@ -17,6 +17,7 @@
OVMF_CODE="$HOME/sysroot-macos-x86_64/share/qemu/edk2-x86_64-code.fd"
+# These arguments should be kept in sync with cmd/runqemubuildlet/darwin.go.
args=(
-m 4096
-cpu host