dashboard, buildenv: label EC2 instances

This change adds a boolean which identified when an instance is an
EC2 instance. Various EC2 related variables have been renamed to be
more consistent.

Updates golang/go#36841

Change-Id: Ief385bf9d41e320ebd7d31bc0108e8053f337afd
Reviewed-on: https://go-review.googlesource.com/c/build/+/233801
Run-TryBot: Carlos Amedee <carlos@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alexander Rakoczy <alex@golang.org>
diff --git a/buildenv/envs.go b/buildenv/envs.go
index e54e3b9..50ef1c5 100644
--- a/buildenv/envs.go
+++ b/buildenv/envs.go
@@ -74,17 +74,17 @@
 	// other fields.
 	ControlZone string
 
-	// PreferredAvailabilityZone is the preffered AWS availability zone.
-	PreferredAvailabilityZone string
+	// PreferredEC2Zone is the preffered AWS availability zone.
+	PreferredEC2Zone string
 
 	// VMZones are the GCE zones that the VMs will be deployed to. These
 	// GCE zones will be periodically cleaned by deleting old VMs. The zones
 	// should all exist within a single region.
 	VMZones []string
 
-	// VMAvailabilityZones are the AWS availability zones that the VMs will be deployed to.
+	// VMEC2Zones are the AWS availability zones that the VMs will be deployed to.
 	// The availability zones should all exist within a single region.
-	VMAvailabilityZones []string
+	VMEC2Zones []string
 
 	// StaticIP is the public, static IP address that will be attached to the
 	// coordinator instance. The zero value means the address will be looked
@@ -158,14 +158,14 @@
 	return e.VMZones[rand.Intn(len(e.VMZones))]
 }
 
-// RandomAWSVMZone returns a randomly selected zone from the zones in
+// RandomEC2VMZone returns a randomly selected zone from the zones in
 // VMAvailabilityZones. The PreferredAvailabilityZone value will be
 // returned if VMAvailabilityZones is not set.
-func (e Environment) RandomAWSVMZone() string {
-	if len(e.VMAvailabilityZones) == 0 {
-		return e.PreferredAvailabilityZone
+func (e Environment) RandomEC2VMZone() string {
+	if len(e.VMEC2Zones) == 0 {
+		return e.PreferredEC2Zone
 	}
-	return e.VMAvailabilityZones[rand.Intn(len(e.VMZones))]
+	return e.VMEC2Zones[rand.Intn(len(e.VMEC2Zones))]
 }
 
 // Region returns the GCE region, derived from its zone.
@@ -289,6 +289,7 @@
 	IsProd:                true,
 	ControlZone:           "us-central1-f",
 	VMZones:               []string{"us-central1-a", "us-central1-b", "us-central1-c", "us-central1-f"},
+	VMEC2Zones:            []string{"us-east-2a", "us-east-2b"},
 	StaticIP:              "107.178.219.46",
 	MachineType:           "n1-standard-4",
 	PreferContainersOnCOS: true,
diff --git a/buildenv/envs_test.go b/buildenv/envs_test.go
index bbee9aa..79f2d34 100644
--- a/buildenv/envs_test.go
+++ b/buildenv/envs_test.go
@@ -50,6 +50,48 @@
 	}
 }
 
+func TestEnvironmentRandomEC2VMZone(t *testing.T) {
+	testCases := []struct {
+		name      string
+		env       Environment
+		wantOneOf []string
+	}{
+		{
+			name: "zones-not-set",
+			env: Environment{
+				PreferredEC2Zone: "zone-a",
+				VMEC2Zones:       []string{},
+			},
+			wantOneOf: []string{"zone-a"},
+		},
+		{
+			name: "zone-and-zones-set",
+			env: Environment{
+				PreferredEC2Zone: "zone-a",
+				VMEC2Zones:       []string{"zone-b", "zone-c"},
+			},
+
+			wantOneOf: []string{"zone-b", "zone-c"},
+		},
+		{
+			name: "zones-only-contains-one-entry",
+			env: Environment{
+				PreferredEC2Zone: "zone-a",
+				VMEC2Zones:       []string{"zone-b"},
+			},
+			wantOneOf: []string{"zone-b"},
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			got := tc.env.RandomEC2VMZone()
+			if !containsString(got, tc.wantOneOf) {
+				t.Errorf("got=%q; want %v", got, tc.wantOneOf)
+			}
+		})
+	}
+}
+
 func containsString(item string, items []string) bool {
 	for _, s := range items {
 		if item == s {
diff --git a/buildlet/aws.go b/buildlet/aws.go
index 8842fc3..a2c3e55 100644
--- a/buildlet/aws.go
+++ b/buildlet/aws.go
@@ -85,7 +85,7 @@
 		opts.Description = fmt.Sprintf("Go Builder for %s", hostType)
 	}
 	if opts.Zone == "" {
-		opts.Zone = buildEnv.RandomAWSVMZone()
+		opts.Zone = buildEnv.RandomEC2VMZone()
 	}
 	if opts.DeleteIn == 0 {
 		opts.DeleteIn = 30 * time.Minute
diff --git a/dashboard/builders.go b/dashboard/builders.go
index bf95b89..2580a91 100644
--- a/dashboard/builders.go
+++ b/dashboard/builders.go
@@ -552,9 +552,10 @@
 		SSHUsername:     "root",
 	},
 	"host-linux-arm64-aws": &HostConfig{
-		Notes:           "Debian Buster, EC2 arm64 instance. See x/build/env/linux-arm64/arm",
+		Notes:           "Debian Buster, EC2 arm64 instance. See x/build/env/linux-arm64/aws",
 		VMImage:         "ami-0454a5239a73a9e81",
 		machineType:     "a1.xlarge",
+		isEC2:           true,
 		env:             []string{"GOROOT_BOOTSTRAP=/usr/local/go-bootstrap"},
 		buildletURLTmpl: "http://storage.googleapis.com/$BUCKET/buildlet.linux-amd64",
 		SSHUsername:     "admin",
@@ -713,6 +714,9 @@
 	RegularDisk    bool   // if true, use spinning disk instead of SSD
 	MinCPUPlatform string // optional; https://cloud.google.com/compute/docs/instances/specify-min-cpu-platform
 
+	// EC2 options
+	isEC2 bool // if true, the instance is configured to run on EC2
+
 	// ReverseOptions:
 	ExpectNum       int  // expected number of reverse buildlets of this type
 	HermeticReverse bool // whether reverse buildlet has fresh env per conn
@@ -1296,6 +1300,11 @@
 	return "n1-highcpu-2"
 }
 
+// IsEC2 returns true if the machine type is an EC2 arm64 type.
+func (c *HostConfig) IsEC2() bool {
+	return c.isEC2
+}
+
 // ShortOwner returns a short human-readable owner.
 func (c BuildConfig) ShortOwner() string {
 	owner := c.HostConfig().Owner
@@ -1316,6 +1325,8 @@
 	switch {
 	case c.IsReverse:
 		return "Reverse (dedicated machine/VM)"
+	case c.IsEC2():
+		return "EC2 VM"
 	case c.IsVM():
 		return "GCE VM"
 	case c.IsContainer():
@@ -1349,6 +1360,8 @@
 	switch {
 	case c.IsReverse:
 		return c.HermeticReverse
+	case c.IsEC2():
+		return true
 	case c.IsVM():
 		return true
 	case c.IsContainer():