all: remove macstadium integration and monitoring
We no longer use this hosting provider.
Removes builders depending on this host type, including Windows ARM
builders.
Fixes golang/go#57562
Updates golang/go#47019
Change-Id: I1b2d3dfb0540cdf1ebc1ce2cfabbcd7d56c30145
Reviewed-on: https://go-review.googlesource.com/c/build/+/460295
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Jenny Rakoczy <jenny@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/cmd/buildlet/buildlet.go b/cmd/buildlet/buildlet.go
index 3418085..961aa3a 100644
--- a/cmd/buildlet/buildlet.go
+++ b/cmd/buildlet/buildlet.go
@@ -34,7 +34,6 @@
"os/exec"
"path"
"path/filepath"
- "regexp"
"runtime"
"strconv"
"strings"
@@ -126,9 +125,6 @@
func main() {
builderEnv := os.Getenv("GO_BUILDER_ENV")
- if builderEnv == "macstadium_vm" {
- configureMacStadium()
- }
onGCE := metadata.OnGCE()
switch runtime.GOOS {
case "plan9":
@@ -1737,103 +1733,6 @@
return p.Kill()
}
-// configureMacStadium configures the buildlet flags for use on a Mac
-// VM running on MacStadium under VMWare.
-func configureMacStadium() {
- *haltEntireOS = true
-
- // TODO: setup RAM disk for tmp and set *workDir
-
- disableMacScreensaver()
- enableMacDeveloperMode()
-
- version, err := exec.Command("sw_vers", "-productVersion").Output()
- if err != nil {
- log.Fatalf("failed to find sw_vers -productVersion: %v", err)
- }
- majorMinor := regexp.MustCompile(`^(\d+)\.(\d+)`)
- m := majorMinor.FindStringSubmatch(string(version))
- if m == nil {
- log.Fatalf("unsupported sw_vers version %q", version)
- }
- major, minor := m[1], m[2] // "10", "12"
-
- // As of macOS 11 (Big Sur), the major digits are used to indicate the version of
- // macOS. This version also introduced support for multiple architectures. This
- // takes into account the need to distinguish between versions and architectures for
- // the later versions.
- mj, err := strconv.Atoi(major)
- if err != nil {
- log.Fatalf("unable to parse major version %q", major)
- }
- if mj >= 13 {
- *reverseType = fmt.Sprintf("host-darwin-%s-%s", runtime.GOARCH, major)
- } else if mj >= 11 {
- // The darwin-amd64-{11,12}_0 hosts have a "_0" suffix as a historical
- // relic from when it distinguished macOS 10.15, 10.14 and older, as below.
- *reverseType = fmt.Sprintf("host-darwin-%s-%s_0", runtime.GOARCH, major)
- } else {
- *reverseType = fmt.Sprintf("host-darwin-%s-%s_%s", runtime.GOARCH, major, minor)
- }
- *coordinator = "farmer.golang.org:443"
-
- // guestName is set by cmd/makemac to something like
- // "mac_10_10_host01b" or "mac_10_12_host01a", which encodes
- // three things: the mac OS version of the guest VM, which
- // physical machine it's on (1 to 10, currently) and which of
- // two possible VMs on that host is running (a or b). For
- // monitoring purposes, we want stable hostnames and don't
- // care which OS version is currently running (which changes
- // constantly), so normalize these to only have the host
- // number and side (a or b), without the OS version. The
- // buildlet will report the OS version to the coordinator
- // anyway. We could in theory do this normalization in the
- // coordinator, but we don't want to put buildlet-specific
- // knowledge there, and this file already contains a bunch of
- // buildlet host-specific configuration, so normalize it here.
- guestName := vmwareGetInfo("guestinfo.name") // "mac_10_12_host01a"
- hostPos := strings.Index(guestName, "_host")
- if hostPos == -1 {
- // Assume cmd/makemac changed its conventions.
- // Maybe all this normalization belongs there anyway,
- // but normalizing here is a safer first step.
- *hostname = guestName
- } else {
- *hostname = "macstadium" + guestName[hostPos:] // "macstadium_host01a"
- }
-}
-
-func disableMacScreensaver() {
- err := exec.Command("defaults", "-currentHost", "write", "com.apple.screensaver", "idleTime", "0").Run()
- if err != nil {
- log.Printf("disabling screensaver: %v", err)
- }
-}
-
-// enableMacDeveloperMode enables developer mode on macOS for the
-// runtime tests. (Issue 31123)
-//
-// It is best effort; errors are logged but otherwise ignored.
-func enableMacDeveloperMode() {
- // Macs are configured with password-less sudo. Without sudo we get prompts
- // that "SampleTools wants to make changes" that block the buildlet from starting.
- // But oddly, not via gomote. Only during startup. The environment must be different
- // enough that in one case macOS asks for permission (because it can use the GUI?)
- // and in the gomote case (where the environment is largely scrubbed) it can't do
- // the GUI dialog somehow and must just try to do it anyway and finds that passwordless
- // sudo works. But using sudo seems to make it always work.
- // For extra paranoia, use a context to not block start-up.
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
-
- out, err := exec.CommandContext(ctx, "/usr/bin/sudo", "/usr/sbin/DevToolsSecurity", "-enable").CombinedOutput()
- if err != nil {
- log.Printf("Error enabling developer mode: %v, %s", err, out)
- return
- }
- log.Printf("DevToolsSecurity: %s", out)
-}
-
func vmwareGetInfo(key string) string {
cmd := exec.Command("/Library/Application Support/VMware Tools/vmware-tools-daemon",
"--cmd",
diff --git a/cmd/buildlet/reverse.go b/cmd/buildlet/reverse.go
index 920a5f9..2b56a10 100644
--- a/cmd/buildlet/reverse.go
+++ b/cmd/buildlet/reverse.go
@@ -33,14 +33,6 @@
if isDevReverseMode() {
return devBuilderKey(mode), nil
}
- if os.Getenv("GO_BUILDER_ENV") == "macstadium_vm" {
- infoKey := "guestinfo.key-" + mode
- key := vmwareGetInfo(infoKey)
- if key == "" {
- return "", fmt.Errorf("no build key found for VMWare info-get key %q", infoKey)
- }
- return key, nil
- }
keyPath := filepath.Join(homedir(), ".gobuildkey-"+mode)
if v := os.Getenv("GO_BUILD_KEY_PATH"); v != "" {
keyPath = v
diff --git a/cmd/buildlet/stage0/Makefile b/cmd/buildlet/stage0/Makefile
index a72924a..6185078 100644
--- a/cmd/buildlet/stage0/Makefile
+++ b/cmd/buildlet/stage0/Makefile
@@ -4,9 +4,6 @@
# The only reason we upload them to GCS is because that's where the
# automated VM/container creation scripts download them from.
#
-# The notable exception is our Mac VMs on MacStadium. In those cases,
-# the images actually do download the stage0 binary on start-up.
-#
GO=go1.19
diff --git a/cmd/buildlet/stage0/stage0.go b/cmd/buildlet/stage0/stage0.go
index 1f3e2db..fa72fbe 100644
--- a/cmd/buildlet/stage0/stage0.go
+++ b/cmd/buildlet/stage0/stage0.go
@@ -26,7 +26,6 @@
"os/exec"
"path/filepath"
"runtime"
- "strings"
"time"
"cloud.google.com/go/compute/metadata"
@@ -75,7 +74,6 @@
}
log.Printf("bootstrap binary running")
- var isMacStadiumVM bool
switch osArch {
case "linux/arm":
if onGCE {
@@ -97,15 +95,6 @@
default:
panic(fmt.Sprintf("unknown/unspecified $GO_BUILDER_ENV value %q", env))
}
- case "darwin/amd64":
- // The MacStadium builders' baked-in stage0.sh
- // bootstrap file doesn't set GO_BUILDER_ENV
- // unfortunately, so use the filename it runs its
- // downloaded bootstrap URL to determine whether we're
- // in that environment.
- isMacStadiumVM = len(os.Args) > 0 && strings.HasSuffix(os.Args[0], "run-builder")
- log.Printf("isMacStadiumVM = %v", isMacStadiumVM)
- os.Setenv("GO_BUILDER_ENV", "macstadium_vm")
}
if !awaitNetwork() {
@@ -115,7 +104,6 @@
netDelay := prettyDuration(timeNetwork.Sub(timeStart))
log.Printf("network up after %v", netDelay)
-Download:
// Note: we name it ".exe" for Windows, but the name also
// works fine on Linux, etc.
target := filepath.FromSlash("./buildlet.exe")
@@ -202,15 +190,6 @@
case "solaris/amd64", "illumos/amd64":
hostType := buildEnv
cmd.Args = append(cmd.Args, reverseHostTypeArgs(hostType)...)
- case "windows/arm64":
- switch buildEnv {
- case "host-windows-arm64-mini", "host-windows11-arm64-mini":
- cmd.Args = append(cmd.Args,
- "--halt=true",
- "--reverse-type="+buildEnv,
- "--coordinator=farmer.golang.org:443",
- )
- }
}
// Release the serial port (if we opened it) so the buildlet
// process can open & write to it. At least on Windows, only
@@ -219,24 +198,6 @@
closeSerialLogOutput()
}
err := cmd.Run()
- if isMacStadiumVM {
- if err != nil {
- log.Printf("error running buildlet: %v", err)
- log.Printf("restarting in 2 seconds.")
- time.Sleep(2 * time.Second) // in case we're spinning, slow it down
- } else {
- log.Printf("buildlet process exited; restarting.")
- }
- // Some of the MacStadium VM environments reuse their
- // environment. Re-download the buildlet (if it
- // changed-- httpdl does conditional downloading) and
- // then re-run. At least on Sierra we never get this
- // far because the buildlet will halt the machine
- // before we get here. (and then cmd/makemac will
- // recreate the VM)
- // But if we get here, restart the process.
- goto Download
- }
if err != nil {
if configureSerialLogOutput != nil {
configureSerialLogOutput()
diff --git a/cmd/coordinator/coordinator.go b/cmd/coordinator/coordinator.go
index df95301..c068686 100644
--- a/cmd/coordinator/coordinator.go
+++ b/cmd/coordinator/coordinator.go
@@ -360,7 +360,6 @@
mux.HandleFunc("/style.css", handleStyleCSS)
mux.HandleFunc("/try", serveTryStatus(false))
mux.HandleFunc("/try.json", serveTryStatus(true))
- mux.HandleFunc("/status/reverse.json", pool.ReversePool().ServeReverseStatusJSON)
mux.HandleFunc("/status/post-submit-active.json", handlePostSubmitActiveJSON)
mux.Handle("/dashboard", dashV2)
mux.HandleFunc("/queues", handleQueues)
diff --git a/cmd/coordinator/coordinator_test.go b/cmd/coordinator/coordinator_test.go
index cdec51d..edb439d 100644
--- a/cmd/coordinator/coordinator_test.go
+++ b/cmd/coordinator/coordinator_test.go
@@ -250,36 +250,36 @@
// First, determine builds without try messages. Our target SlowBot shouldn't be included.
ts := newTrySet(work)
- hasWindowsARM64Builder := false
+ hasLinuxArmBuilder := false
for _, bs := range ts.builds {
v := bs.NameAndBranch()
- if v == "windows-arm64-10" {
- hasWindowsARM64Builder = true
+ if v == "linux-arm" {
+ hasLinuxArmBuilder = true
}
}
- if hasWindowsARM64Builder {
- // This test relies on windows-arm64-10 builder not being a default
+ if hasLinuxArmBuilder {
+ // This test relies on linux-arm builder not being a default
// TryBot to provide coverage for issue 42084. If the build policy
// changes, need to pick another builder to use in this test.
- t.Fatal("windows-arm64-10 builder was included even without TRY= message")
+ t.Fatal("linux-arm builder was included even without TRY= message")
}
// Next, add try messages, and check that the SlowBot is now included.
work.TryMessage = []*apipb.TryVoteMessage{
- {Message: "TRY=windows-amd64", AuthorId: 1234, Version: 1},
- {Message: "TRY=windows-arm64-10", AuthorId: 1234, Version: 1},
+ {Message: "TRY=linux", AuthorId: 1234, Version: 1},
+ {Message: "TRY=linux-arm", AuthorId: 1234, Version: 1},
}
ts = newTrySet(work)
- hasWindowsARM64Builder = false
+ hasLinuxArmBuilder = false
for i, bs := range ts.builds {
v := bs.NameAndBranch()
t.Logf("build[%d]: %s", i, v)
- if v == "windows-arm64-10" {
- hasWindowsARM64Builder = true
+ if v == "linux-arm-aws" {
+ hasLinuxArmBuilder = true
}
}
- if !hasWindowsARM64Builder {
- t.Error("windows-arm64-10 SlowBot was not included")
+ if !hasLinuxArmBuilder {
+ t.Error("linux-arm SlowBot was not included")
}
}
diff --git a/cmd/coordinator/status.go b/cmd/coordinator/status.go
index 5f87d1b..f52a09a 100644
--- a/cmd/coordinator/status.go
+++ b/cmd/coordinator/status.go
@@ -13,7 +13,6 @@
"bytes"
"context"
_ "embed"
- "encoding/json"
"errors"
"fmt"
"html"
@@ -147,7 +146,6 @@
var basePinErr atomic.Value
func addHealthCheckers(ctx context.Context, mux *http.ServeMux, sc *secret.Client) {
- addHealthChecker(mux, newMacHealthChecker())
addHealthChecker(mux, newMacOSARM64Checker())
addHealthChecker(mux, newOSUPPC64leChecker())
addHealthChecker(mux, newOSUPPC64lePower9Checker())
@@ -292,81 +290,6 @@
}
}
-func newMacHealthChecker() *healthChecker {
- var hosts []string
- const numMacHosts = 8 // physical Mac Pros, not reverse buildlet connections. M1 Macs will be included in separate checks.
- for i := 1; i <= numMacHosts; i++ {
- for _, suf := range []string{"a", "b"} {
- name := fmt.Sprintf("macstadium_host%02d%s", i, suf)
- hosts = append(hosts, name)
- }
- }
- checkHosts := reverseHostChecker(hosts)
-
- // And check that the makemac daemon is listening.
- var makeMac struct {
- sync.Mutex
- lastCheck time.Time // currently unused
- lastErrors []string
- lastWarns []string
- }
- setMakeMacStatus := func(errs, warns []string) {
- makeMac.Lock()
- defer makeMac.Unlock()
- makeMac.lastCheck = time.Now()
- makeMac.lastErrors = errs
- makeMac.lastWarns = warns
- }
- go func() {
- for {
- errs, warns := fetchMakeMacStatus()
- setMakeMacStatus(errs, warns)
- time.Sleep(15 * time.Second)
- }
- }()
- return &healthChecker{
- ID: "macs",
- Title: "MacStadium Mac VMs",
- DocURL: "https://github.com/golang/build/tree/master/env/darwin/macstadium",
- Check: func(w *checkWriter) {
- // Check hosts.
- checkHosts(w)
- // Check makemac daemon.
- makeMac.Lock()
- defer makeMac.Unlock()
- for _, v := range makeMac.lastWarns {
- w.warnf("makemac daemon: %v", v)
- }
- for _, v := range makeMac.lastErrors {
- w.errorf("makemac daemon: %v", v)
- }
- },
- }
-}
-
-func fetchMakeMacStatus() (errs, warns []string) {
- c := &http.Client{Timeout: 15 * time.Second}
- res, err := c.Get("http://macstadiumd.golang.org:8713")
- if err != nil {
- return []string{fmt.Sprintf("failed to fetch status: %v", err)}, nil
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- return []string{fmt.Sprintf("HTTP status %v", res.Status)}, nil
- }
- if res.Header.Get("Content-Type") != "application/json" {
- return []string{fmt.Sprintf("unexpected content-type %q; want JSON", res.Header.Get("Content-Type"))}, nil
- }
- var resj struct {
- Errors []string
- Warnings []string
- }
- if err := json.NewDecoder(res.Body).Decode(&resj); err != nil {
- return []string{fmt.Sprintf("reading status response body: %v", err)}, nil
- }
- return resj.Errors, resj.Warnings
-}
-
func newMacOSARM64Checker() *healthChecker {
var expect int // Number of expected darwin/arm64 reverse builders based on x/build/dashboard.
for hostType, hc := range dashboard.Hosts {
diff --git a/cmd/coordinator/status_test.go b/cmd/coordinator/status_test.go
index 7374248..ee46e0a 100644
--- a/cmd/coordinator/status_test.go
+++ b/cmd/coordinator/status_test.go
@@ -95,8 +95,6 @@
t.Fatalf("output didn't contain %q: %s", suf, got)
}
for _, sub := range []string{
- `<a href="/status/macs">MacStadium Mac VMs</a> [`,
- `<li>macstadium_host06a not yet connected</li>`,
`<a href="/status/allgood">All Good Test</a>: ok`,
`<li>test-info</li>`,
`<li><span style='color: orange'>test-warn</span></li>`,
diff --git a/cmd/makemac/README.md b/cmd/makemac/README.md
deleted file mode 100644
index 6ab5482..0000000
--- a/cmd/makemac/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-[![Go Reference](https://pkg.go.dev/badge/golang.org/x/build/cmd/makemac.svg)](https://pkg.go.dev/golang.org/x/build/cmd/makemac)
-
-# golang.org/x/build/cmd/makemac
-
-The makemac command manages creating & destroying macOS VMs for the
-builders. See the README in x/build/env/darwin/macstadium for some
-more background.
-
-## Deploying `makemac`
-
-```
-* On Linux,
- $ cd cmd/makemac
- $ CGO_ENABLED=0 go build golang.org/x/build/cmd/makemac
- $ scp -i ~/.ssh/id_ed25519_golang1 ./makemac gopher@macstadiumd.golang.org:makemac.new
- $ ssh -i ~/.ssh/id_ed25519_golang1 gopher@macstadiumd.golang.org
-
-On that host,
- $ cp makemac makemac.old
- $ install makemac.new makemac
- $ sudo systemctl restart makemac
- $ sudo journalctl -f -u makemac # watch it
-```
-
-## Updating `makemac.service`
-
-```
-* On Linux,
- $ scp -i ~/.ssh/id_ed25519_golang1 cmd/makemac/makemac.service gopher@macstadiumd.golang.org:makemac.service
-
-On that host,
- $ sudo mv makemac.service /etc/systemd/system/makemac.service
- $ sudo systemctl daemon-reload
- $ sudo systemctl restart makemac
- $ sudo journalctl -f -u makemac # watch it
-```
-
-## Checking that it's running:
-
-```
-$ curl -v http://macstadiumd.golang.org:8713
-```
-
-(Note that URL won't work in a browser due to HSTS requirements on
- *.golang.org)
diff --git a/cmd/makemac/makemac.go b/cmd/makemac/makemac.go
deleted file mode 100644
index 1d040e7..0000000
--- a/cmd/makemac/makemac.go
+++ /dev/null
@@ -1,984 +0,0 @@
-// Copyright 2016 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.
-
-/*
-The makemac command starts OS X VMs for the builders.
-It is currently just a thin wrapper around govc.
-
-See https://github.com/vmware/govmomi/tree/master/govc
-
-Usage:
-
- $ makemac <macos_version> # e.g, darwin-amd64-10_10, darwin-amd64-10_11, darwin-amd64-10_15, darwin-amd64-11_0
-*/
-package main
-
-import (
- "bufio"
- "context"
- "encoding/json"
- "errors"
- "flag"
- "fmt"
- "io/ioutil"
- "log"
- "net/http"
- "os"
- "os/exec"
- "path"
- "path/filepath"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "golang.org/x/build/types"
-)
-
-func usage() {
- fmt.Fprintf(os.Stderr, `Usage:
- makemac <macos_version> e.g, darwin-amd64-10_10, darwin-amd64-11_0
- makemac -status
- makemac -auto
-`)
- os.Exit(1)
-}
-
-var (
- flagStatus = flag.Bool("status", false, "print status only")
- flagAuto = flag.Bool("auto", false, "Automatically create & destroy as needed, reacting to https://farmer.golang.org/status/reverse.json status.")
- flagListen = flag.String("listen", ":8713", "HTTP status port; used by auto mode only")
- flagNuke = flag.Bool("destroy-all", false, "immediately destroy all running Mac VMs")
- flagBaseDisk = flag.String("base-disk", "", "debug mode: if set, print base disk of macOS version selected VM and exit")
- flagDatacenter = flag.String("datacenter", "MacStadium-ATL", "target VMWare datacenter")
- flagCluster = flag.String("cluster", "MacPro_Cluster", "target VMWare cluster")
-)
-
-func main() {
- flag.Parse()
- numArg := flag.NArg()
- ctx := context.Background()
- if *flagBaseDisk != "" {
- fv, err := hostTypeToVersion("host-" + *flagBaseDisk)
- if err != nil {
- log.Fatalf("unable to convert host=%q to VM", *flagBaseDisk)
- }
- baseDisk, err := findBaseDisk(ctx, fv)
- if err != nil {
- log.Fatal(err)
- }
- fmt.Println(baseDisk)
- return
- }
- if *flagStatus {
- numArg++
- }
- if *flagAuto {
- numArg++
- }
- if *flagNuke {
- numArg++
- }
- if numArg != 1 {
- usage()
- }
- if *flagAuto {
- autoLoop()
- return
- }
- if *flagNuke {
- state, err := getState(ctx)
- if err != nil {
- log.Fatal(err)
- }
- if err := state.DestroyAllMacs(ctx); err != nil {
- log.Fatal(err)
- }
- return
- }
- v, err := hostTypeToVersion("host-" + flag.Arg(0))
- if err != nil && !*flagStatus {
- usage()
- }
-
- state, err := getState(ctx)
- if err != nil {
- log.Fatal(err)
- }
-
- if *flagStatus {
- stj, _ := json.MarshalIndent(state, "", " ")
- fmt.Printf("%s\n", stj)
- return
- }
-
- if _, err = state.CreateMac(ctx, v); err != nil {
- log.Fatal(err)
- }
-}
-
-// State is the state of the world.
-type State struct {
- mu sync.Mutex
-
- Hosts map[string]int // IP address -> running Mac VM count (including 0)
- VMHost map[string]string // "mac_10_8_amd64_host02b" => "10.0.0.0"
- HostIP map[string]string // "host-5" -> "10.0.0.0"
- VMInfo map[string]VMInfo // "mac_10_8_amd64_host02b" => ...
-
- // VMOfSlot maps from a "slot name" to the VMWare VM name.
- //
- // A slot name is a tuple of (host number, "a"|"b"), where "a"
- // and "b" are the two possible guests that can run per host.
- // This slot name of the form "macstadium_host02b" is what's
- // reported as the host name to the coordinator.
- //
- // The map value is the VMWare vm name, such as "mac_10_8_amd64_host02b",
- // and is the map key of VMHost and VMInfo above.
- VMOfSlot map[string]string // "macstadium_host02b" => "mac_10_8_amd64_host02b"
-}
-
-type VMInfo struct {
- IP string
- BootTime time.Time
-
- // SlotName is the name of a place where we can run a VM.
- // As of 2017-08-04 we have 20 slots total over 10 physical
- // machines. (Two VMs per physical Mac Mini running ESXi)
- // We use slot names of the form "macstadium_host02b"
- // with a %02d digit host number and suffix 'a' and 'b'
- // for which VM it is on that host.
- //
- // This slot name is also the name passed to the build
- // coordinator as the coordinator's "host name". (which exists
- // both for debugging, and for monitoring last-seen/uptime of
- // dedicated builders.)
- SlotName string
-}
-
-// NumCreatableVMs returns the number of VMs that can be created given
-// the current capacity.
-func (st *State) NumCreatableVMs() int {
- st.mu.Lock()
- defer st.mu.Unlock()
- n := 0
- for _, cur := range st.Hosts {
- if cur < 2 {
- n += 2 - cur
- }
- }
- return n
-}
-
-// NumMacVMsOfVersion reports how many VMs are running the specified macOS version.
-func (st *State) NumMacVMsOfVersion(ver *Version) int {
- st.mu.Lock()
- defer st.mu.Unlock()
-
- prefix := fmt.Sprintf("mac_%d_%d_%s_", ver.Major, ver.Minor, ver.Arch)
- n := 0
- for name := range st.VMInfo {
- if strings.HasPrefix(name, prefix) {
- n++
- }
- }
- return n
-}
-
-// DestroyAllMacs runs "govc vm.destroy" on each running Mac VM.
-func (st *State) DestroyAllMacs(ctx context.Context) error {
- st.mu.Lock()
- defer st.mu.Unlock()
- var ret error
- for name := range st.VMInfo {
- log.Printf("destroying %s ...", name)
- err := govc(ctx, "vm.destroy", name)
- log.Printf("vm.destroy(%q) = %v", name, err)
- if err != nil && ret == nil {
- ret = err
- }
- }
- return ret
-}
-
-// guestType returns the appropriate VMWare guest type for the macOS version requested.
-func guestType(ver *Version) (string, error) {
- switch ver.String() {
- case "amd64_10.8":
- return "darwin12_64Guest", nil
- case "amd64_10.9":
- return "darwin13_64Guest", nil
- case "amd64_10.10":
- return "darwin14_64Guest", nil
- case "amd64_10.11":
- return "darwin15_64Guest", nil
- case "amd64_10.12":
- return "darwin16_64Guest", nil
- case "amd64_10.13":
- // High Sierra. Requires vSphere 6.7.
- // https://www.virtuallyghetto.com/2018/04/new-vsphere-6-7-apis-worth-checking-out.html
- return "darwin17_64Guest", nil
- case "amd64_10.14":
- // Mojave. Requires vSphere 6.7.
- // https://www.virtuallyghetto.com/2018/04/new-vsphere-6-7-apis-worth-checking-out.html
- return "darwin18_64Guest", nil
- case "amd64_10.15":
- // Catalina. Requires vSphere 6.7 update 3.
- // https://docs.macstadium.com/docs/vsphere-67-update-3
- // vSphere 6.7 update 3 does not support the guestid `darwin19_64Guest` (which would be
- // associated with macOS 10.15. It enables the creation of a macOS 10.15 vm via guestid
- // `darwin18_64Guest`.
- // TODO: Add a new GOS definition for darwin19_64 (macOS 10.15) in HWV >= 17
- // https://github.com/vmware/open-vm-tools/commit/6297504ef9e139c68b65afe299136d041d690eeb
- // TODO: investigate updating the guestid when we upgrade vSphere past version 6.7u3.
- return "darwin18_64Guest", nil
- case "amd64_11.0":
- // Big Sur. Requires vSphere 6.7 update 3.
- // https://docs.macstadium.com/docs/macos-version-in-your-vmware-cloud
- return "darwin19_64Guest", nil
- case "amd64_12.0":
- // Determined experimentally to be the latest version by running:
- // $ source govc_env_file
- // $ govc vm.create -g darwin19_64Guest -ds GGLGTM-A-002-STV02 -net Private-1 -on=false heschi-test
- // See also https://github.com/vmware/open-vm-tools/blob/master/open-vm-tools/lib/include/guest_os_tables.h.
- return "darwin19_64Guest", nil
- }
- return "", fmt.Errorf("unsupported makemac OS X version %s", ver.String())
-}
-
-// CreateMac creates a VM running the requested macOS version.
-func (st *State) CreateMac(ctx context.Context, ver *Version) (slotName string, err error) {
- st.mu.Lock()
- defer st.mu.Unlock()
-
- gt, err := guestType(ver)
- if err != nil {
- return "", err
- }
-
- hostType := fmt.Sprintf("host-darwin-%s-%d_%d", ver.Arch, ver.Major, ver.Minor)
- key, err := ioutil.ReadFile(filepath.Join(os.Getenv("HOME"), "keys", hostType))
- if err != nil {
- return "", err
- }
- baseDisk, err := findBaseDisk(ctx, ver)
- if err != nil {
- return "", fmt.Errorf("failed to find osx_%s_%d_%d_frozen_nfs base disk: %v", ver.Arch, ver.Major, ver.Minor, err)
- }
-
- hostNum, hostWhich, err := st.pickHost()
- if err != nil {
- return "", err
- }
- name := fmt.Sprintf("mac_%d_%d_%s_host%02d%s", ver.Major, ver.Minor, ver.Arch, hostNum, hostWhich)
- slotName = fmt.Sprintf("macstadium_host%02d%s", hostNum, hostWhich)
-
- if err := govc(ctx, "vm.create",
- "-m", "4096",
- "-c", "6",
- "-on=false",
- "-net", "Private-1", // 172.17.20.0/24
- "-g", gt,
- "-pool", fmt.Sprintf("%s/Resources", *flagCluster),
- // Put the config on the host's datastore, which
- // forces the VM to run on that host:
- "-ds", fmt.Sprintf("BOOT_%d", hostNum),
- name,
- ); err != nil {
- return "", err
- }
- defer func() {
- if err != nil {
- err := govc(ctx, "vm.destroy", name)
- if err != nil {
- log.Printf("failed to destroy %v: %v", name, err)
- }
- }
- }()
-
- if err := govc(ctx, "vm.change",
- "-e", "smc.present=TRUE",
- "-e", "ich7m.present=TRUE",
- "-e", "firmware=efi",
- "-e", fmt.Sprintf("guestinfo.key-%s=%s", hostType, strings.TrimSpace(string(key))),
- "-e", "guestinfo.name="+name,
- "-vm", name,
- ); err != nil {
- return "", err
- }
-
- if err := govc(ctx, "device.usb.add", "-vm", name); err != nil {
- return "", err
- }
-
- if err := govc(ctx, "vm.disk.attach",
- "-vm", name,
- "-link=true",
- "-persist=false",
- "-ds=GGLGTM-A-002-STV02",
- "-disk", baseDisk,
- ); err != nil {
- return "", err
- }
-
- if err := govc(ctx, "vm.power", "-on", name); err != nil {
- return "", err
- }
- log.Printf("Success.")
- return slotName, nil
-}
-
-// govc runs "govc <args...>" and ignores its output, unless there's an error.
-func govc(ctx context.Context, args ...string) error {
- fmt.Fprintf(os.Stderr, "$ govc %v\n", strings.Join(args, " "))
- out, err := exec.CommandContext(ctx, "govc", args...).CombinedOutput()
- if err != nil {
- if isFileSystemReadOnly() {
- out = append(out, "; filesystem is read-only"...)
- }
- return fmt.Errorf("govc %s ...: %v, %s", args[0], err, out)
- }
- return nil
-}
-
-// esx management network IP range
-const hostIPPrefix = "10.87.58." // with fourth octet starting at 10
-
-var errNoHost = errors.New("no usable host found")
-
-// st.mu must be held.
-func (st *State) pickHost() (hostNum int, hostWhich string, err error) {
- for ip, inUse := range st.Hosts {
- if !strings.HasPrefix(ip, hostIPPrefix) {
- continue
- }
- if inUse >= 2 {
- // Apple policy.
- continue
- }
- hostNum, err = strconv.Atoi(strings.TrimPrefix(ip, hostIPPrefix))
- if err != nil {
- return 0, "", err
- }
- hostNum -= 10 // 10.87.58.11 is "BOOT_1" datastore.
- hostWhich = "a" // unless in use
- if st.whichAInUse(hostNum) {
- hostWhich = "b"
- }
- return
- }
- return 0, "", errNoHost
-}
-
-// whichAInUse reports whether a VM is running on the provided hostNum named
-// with suffix "_host<%02d>a", hostnum.
-//
-// st.mu must be held
-func (st *State) whichAInUse(hostNum int) bool {
- suffix := fmt.Sprintf("_host%02da", hostNum)
- for name := range st.VMHost {
- if strings.HasSuffix(name, suffix) {
- return true
- }
- }
- return false
-}
-
-// vmNameReg is used to validate valid host names. Such as mac_11_12_amd64_host01b.
-var vmNameReg = regexp.MustCompile("^mac_[1-9][0-9]_[0-9][0-9]?_amd64_host[0-9][0-9](a|b)$")
-
-// getStat queries govc to find the current state of the hosts and VMs.
-func getState(ctx context.Context) (*State, error) {
- st := &State{
- VMHost: make(map[string]string),
- Hosts: make(map[string]int),
- HostIP: make(map[string]string),
- VMInfo: make(map[string]VMInfo),
- VMOfSlot: make(map[string]string),
- }
-
- var hosts elementList
- p := fmt.Sprintf("/%s/host/%s", *flagDatacenter, *flagCluster)
- if err := govcJSONDecode(ctx, &hosts, "ls", "-json", p); err != nil {
- return nil, fmt.Errorf("getState: reading %s: %v", p, err)
- }
- for _, h := range hosts.Elements {
- if h.Object.Self.Type == "HostSystem" {
- ip := path.Base(h.Path)
- st.Hosts[ip] = 0
- st.HostIP[h.Object.Self.Value] = ip
- }
- }
-
- var vms elementList
- if err := govcJSONDecode(ctx, &vms, "ls", "-json", fmt.Sprintf("/%s/vm", *flagDatacenter)); err != nil {
- return nil, fmt.Errorf("getState: reading /%s/vm: %v", *flagDatacenter, err)
- }
- for _, h := range vms.Elements {
- if h.Object.Self.Type != "VirtualMachine" {
- continue
- }
- name := path.Base(h.Path)
- hostID := h.Object.Runtime.Host.Value
- hostIP := st.HostIP[hostID]
- st.VMHost[name] = hostIP
- if hostIP != "" && vmNameReg.MatchString(name) {
- st.Hosts[hostIP]++
- var bootTime time.Time
- if bt := h.Object.Summary.Runtime.BootTime; bt != "" {
- bootTime, _ = time.Parse(time.RFC3339, bt)
- }
-
- var slotName string
- if p := strings.Index(name, "_host"); p != -1 {
- slotName = "macstadium" + name[p:] // macstadium_host02a
-
- if exist := st.VMOfSlot[slotName]; exist != "" {
- // Should never happen, but just in case.
- log.Printf("ERROR: existing VM %q found in slot %q; destroying later VM %q", exist, slotName, name)
- err := govc(ctx, "vm.destroy", name)
- log.Printf("vm.destroy(%q) = %v", name, err)
- } else {
- st.VMOfSlot[slotName] = name // macstadium_host02a => mac_10_8_amd64_host02a
- }
- }
-
- vi := VMInfo{
- IP: hostIP,
- BootTime: bootTime,
- SlotName: slotName,
- }
- st.VMInfo[name] = vi
- }
- }
-
- return st, nil
-}
-
-// objRef is a VMWare "Managed Object Reference".
-type objRef struct {
- Type string // e.g. "VirtualMachine"
- Value string // e.g. "host-12"
-}
-
-type elementList struct {
- Elements []*elementJSON `json:"elements"`
-}
-
-type elementJSON struct {
- Path string
- Object struct {
- Self objRef
- Runtime struct {
- Host objRef // for VMs; not present otherwise
- }
- Summary struct {
- Runtime struct {
- BootTime string // time.RFC3339 format, or empty if not running
- }
- }
- }
-}
-
-// govcJSONDecode runs "govc <args...>" and decodes its JSON output into dst.
-func govcJSONDecode(ctx context.Context, dst interface{}, args ...string) error {
- cmd := exec.CommandContext(ctx, "govc", args...)
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- return err
- }
- if err := cmd.Start(); err != nil {
- return err
- }
- err = json.NewDecoder(stdout).Decode(dst)
- if werr := cmd.Wait(); werr != nil && err == nil {
- err = werr
- }
- return err
-}
-
-// findBaseDisk returns the path of the vmdk of the most recent
-// snapshot of the osx_$(arch)_$(major)_$(minor)_frozen_nfs VM.
-func findBaseDisk(ctx context.Context, ver *Version) (string, error) {
- vmName := fmt.Sprintf("osx_%s_%d_%d_frozen_nfs", ver.Arch, ver.Major, ver.Minor)
- out, err := exec.CommandContext(ctx, "govc", "vm.info", "-json", vmName).Output()
- if err != nil {
- return "", err
- }
- var ret struct {
- VirtualMachines []struct {
- Layout struct {
- Snapshot []struct {
- SnapshotFile []string
- }
- }
- }
- }
- if err := json.Unmarshal(out, &ret); err != nil {
- return "", fmt.Errorf("failed to parse vm.info JSON to find base disk: %v", err)
- }
- if n := len(ret.VirtualMachines); n != 1 {
- if n == 0 {
- return "", fmt.Errorf("VM %s not found", vmName)
- }
- return "", fmt.Errorf("len(ret.VirtualMachines) = %d; want 1 in JSON to find base disk: %v", n, err)
- }
- vm := ret.VirtualMachines[0]
- if len(vm.Layout.Snapshot) < 1 {
- return "", fmt.Errorf("VM %s does not have any snapshots; needs at least one", vmName)
- }
- ss := vm.Layout.Snapshot[len(vm.Layout.Snapshot)-1] // most recent snapshot is last in list
-
- // Now find the first vmdk file, without its [datastore] prefix. The files are listed like:
- /*
- "SnapshotFile": [
- "[GGLGLN-A-001-STV1] osx_amd64_10_14_frozen_nfs/osx_amd64_10_14_frozen_nfs-Snapshot2.vmsn",
- "[GGLGLN-A-001-STV1] osx_amd64_10_14_frozen_nfs/osx_amd64_10_14_frozen_nfs_15.vmdk",
- "[GGLGLN-A-001-STV1] osx_amd64_10_14_frozen_nfs/osx_amd64_10_14_frozen_nfs_15-000001.vmdk"
- ]
- */
- for _, f := range ss.SnapshotFile {
- if strings.HasSuffix(f, ".vmdk") {
- i := strings.Index(f, "] ")
- if i == -1 {
- return "", fmt.Errorf("unexpected vmdk line %q in SnapshotFile", f)
- }
- return f[i+2:], nil
- }
- }
- return "", fmt.Errorf("no VMDK found in snapshot for %v", vmName)
-}
-
-const autoAdjustTimeout = 5 * time.Minute
-
-var status struct {
- sync.Mutex
- lastCheck time.Time
- lastLog string
- lastState *State
- warnings []string
- errors []string
-}
-
-func init() {
- http.HandleFunc("/stage0/", handleStage0)
- http.HandleFunc("/buildlet.darwin-amd64", handleBuildlet)
- http.Handle("/", onlyAtRoot{http.HandlerFunc(handleStatus)}) // legacy status location
- http.HandleFunc("/status", handleStatus)
-}
-
-func dedupLogf(format string, args ...interface{}) {
- s := fmt.Sprintf(format, args...)
- status.Lock()
- defer status.Unlock()
- if s == status.lastLog {
- return
- }
- status.lastLog = s
- log.Print(s)
-}
-
-func autoLoop() {
- if addr := *flagListen; addr != "" {
- go func() {
- if err := http.ListenAndServe(*flagListen, nil); err != nil {
- log.Fatalf("ListenAndServe: %v", err)
- }
- }()
- }
- for {
- timer := time.AfterFunc(autoAdjustTimeout, watchdogFail)
- autoAdjust()
- timer.Stop()
- time.Sleep(2 * time.Second)
- }
-}
-
-func watchdogFail() {
- stacks := make([]byte, 1<<20)
- stacks = stacks[:runtime.Stack(stacks, true)]
- log.Fatalf("timeout after %v waiting for autoAdjust(). stacks:\n%s",
- autoAdjustTimeout, stacks)
-}
-
-func autoAdjust() {
- status.Lock()
- status.lastCheck = time.Now()
- status.Unlock()
-
- ctx, cancel := context.WithTimeout(context.Background(), autoAdjustTimeout)
- defer cancel()
-
- ro := isFileSystemReadOnly()
-
- st, err := getState(ctx)
- if err != nil {
- status.Lock()
- if ro {
- status.errors = append(status.errors, "Host filesystem is read-only")
- }
- status.errors = []string{err.Error()}
- status.Unlock()
- log.Print(err)
- return
- }
- var warnings, errors []string
- if ro {
- errors = append(errors, "Host filesystem is read-only")
- }
- defer func() {
- // Set status.lastState once we're now longer using it.
- if st != nil {
- status.Lock()
- status.lastState = st
- status.warnings = warnings
- status.errors = errors
- status.Unlock()
- }
- }()
-
- req, _ := http.NewRequestWithContext(ctx, "GET", "https://farmer.golang.org/status/reverse.json", nil)
- res, err := http.DefaultClient.Do(req)
- if err != nil {
- errors = append(errors, fmt.Sprintf("getting /status/reverse.json from coordinator: %v", err))
- log.Printf("getting reverse status: %v", err)
- return
- }
- defer res.Body.Close()
- var rstat types.ReverseBuilderStatus
- if err := json.NewDecoder(res.Body).Decode(&rstat); err != nil {
- errors = append(errors, fmt.Sprintf("decoding /status/reverse.json from coordinator: %v", err))
- log.Printf("decoding reverse.json: %v", err)
- return
- }
-
- revHost := make(map[string]*types.ReverseBuilder)
- for hostType, hostStatus := range rstat.HostTypes {
- if !hostOnMacStadium(hostType) {
- continue
- }
- for name, revBuild := range hostStatus.Machines {
- revHost[name] = revBuild
- }
- }
-
- // Destroy running VMs that appear to be dead and not connected to the coordinator.
- // TODO: do these all concurrently.
- dirty := false
- for name, vi := range st.VMInfo {
- if vi.BootTime.After(time.Now().Add(-3 * time.Minute)) {
- // Recently created. It takes about a minute
- // to boot and connect to the coordinator, so
- // give it 3 minutes of grace before killing
- // it.
- continue
- }
- rh := revHost[name]
- if rh == nil {
- // Look it up by its slot name instead.
- rh = revHost[vi.SlotName]
- }
- if rh == nil {
- log.Printf("Destroying VM %q unknown to coordinator...", name)
- err := govc(ctx, "vm.destroy", name)
- log.Printf("vm.destroy(%q) = %v", name, err)
- dirty = true
- if err != nil {
- warnings = append(warnings, fmt.Sprintf("vm.destroy(%q) = %v", name, err))
- }
- }
- }
- for {
- if dirty {
- st, err = getState(ctx)
- if err != nil {
- errors = append(errors, err.Error())
- log.Print(err)
- return
- }
- }
- canCreate := st.NumCreatableVMs()
- if canCreate <= 0 {
- dedupLogf("All Mac VMs running.")
- return
- }
- ver := wantedMacVersionNext(st, &rstat)
- if ver == nil {
- dedupLogf("Have capacity for %d more Mac VMs, but none requested by coordinator.", canCreate)
- return
- }
- dedupLogf("Have capacity for %d more Mac VMs; creating requested %d.%d_%s...", canCreate, ver.Major, ver.Minor, ver.Arch)
- slotName, err := st.CreateMac(ctx, ver)
- if err != nil {
- errStr := fmt.Sprintf("Error creating %d.%d_%s: %v", ver.Major, ver.Minor, ver.Arch, err)
- errors = append(errors, errStr)
- log.Print(errStr)
- return
- }
- log.Printf("Created %d.%d_%s VM on %q", ver.Major, ver.Minor, ver.Arch, slotName)
- dirty = true
- }
-}
-
-// Version represents a macOS version.
-// For example, Major=11 Minor=2 Arch=arm64 represents macOS 11.2 arm64.
-type Version struct {
- Major int // 10, 11, ...
- Minor int // 0, 1, 2, ...
- Arch string // amd64, arm64
-}
-
-func (v Version) String() string {
- return fmt.Sprintf("%s_%d.%d", v.Arch, v.Major, v.Minor)
-}
-
-// hostTypeToVersion determines the version of macOS from the host type.
-// Sample host types would be: host-darwin-amd64-10_15 and host-darwin-arm64-11_0.
-func hostTypeToVersion(hostType string) (*Version, error) {
- v := &Version{}
- var err error
- if !strings.HasPrefix(hostType, "host-darwin-") {
- return nil, errors.New("unrecognized version")
- }
- htv := strings.TrimPrefix(hostType, "host-darwin-")
- var majorMinor string
- switch vs := strings.Split(htv, "-"); len(vs) {
- case 2:
- if vs[0] != "amd64" && vs[0] != "arm64" {
- return nil, errors.New("unrecognized version")
- }
- v.Arch = vs[0]
- majorMinor = vs[1]
- default:
- return nil, errors.New("unrecognized version")
- }
- switch mms := strings.Split(majorMinor, "_"); len(mms) {
- case 1:
- v.Major, err = strconv.Atoi(mms[0])
- if err != nil {
- return nil, err
- }
- case 2:
- v.Major, err = strconv.Atoi(mms[0])
- if err != nil {
- return nil, err
- }
- v.Minor, err = strconv.Atoi(mms[1])
- if err != nil {
- return nil, err
- }
- default:
- return nil, errors.New("unrecognized version")
- }
- return v, nil
-}
-
-// wantedMacVersionNext returns the macOS version to create next,
-// or nil to not make anything. It gets the latest reverse buildlet
-// status from the coordinator.
-func wantedMacVersionNext(st *State, rstat *types.ReverseBuilderStatus) *Version {
- // TODO(go.dev/issue/35698): improve this logic now that
- // the coordinator has a proper scheduler. Instead, don't
- // create anything proactively until there's demand from it
- // from the scheduler. (will need to add that to the coordinator's
- // status JSON) And maybe add a streaming endpoint to the
- // coordinator so we don't need to poll every N seconds. Or
- // just poll every few seconds, perhaps at a lighter endpoint
- // that only does darwin.
- //
- // For now just use the static configuration in
- // dashboard/builders.go of how many are expected, which ends
- // up in ReverseBuilderStatus.
- for hostType, hostStatus := range rstat.HostTypes {
- if !hostOnMacStadium(hostType) {
- continue
- }
- ver, err := hostTypeToVersion(hostType)
- if err != nil {
- log.Printf("ERROR: unexpected host type %q", hostType)
- continue
- }
- want := hostStatus.Expect - st.NumMacVMsOfVersion(ver)
- if want > 0 {
- return ver
- }
- }
- return nil
-}
-
-func handleStatus(w http.ResponseWriter, r *http.Request) {
- status.Lock()
- defer status.Unlock()
- w.Header().Set("Content-Type", "application/json")
-
- // Locking the lastState shouldn't matter since we
- // currently only set status.lastState once the
- // *Status is no longer in use, but lock it anyway, in
- // case usage changes in the future.
- if st := status.lastState; st != nil {
- st.mu.Lock()
- defer st.mu.Unlock()
- }
-
- // TODO: probably more status, as needed.
- res := &struct {
- LastCheck string
- LastLog string
- LastState *State
- Warnings []string
- Errors []string
- }{
- LastCheck: status.lastCheck.UTC().Format(time.RFC3339),
- LastLog: status.lastLog,
- LastState: status.lastState,
- Warnings: status.warnings,
- Errors: status.errors,
- }
- j, _ := json.MarshalIndent(res, "", "\t")
- w.Write(j)
-}
-
-// handleStage0 serves the shell script for buildlets to run on boot, based
-// on their macOS version.
-//
-// Starting with the macOS 10.14 (Mojave) image, their baked-in stage0.sh
-// script does:
-//
-// while true; do (curl http://172.17.20.2:8713/stage0/$(sw_vers -productVersion)| sh); sleep 5; done
-func handleStage0(w http.ResponseWriter, r *http.Request) {
- // ver will be like "10.14.4"
- ver := strings.TrimPrefix(r.RequestURI, "/stage0/")
- vs := strings.Split(ver, ".")
- major, err := strconv.Atoi(vs[0])
- if err != nil {
- log.Printf("handleStage0 error converting version=%q; %s", ver, err)
- major = 10
- }
-
- fmt.Fprintf(w, "set -e\nset -x\n")
- fmt.Fprintf(w, "export GO_BUILDER_ENV=macstadium_vm\n")
- fmt.Fprintf(w, "curl -o buildlet http://172.17.20.2:8713/buildlet.darwin-amd64\n")
-
- // Starting with macOS 11.0, the work directory path generated by the buildlet is
- // longer than permitted by certain net package tests. This is a workaround until
- // a cleaner solution is implemeted.
- if major >= 11 {
- fmt.Fprint(w, "rm -rf /Users/gopher/workdir\n")
- fmt.Fprint(w, "mkdir -p /Users/gopher/workdir\n")
- fmt.Fprintf(w, "chmod +x buildlet; ./buildlet -workdir /Users/gopher/workdir")
- } else {
- fmt.Fprintf(w, "chmod +x buildlet; ./buildlet")
- }
-}
-
-func handleBuildlet(w http.ResponseWriter, r *http.Request) {
- bin, err := getLatestMacBuildlet(r.Context())
- if err != nil {
- log.Printf("error getting buildlet from GCS: %v", err)
- http.Error(w, "error getting buildlet from GCS", 500)
- }
- w.Header().Set("Content-Length", fmt.Sprint(len(bin)))
- w.Write(bin)
-}
-
-// buildlet binary caching by its last seen ETag from HEAD responses
-var (
- buildletMu sync.Mutex
- lastEtag string
- lastBuildlet []byte // last buildlet binary for lastEtag
-)
-
-func getLatestMacBuildlet(ctx context.Context) (bin []byte, err error) {
- req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://storage.googleapis.com/go-builder-data/buildlet.darwin-amd64", nil)
- res, err := http.DefaultClient.Do(req)
- if err != nil {
- return nil, err
- }
- if res.StatusCode != 200 {
- return nil, fmt.Errorf("%s from HEAD to %s", res.Status, req.URL)
- }
- etag := res.Header.Get("Etag")
- if etag == "" {
- return nil, fmt.Errorf("HEAD of %s lacked ETag", req.URL)
- }
-
- buildletMu.Lock()
- if etag == lastEtag {
- bin = lastBuildlet
- log.Printf("served cached buildlet of %s", etag)
- buildletMu.Unlock()
- return bin, nil
- }
- buildletMu.Unlock()
-
- log.Printf("fetching buildlet from GCS...")
- req, _ = http.NewRequestWithContext(ctx, "GET", "https://storage.googleapis.com/go-builder-data/buildlet.darwin-amd64", nil)
- res, err = http.DefaultClient.Do(req)
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- return nil, fmt.Errorf("%s from GET to %s", res.Status, req.URL)
- }
- etag = res.Header.Get("Etag")
- log.Printf("fetched buildlet from GCS with etag %s", etag)
- if etag == "" {
- return nil, fmt.Errorf("GET of %s lacked ETag", req.URL)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return nil, err
- }
-
- buildletMu.Lock()
- defer buildletMu.Unlock()
- lastEtag = etag
- lastBuildlet = slurp
- return lastBuildlet, nil
-}
-
-// onlyAtRoot is an http.Handler wrapper that enforces that it's
-// called at /, else it serves a 404.
-type onlyAtRoot struct{ h http.Handler }
-
-func (h onlyAtRoot) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if r.URL.Path != "/" {
- http.NotFound(w, r)
- return
- }
- h.h.ServeHTTP(w, r)
-}
-
-func isFileSystemReadOnly() bool {
- f, err := os.Open("/proc/mounts")
- if err != nil {
- return false
- }
- defer f.Close()
- // Look for line:
- // /dev/sda1 / ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
- bs := bufio.NewScanner(f)
- for bs.Scan() {
- f := strings.Fields(bs.Text())
- if len(f) < 4 {
- continue
- }
- mountPoint, state := f[1], f[3]
- if mountPoint == "/" {
- return strings.HasPrefix(state, "ro,")
- }
- }
- return false
-}
-
-// onMacStadiumReg matches host names for hosts that are hosted on MacStadium.
-var onMacStadiumReg = regexp.MustCompile("^host-darwin-amd64-[1-9][0-9]+_[0-9]+$")
-
-// hostOnMacstadium is true if the host type is hosted on the MacStadium cluster.
-func hostOnMacStadium(hostType string) bool {
- return onMacStadiumReg.MatchString(hostType)
-}
diff --git a/cmd/makemac/makemac.service b/cmd/makemac/makemac.service
deleted file mode 100644
index ea009a0..0000000
--- a/cmd/makemac/makemac.service
+++ /dev/null
@@ -1,16 +0,0 @@
-[Unit]
-Description=Go Builders - makemac
-Documentation=https://github.com/golang/build/blob/master/cmd/makemac/makemac.go
-After=network.target
-
-[Service]
-User=gopher
-Environment="PATH=/home/gopher/bin:/usr/local/bin:/usr/bin"
-# The following file declares these variables: GOVC_URL GOVC_USERNAME GOVC_PASSWORD GOVC_INSECURE
-EnvironmentFile=/home/gopher/govc_env_file
-ExecStart=/home/gopher/makemac -auto
-Restart=always
-RestartSec=3
-
-[Install]
-WantedBy=multi-user.target
diff --git a/cmd/makemac/makemac_test.go b/cmd/makemac/makemac_test.go
deleted file mode 100644
index b1ee314..0000000
--- a/cmd/makemac/makemac_test.go
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2021 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.
-
-package main
-
-import (
- "testing"
-
- "github.com/google/go-cmp/cmp"
-)
-
-func TestHostTypeToVersion(t *testing.T) {
- testCases := []struct {
- desc string
- hostType string
- wantVersion *Version
- }{
- {
- desc: "valid original darwin host type",
- hostType: "host-darwin-amd64-10_14",
- wantVersion: &Version{
- Major: 10,
- Minor: 14,
- Arch: "amd64",
- },
- },
- {
- desc: "valid original darwin host type",
- hostType: "host-darwin-amd64-10_15",
- wantVersion: &Version{
- Major: 10,
- Minor: 15,
- Arch: "amd64",
- },
- },
- {
- desc: "valid newer darwin host ARM64",
- hostType: "host-darwin-arm64-11_0",
- wantVersion: &Version{
- Major: 11,
- Minor: 0,
- Arch: "arm64",
- },
- },
- {
- desc: "valid newer darwin host AMD64",
- hostType: "host-darwin-amd64-11_1",
- wantVersion: &Version{
- Major: 11,
- Minor: 1,
- Arch: "amd64",
- },
- },
- {
- desc: "valid newer darwin host AMD64",
- hostType: "host-darwin-amd64-13",
- wantVersion: &Version{
- Major: 13,
- Minor: 0,
- Arch: "amd64",
- },
- },
- }
- for _, tc := range testCases {
- t.Run(tc.desc, func(t *testing.T) {
- got, err := hostTypeToVersion(tc.hostType)
- if err != nil {
- t.Fatalf("hostTypeToVersion(%q) = %v, %s; want no error", tc.hostType, got, err)
- }
- if diff := cmp.Diff(tc.wantVersion, got); diff != "" {
- t.Errorf("hostTypeToVersion(%q) = (-want +got):\n%s", tc.hostType, diff)
- }
- })
- }
-}
-
-func TestHostTypeToVersionError(t *testing.T) {
- testCases := []struct {
- desc string
- hostType string
- wantErr error
- }{
- {
- desc: "empty string",
- hostType: "",
- },
- {
- desc: "invalid newer darwin host ARM64",
- hostType: "host-darwin-amd64-11_1-toothrot",
- },
- }
- for _, tc := range testCases {
- t.Run(tc.desc, func(t *testing.T) {
- if got, gotErr := hostTypeToVersion(tc.hostType); got != nil || gotErr == nil {
- t.Errorf("hostTypeToVersion(%q) = %+v, %s; want nil, error", tc.hostType, got, gotErr)
- }
- })
- }
-}
-
-func TestHostOnMacStadium(t *testing.T) {
- testCases := []struct {
- desc string
- hostType string
- want bool
- }{
- {
- desc: "empty string",
- hostType: "",
- want: false,
- },
- {
- desc: "valid original darwin host",
- hostType: "host-darwin-amd64-10_14",
- want: true,
- },
- {
- desc: "valid newer darwin host",
- hostType: "host-darwin-amd64-11_0",
- want: true,
- },
- {
- desc: "invalid newer darwin host type",
- hostType: "host-darwin-arm64-11_0-toothrot",
- want: false,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.desc, func(t *testing.T) {
- if got := hostOnMacStadium(tc.hostType); got != tc.want {
- t.Errorf("hostOnMacStadium(%q) = %t; want %t", tc.hostType, got, tc.want)
- }
- })
- }
-}
-
-func TestVMNameReg(t *testing.T) {
- testCases := []struct {
- desc string
- vmName string
- want bool
- }{
- {
- desc: "empty string",
- vmName: "",
- want: false,
- },
- {
- desc: "invalid original darwin host",
- vmName: "mac_10_11_host01b",
- want: false,
- },
- {
- desc: "valid newer darwin host",
- vmName: "mac_11_12_amd64_host01b",
- want: true,
- },
- {
- desc: "valid newer darwin host",
- vmName: "mac_11_20_amd64_host05a",
- want: true,
- },
- {
- desc: "invalid newer darwin host type",
- vmName: "host-darwin-arm64-11_0-toothrot",
- want: false,
- },
- {
- desc: "invalid bastion host",
- vmName: "dns_server",
- want: false,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.desc, func(t *testing.T) {
- if got := vmNameReg.MatchString(tc.vmName); got != tc.want {
- t.Errorf("vmNameReg.MatchString(%q) = %t; want %t", tc.vmName, got, tc.want)
- }
- })
- }
-}
diff --git a/dashboard/builders.go b/dashboard/builders.go
index b2f7322..7ee6548 100644
--- a/dashboard/builders.go
+++ b/dashboard/builders.go
@@ -100,7 +100,9 @@
"windows-386": "windows-386-2008",
"windows-amd64": "windows-amd64-2016",
"windows-arm": "windows-arm-zx2c4",
- "windows-arm64": "windows-arm64-11",
+ // TODO:(golang/go#47019) - uncomment when builder returns and
+ // update test.
+ // "windows-arm64": "windows-arm64-11",
}
// Builders are the different build configurations.
@@ -569,22 +571,11 @@
VMImage: "windows-amd64-server-2016-v7",
SSHUsername: "gopher",
},
- "host-windows-arm64-mini": { // host name known to cmd/buildlet/stage0, cannot change
- Notes: "MacStadium mac minis hosting Windows 10 in qemu with HVM acceleration.",
- IsReverse: true,
- ExpectNum: 2,
- },
"host-windows-arm64-zx2c4": {
IsReverse: true,
ExpectNum: 0,
Owners: []*gophers.Person{gh("zx2c4")},
},
- "host-windows11-arm64-mini": { // host name known to cmd/buildlet/stage0, cannot change
- Notes: "MacStadium mac minis hosting Windows 11 in qemu with HVM acceleration.",
- HostArch: "windows-arm64",
- IsReverse: true,
- ExpectNum: 5,
- },
}
func gh(githubUsername string) *gophers.Person {
@@ -2481,24 +2472,6 @@
"GO_TEST_TIMEOUT_SCALE=3"},
})
addBuilder(BuildConfig{
- Name: "windows-arm64-10",
- HostType: "host-windows-arm64-mini",
- numTryTestHelpers: 1,
- env: []string{
- "GOARCH=arm64",
- },
- })
- addBuilder(BuildConfig{
- Name: "windows-arm64-11",
- HostType: "host-windows11-arm64-mini",
- numTryTestHelpers: 1,
- env: []string{
- "GOARCH=arm64",
- "GOMAXPROCS=4", // OOM problems, see go.dev/issue/51019
- },
- KnownIssues: []int{51019},
- })
- addBuilder(BuildConfig{
Name: "darwin-amd64-10_14",
HostType: "host-darwin-amd64-10_14-aws",
distTestAdjust: macTestPolicy,
diff --git a/dashboard/builders_test.go b/dashboard/builders_test.go
index 49e4554..a18f2b3 100644
--- a/dashboard/builders_test.go
+++ b/dashboard/builders_test.go
@@ -729,7 +729,10 @@
}
ports := strings.Fields(string(out))
- done := map[string]bool{}
+ done := map[string]bool{
+ // TODO:(golang/go#47019) - remove when alias added
+ "windows-arm64": true,
+ }
var add bytes.Buffer
check := func(term string, isArch bool) {
@@ -879,23 +882,6 @@
}
}
-// TestExpectedMacstadiumVMCount ensures that the right number of
-// instances of macOS virtual machines are expected at MacStadium.
-//
-// TODO(go.dev/issue/35698): remove once the scheduler allocates VMs based on demand.
-func TestExpectedMacstadiumVMCount(t *testing.T) {
- t.Skip("MacStadium turndown")
- got := 0
- for host, config := range Hosts {
- if strings.HasPrefix(host, "host-darwin-amd64-") && !strings.HasSuffix(host, "-aws") {
- got += config.ExpectNum
- }
- }
- if got != 16 {
- t.Fatalf("macstadium host count: got %d; want 16", got)
- }
-}
-
// Test that we have longtest builders and
// that their environment configurations are okay.
func TestLongTestBuilder(t *testing.T) {
diff --git a/env/darwin/macstadium/10_11/Makefile b/env/darwin/macstadium/10_11/Makefile
deleted file mode 100644
index f763396..0000000
--- a/env/darwin/macstadium/10_11/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-usage: FORCE
- # See Makefile targets.
- exit 1
-
-FORCE:
-
-upload: FORCE
- go install golang.org/x/build/cmd/upload
- upload --verbose --gzip --file=run-builder-darwin-10_11.sh -cacheable=false -public=true go-builder-data/run-builder-darwin-10_11.gz
diff --git a/env/darwin/macstadium/10_11/stage0.sh b/env/darwin/macstadium/10_11/stage0.sh
deleted file mode 100755
index 0894e8e..0000000
--- a/env/darwin/macstadium/10_11/stage0.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-# Copyright 2022 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.
-
-
-# This is the file baked into the OS X 10.11 VM image. It is ALSO
-# baked into the macOS 10.12 Sierra image. (That is, both 10.11 and
-# 10.12 download and run the run-builder-darwin-10_11.gz URL)
-#
-# It is not used on modern OS X versions.
-#
-# Normally our VMs & containers actually have the cmd/buildlet/stage0
-# binary baked-in, but the Mac VM images are extra painful to
-# configure, so there's an extra level of indirection in their boot
-# process to give us this point of flexibility. This shell script then
-# downloads run-builder-darwin-10_11.gz which is the cmd/buildlet/stage0
-# binary, compressed.
-
-set -e
-url="https://storage.googleapis.com/go-builder-data/run-builder-darwin-10_11.gz"
-while ! curl -f -o run-builder.gz "$url"; do
- echo
- echo "curl failed to fetch $url"
- echo "Sleeping before retrying..."
- sleep 2
-done
-
-set -x
-gunzip -f run-builder.gz
-chmod +x run-builder
-exec ./run-builder
diff --git a/env/darwin/macstadium/README.md b/env/darwin/macstadium/README.md
deleted file mode 100644
index d93055f..0000000
--- a/env/darwin/macstadium/README.md
+++ /dev/null
@@ -1,90 +0,0 @@
-# Overview
-
-Go's Mac builders run at Mac hosting provider,
-[MacStadium](https://macstadium.com). We have a VMware cluster with 8
-physical Mac Pros on which we run two VMs each. There is also a single M1 Mac Mini.
-
-In addition to the Mac VMs and M1 Mac mini, we also run one a Linux VM that's our
-bastion host & runs various services.
-
-## Bastion Host
-
-The bastion host is **macstadiumd.golang.org** and can be accessed
-via:
-
- $ ssh -D :1080 -i ~/keys/id_ed25519_golang1 gopher@macstadiumd.golang.org
-
-(Where `id_ed255519_golang1` is available from go/go-builders-ssh)
-
-It also runs:
-
-* a DHCP server for the 16 Mac VMs to get IP addresses from (systemd
- unit `isc-dhcp-server.service`, so watch with `journalctl -f -u
- isc-dhcp-server.service`)
-
-* the [**makemac** daemon](../../../cmd/makemac/) daemon (systemd
- unit `makemac.service`, so watch with `journalctl -f -u makemac`).
- This monitors the build coordinator (farmer.golang.org) as well as
- the VMware cluster (via the [`govc` CLI
- tool](https://github.com/vmware/govmomi/tree/master/govc)) and makes
- and destroys Mac VMs as needed. It also serves plaintext HTTP status
- at http://macstadiumd.golang.org:8713 which used to be accessible in
- a browser, but recent HSTS configuration on `*.golang.org` means you
- need to use curl now. But that's a good way to see what it's doing
- remotely, without authentication.
-
-* [WireGuard](https://www.wireguard.com/) listening on port 51820,
- because OpenVPN + Mac's built-in VPN client is painful and buggy.
- See config in `/etc/wireguard/wg0.conf`. This doesn't yet come up on
- boot. It's a recent addition.
-
-## OpenVPN
-
-The method of last resort to access the cluster, which works even if
-the bastion host VM is down, is to VPN to our Cisco gateway via go/go-how-to-vpn-into-macstadium.
-
-## VMware web UI
-
-Connect with OpenVPN, WireGuard, or configure your browser to use
-localhost:1080 as a SOCKS proxy. Add:
-
-10.87.58.9 vcenter.gglgtm-a-002.macstadium.com
-
-to your hosts file, then access the UI at https://vcenter.gglgtm-a-002.macstadium.com.
-
-VMware web UI at:
-
- https://10.87.58.9/ui/
-
-## Adding a New Image
-
-When a new version of macOS is released:
-
-* Ensure that the version of vSphere deployed on MacStadium supports the
- new version of macOS. If it doesn't, either request that MacStadium
- upgrade the cluster or seek guidance from them about the upgrade path.
-
-* Clone the latest macOS version on vSphere and upgrade that version
- to the desired macOS version as per the [instructions](vmware-notes.md).
-
-* If a completely new image is required, follow the [images setup notes](../setup-notes.md)
- in order to add a new image.
-
-## Debugging
-
-Common techniques to debug:
-
-* Can you get to the bastion host?
-
-* What does `journalctl -f -u makemac` say? Is it error looping?
-
-* Look at https://10.87.58.9/ui/ and see if VMware is unhappy about
- things. Did hosts die? Did storage disappear?
-
-* Need to hard reboot machines? Eventually we'll fix
- https://github.com/golang/go/issues/32033 but for now you can use
- https://portal.macstadium.com/subscriptions and power cycle
- machines that VMware reports dead (or that you see missing from
- [https://farmer.golang.org](https://farmer.golang.org)'s reverse pool info).
-
-* Worst case, file a ticket: https://portal.macstadium.com/tickets
diff --git a/env/darwin/macstadium/vmware-notes.md b/env/darwin/macstadium/vmware-notes.md
deleted file mode 100644
index 2618549..0000000
--- a/env/darwin/macstadium/vmware-notes.md
+++ /dev/null
@@ -1,36 +0,0 @@
-* Create a new virtual machine stored in GGLGTM*, with the most recent
- supported version of macOS as the guest OS. Configure it with 2 CPUs,
- 4 GB RAM, 60+ GiB of disk, and mount the installer ISO from ISO/OSX.
-* Setup OS X following setup-notes.md.
-* Shut it down.
-* Clone to Virtual Machine (convention: "osx_amd64_11_0_frozen" for macOS
- 11.0")
-* Snapshot that new frozen VM once to make its vmdk in COW format.
-* Clone it again to _frozen_nfs; nobody quite knows why we do this
- but it's the required format for makemac.
-
-Then change makemac to know about the new OS, and add the new reverse builders
-and build to the coordinator.
-
-Other misc notes:
-
-```bash
-$ source govc_env_file
-$ govc vm.info -json mac_11_0_amd64_host07a | jq . | grep MacAdd
- "MacAddress": "00:50:56:b4:05:57",
-```
-
-if sleep failing,
-```bash
-sudo pmset -a hibernatemode 25
-sudo pmset sleepnow
-```
-
-```bash
-pmset -g assertions # RemovableMedia mounted
-system_profiler # to see which
-```
-
-https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1012225
- ... doesn't seem to work
- ... but changing from SATA to IDE does make the RemovableMedia assertion go away (but `pmset sleepnow` stil doesn't work)
diff --git a/env/darwin/setup-notes.md b/env/darwin/setup-notes.md
index 8db0273..8ff3c6b 100644
--- a/env/darwin/setup-notes.md
+++ b/env/darwin/setup-notes.md
@@ -1,18 +1,3 @@
-# For VMWare VMs only #
-
-The Disk should be formatted with a case insensitive file system (default).
-
-Install VMWare tools daemon.
-
- - The UI is supposed to be able to do this automatically, but it's broken as of writing.
- - Instead, mount darwin.iso from ISO/VMWARE TOOLS and run the installer from there.
- - open security preferences and click "Allow" on blocked software install from VMware
- - reboot
- - make sure you can run and see:
-
- $ /Library/Application Support/VMware Tools/vmware-tools-daemon --cmd "info-get guestinfo.name"
- No value found
-
# For all machine types
- Turn on the computer.
@@ -37,12 +22,6 @@
Create `$HOME/stage0.sh`.
-**For VMWare VMs**
-```
-#!/bin/bash
-while true; do (curl -v http://172.17.20.2:8713/stage0/$(sw_vers -productVersion) | sh); sleep 5; done
-```
-
**For physical machines**
```
#!/bin/bash
diff --git a/env/windows-arm64/macstadium/image-setup-notes.txt b/env/windows-arm64/macstadium/image-setup-notes.txt
deleted file mode 100644
index d876fb5..0000000
--- a/env/windows-arm64/macstadium/image-setup-notes.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-The Disk should be formatted with a case insensitive file system (default).
-
-System Preferences > Software Update > off
-
-System Preferences > Desktop & Screensaver > never screensaver
-
-System Preferences > Energy Saver > never sleep
-
-System Preferences > Energy Saver > start up automatically after power failure
-
-System Preferences > Sharing > enable ssh (enable for administrators)
-
-windows image:
-
- gsutil cp gs://go-builder-data/windows-arm64.20210629.tar.xz ./windows-arm64.20210629.tar.xz
- scp windows-arm64.20210629.tar.xz your-macmini-instance:~/
- ssh your-macmini-instance
- # The following will create a directory called macmini-windows with image and qemu binaries inside:
- tar xf windows-arm64-20210629.tar.xz
-
-Automator:
-
- scp env/windows-arm64/macstadium/winloop.sh your-macmini-instance:~/macmini-windows/winloop.sh
- # On buildlet host:
- chmod u+x ~/macmini-windows/winloop.sh
- File > New > Application
- [+] Run shell script
- [ open -a Terminal.app $HOME/macmini-windows/winloop.sh ]
- Save to desktop as "run-builder"
-
-System Preferences > Users & Groups > auto-login "gopher" user, run Desktop/run-builder (automator app)
-
-passwordless sudo:
-
- sudo visudo
- Change line from:
- %admin ALL=(ALL) ALL
- to:
- %admin ALL=(ALL) NOPASSWD: ALL
-
-verbose boot: (text instead of apple image)
-
- sudo nvram boot-args="-v"
diff --git a/env/windows-arm64/macstadium/winloop.sh b/env/windows-arm64/macstadium/winloop.sh
deleted file mode 100755
index 164a89f..0000000
--- a/env/windows-arm64/macstadium/winloop.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-# Copyright 2022 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.
-
-
-while true; do
- DYLD_LIBRARY_PATH="$HOME/macmini-windows/sysroot-macos-arm64/lib" "$HOME/macmini-windows/sysroot-macos-arm64/bin/qemu-system-aarch64" \
- -L ./UTM.app/Contents/Resources/qemu \
- -device ramfb \
- -cpu max \
- -smp cpus=8,sockets=1,cores=8,threads=1 \
- -machine virt,highmem=off \
- -accel hvf \
- -accel tcg,tb-size=1536 \
- -boot menu=on \
- -m 8192 \
- -name "Virtual Machine" \
- -device qemu-xhci,id=usb-bus \
- -device usb-tablet,bus=usb-bus.0 \
- -device usb-mouse,bus=usb-bus.0 \
- -device usb-kbd,bus=usb-bus.0 \
- -bios "$HOME/macmini-windows/Images/QEMU_EFI.fd" \
- -device nvme,drive=drive0,serial=drive0,bootindex=0 \
- -drive "if=none,media=disk,id=drive0,file=$HOME/macmini-windows/Images/win10.qcow2,cache=writethrough" \
- -device usb-storage,drive=drive2,removable=true,bootindex=1 \
- -drive "if=none,media=cdrom,id=drive2,file=$HOME/macmini-windows/Images/virtio.iso,cache=writethrough" \
- -device virtio-net-pci,netdev=net0 \
- -netdev user,id=net0 \
- -uuid 41E1CBA2-8837-4224-801B-277336D58A3D \
- -snapshot \
- -vnc :3
- sleep 5
-done
diff --git a/internal/coordinator/pool/reverse.go b/internal/coordinator/pool/reverse.go
index a58fb43..7645483 100644
--- a/internal/coordinator/pool/reverse.go
+++ b/internal/coordinator/pool/reverse.go
@@ -35,7 +35,6 @@
"context"
"crypto/hmac"
"crypto/md5"
- "encoding/json"
"errors"
"fmt"
"io"
@@ -51,7 +50,6 @@
"golang.org/x/build/dashboard"
"golang.org/x/build/internal/coordinator/pool/queue"
"golang.org/x/build/revdial/v2"
- "golang.org/x/build/types"
)
const minBuildletVersion = 23
@@ -117,56 +115,6 @@
return t, ok
}
-// ServeReverseStatusJSON is an HTTP handler implementation which serves the status in
-// JSON format.
-func (p *ReverseBuildletPool) ServeReverseStatusJSON(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- status := p.BuildReverseStatusJSON()
- j, _ := json.MarshalIndent(status, "", "\t")
- w.Write(j)
-}
-
-// BuildReverseStatusJSON is an HTTP handler implementation which builds the reverse
-// status reverse buildlets.
-func (p *ReverseBuildletPool) BuildReverseStatusJSON() *types.ReverseBuilderStatus {
- status := &types.ReverseBuilderStatus{}
-
- p.mu.Lock()
- defer p.mu.Unlock()
- for _, b := range p.buildlets {
- hs := status.Host(b.hostType)
- if hs.Machines == nil {
- hs.Machines = make(map[string]*types.ReverseBuilder)
- }
- hs.Connected++
- bs := &types.ReverseBuilder{
- Name: b.hostname,
- HostType: b.hostType,
- ConnectedSec: time.Since(b.regTime).Seconds(),
- Version: b.version,
- }
- if b.inUse && !b.inHealthCheck {
- hs.Busy++
- bs.Busy = true
- bs.BusySec = time.Since(b.inUseTime).Seconds()
- } else {
- hs.Idle++
- bs.IdleSec = time.Since(b.inUseTime).Seconds()
- }
-
- hs.Machines[b.hostname] = bs
- }
- for hostType, queue := range p.hostQueue {
- status.Host(hostType).Waiters = queue.Len()
- }
- for hostType, hc := range dashboard.Hosts {
- if hc.ExpectNum > 0 {
- status.Host(hostType).Expect = hc.ExpectNum
- }
- }
- return status
-}
-
// tryToGrab returns non-nil bc on success if a buildlet is free.
//
// Otherwise it returns how many were busy, which might be 0 if none