Skip to content

Commit d960d82

Browse files
committed
cmd/coordinator: support testing subrepos that use modules
Only the "oauth2" and "build" repos for now, as a test. We'll lock down policy more later and decide when to do this automatically. Also, this currently only runs buildlets which run in our GCP project, because we're not yet proxying the a localhost:3000 port from the reverse buildlets to an authenticated TLS connection back to our module proxy service on GKE. Updates golang/go#14594 Fixes golang/go#29637 Change-Id: I6f05da2186b38dc8056081252563a82c50f0ce05 Reviewed-on: https://go-review.googlesource.com/c/157438 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]> Reviewed-by: Andrew Bonventre <[email protected]>
1 parent 041ab4d commit d960d82

File tree

5 files changed

+194
-14
lines changed

5 files changed

+194
-14
lines changed

cmd/coordinator/athens-prod.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
apiVersion: extensions/v1beta1
2+
kind: Deployment
3+
metadata:
4+
name: athens-deployment
5+
spec:
6+
template:
7+
metadata:
8+
labels:
9+
app: athens
10+
annotations:
11+
container.seccomp.security.alpha.kubernetes.io/athens: docker/default
12+
container.apparmor.security.beta.kubernetes.io/athens: runtime/default
13+
spec:
14+
volumes:
15+
- name: cache-volume
16+
emptyDir: {}
17+
containers:
18+
- name: athens
19+
image: gomods/athens:v0.2.0
20+
imagePullPolicy: Always
21+
command: ["/bin/athens-proxy", "-config_file=/config/config.toml"]
22+
volumeMounts:
23+
- mountPath: "/athens-cache"
24+
name: cache-volume
25+
env:
26+
- name: GO_ENV
27+
value: "production"
28+
- name: ATHENS_STORAGE_TYPE
29+
value: "disk"
30+
- name: ATHENS_DISK_STORAGE_ROOT
31+
value: "/athens-cache"
32+
ports:
33+
- containerPort: 3000
34+
resources:
35+
requests:
36+
cpu: "1"
37+
memory: "2Gi"

cmd/coordinator/coordinator.go

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747
"go4.org/syncutil"
4848
grpc "grpc.go4.org"
4949

50+
"cloud.google.com/go/compute/metadata"
5051
"cloud.google.com/go/errorreporting"
5152
"cloud.google.com/go/storage"
5253
"golang.org/x/build"
@@ -985,9 +986,8 @@ func findTryWork() error {
985986
log.Printf("Warning: skipping incomplete %#v", work)
986987
continue
987988
}
988-
if work.Project == "build" || work.Project == "grpc-review" {
989-
// Skip trybot request in build repo.
990-
// Also skip grpc-review, which is only for reviews for now.
989+
if work.Project == "grpc-review" {
990+
// Skip grpc-review, which is only for reviews for now.
991991
continue
992992
}
993993
key := tryWorkItemKey(work)
@@ -1073,6 +1073,8 @@ func tryWorkItemKey(work *apipb.GerritTryWorkItem) tryKey {
10731073
}
10741074
}
10751075

1076+
var testingKnobSkipBuilds bool
1077+
10761078
// newTrySet creates a new trySet group of builders for a given
10771079
// work item, the (Project, Branch, Change-ID, Commit) tuple.
10781080
// It also starts goroutines for each build.
@@ -1108,11 +1110,16 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
11081110
idx := len(ts.builds)
11091111
ts.builds = append(ts.builds, bs)
11101112
ts.remain++
1113+
if testingKnobSkipBuilds {
1114+
return
1115+
}
11111116
go bs.start() // acquires statusMu itself, so in a goroutine
11121117
go ts.awaitTryBuild(idx, bs, brev)
11131118
}
11141119

1115-
go ts.notifyStarting()
1120+
if !testingKnobSkipBuilds {
1121+
go ts.notifyStarting()
1122+
}
11161123
for _, bconf := range builders {
11171124
brev := tryKeyToBuilderRev(bconf.Name, key, goRev)
11181125
bs, err := newBuild(brev)
@@ -1130,6 +1137,10 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
11301137
work.GoCommit = work.GoCommit[:len(work.GoBranch)]
11311138
}
11321139

1140+
// linuxBuilder is the standard builder we run for when testing x/* repos against
1141+
// the past two Go releases.
1142+
linuxBuilder := dashboard.Builders["linux-amd64"]
1143+
11331144
// If there's more than one GoCommit, that means this is an x/* repo
11341145
// and we're testing against previous releases of Go.
11351146
for i, goRev := range work.GoCommit {
@@ -1138,7 +1149,10 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
11381149
continue
11391150
}
11401151
branch := work.GoBranch[i]
1141-
brev := tryKeyToBuilderRev("linux-amd64", key, goRev)
1152+
if !linuxBuilder.BuildBranch(key.Project, "master", branch) {
1153+
continue
1154+
}
1155+
brev := tryKeyToBuilderRev(linuxBuilder.Name, key, goRev)
11421156
bs, err := newBuild(brev)
11431157
if err != nil {
11441158
log.Printf("can't create build for %q: %v", brev, err)
@@ -1344,6 +1358,9 @@ func (ts *trySet) noteBuildComplete(bs *buildStatus) {
13441358
}
13451359
}
13461360

1361+
// skipBuild reports whether the br build should be skipped.
1362+
//
1363+
// TODO(bradfitz): move this policy func into dashboard/builders.go in its own CL sometime.
13471364
func skipBuild(br buildgo.BuilderRev) bool {
13481365
if br.Name == "freebsd-arm-paulzhol" {
13491366
// This was a fragile little machine with limited memory.
@@ -1356,11 +1373,20 @@ func skipBuild(br buildgo.BuilderRev) bool {
13561373
return true
13571374
}
13581375
switch br.SubName {
1359-
case "build", // has external deps
1360-
"exp", // always broken, depends on mobile which is broken
1376+
case "oauth2", "build":
1377+
// The oauth2 and build repos are our guinea pigs for
1378+
// testing using modules. But they currently only work
1379+
// inside the GCP network.
1380+
// TODO: once we proxy through the module proxy from
1381+
// reverse buildlets' localhost:3000 to
1382+
// authenticated+TLS farmer.golang.org to the GKE
1383+
// service, then we can use modules less
1384+
// conditionally.
1385+
bc, ok := dashboard.Builders[br.Name]
1386+
return !ok || bc.IsReverse()
1387+
case "exp", // always broken, depends on mobile which is broken
13611388
"mobile", // always broken (gl, etc). doesn't compile.
1362-
"term", // no code yet in repo: "warning: "golang.org/x/term/..." matched no packages"
1363-
"oauth2": // has external deps
1389+
"term": // no code yet in repo,
13641390
return true
13651391
case "perf":
13661392
if br.Name == "linux-amd64-nocgo" {
@@ -2690,10 +2716,11 @@ func (st *buildStatus) runSubrepoTests() (remoteErr, err error) {
26902716
return nil, nil
26912717
}
26922718

2693-
// Recursively fetch the repo and its dependencies.
2694-
// Dependencies are always fetched at master, which isn't
2695-
// great but the dashboard data model doesn't track
2696-
// sub-repo dependencies. TODO(adg): fix this somehow??
2719+
// Recursively fetch the repo and their golang.org/x/*
2720+
// dependencies. Dependencies are always fetched at master,
2721+
// which isn't great but the dashboard data model doesn't
2722+
// track non-golang.org/x/* dependencies. For those, we
2723+
// require on the code under test to be using Go modules.
26972724
for i := 0; i < len(toFetch); i++ {
26982725
repo := toFetch[i]
26992726
if fetched[repo] {
@@ -2725,17 +2752,70 @@ func (st *buildStatus) runSubrepoTests() (remoteErr, err error) {
27252752

27262753
sp := st.CreateSpan("running_subrepo_tests", st.SubName)
27272754
defer func() { sp.Done(err) }()
2755+
2756+
goProxy, err := st.moduleProxy()
2757+
if err != nil {
2758+
return nil, err
2759+
}
2760+
var go111Module, dir string
2761+
if goProxy != "" {
2762+
go111Module = "on"
2763+
dir = "gopath/src/golang.org/x/" + st.SubName
2764+
}
2765+
27282766
return st.bc.Exec(path.Join("go", "bin", "go"), buildlet.ExecOpts{
27292767
Output: st,
2768+
Dir: dir,
27302769
ExtraEnv: append(st.conf.Env(),
27312770
"GOROOT="+goroot,
27322771
"GOPATH="+gopath,
2772+
"GO111MODULE="+go111Module,
2773+
"GOPROXY="+goProxy,
27332774
),
27342775
Path: []string{"$WORKDIR/go/bin", "$PATH"},
27352776
Args: []string{"test", "-short", subrepoPrefix + st.SubName + "/..."},
27362777
})
27372778
}
27382779

2780+
// moduleProxy returns the GOPROXY environment value to use for this
2781+
// build's tests. If non-empty, GO111MODULE=on is included in the
2782+
// environment as well. Returning two zero values means to not
2783+
// configure the environment values.
2784+
//
2785+
// We go through a GCP-project-internal module proxy ("GOPROXY") to
2786+
// eliminate load on the origin servers. Our builder VMs are ephemeral
2787+
// and only run for the duration of one build. They also often don't
2788+
// have all the VCS tools installed (or even available: there is no
2789+
// git for plan9).
2790+
func (bs *buildStatus) moduleProxy() (string, error) {
2791+
switch bs.SubName {
2792+
case "oauth2", "build":
2793+
// The two repos we're starting with for testing.
2794+
default:
2795+
return "", nil
2796+
}
2797+
// If we're running on localhost, just use the current environment's value.
2798+
if buildEnv == nil || !buildEnv.IsProd {
2799+
return os.Getenv("GOPROXY"), nil
2800+
}
2801+
2802+
// We run a NodePort service on each GKE node
2803+
// (cmd/coordinator/module-proxy-service.yaml) on port 30156
2804+
// that maps to the Athens service. We could round robin over
2805+
// all the GKE nodes' IPs if we wanted, but the coordinator is
2806+
// running on GKE so our node by definition is up, so just use it.
2807+
// It won't be much traffic.
2808+
// TODO: migrate to a GKE internal load balancer with an internal static IP
2809+
// once we migrate symbolic-datum-552 off a Legacy VPC network to the modern
2810+
// scheme that supports internal static IPs.
2811+
gkeNodeIP, err := metadata.Get("instance/network-interfaces/0/ip")
2812+
if err != nil || gkeNodeIP == "" {
2813+
log.Printf("WARNING: failed to discover local GCE node's IP: %v; disabling GOPROXY", err)
2814+
return "", nil
2815+
}
2816+
return "http://" + gkeNodeIP + ":30156", nil
2817+
}
2818+
27392819
// affectedPkgs returns the name of every package affected by this commit.
27402820
// The returned list may contain duplicates and is unsorted.
27412821
// It is safe to call this on a nil trySet.

cmd/coordinator/coordinator_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"time"
1616

1717
"golang.org/x/build/internal/buildgo"
18+
"golang.org/x/build/maintner/maintnerd/apipb"
1819
)
1920

2021
func TestPartitionGoTests(t *testing.T) {
@@ -111,3 +112,25 @@ func TestStagingClusterBuilders(t *testing.T) {
111112
// Just test that it doesn't panic:
112113
stagingClusterBuilders()
113114
}
115+
116+
// tests that we don't test Go 1.10 for the build repo
117+
func TestNewTrySetBuildRepoGo110(t *testing.T) {
118+
testingKnobSkipBuilds = true
119+
120+
work := &apipb.GerritTryWorkItem{
121+
Project: "build",
122+
Branch: "master",
123+
ChangeId: "I6f05da2186b38dc8056081252563a82c50f0ce05",
124+
Commit: "a62e6a3ab11cc9cc2d9e22a50025dd33fc35d22f",
125+
GoCommit: []string{"a2e79571a9d3dbe3cf10dcaeb1f9c01732219869", "e39e43d7349555501080133bb426f1ead4b3ef97", "f5ff72d62301c4e9d0a78167fab5914ca12919bd"},
126+
GoBranch: []string{"master", "release-branch.go1.11", "release-branch.go1.10"},
127+
}
128+
ts := newTrySet(work)
129+
for i, bs := range ts.builds {
130+
v := bs.NameAndBranch()
131+
if strings.Contains(v, "Go 1.10.x") {
132+
t.Errorf("unexpected builder: %v", v)
133+
}
134+
t.Logf("build[%d]: %s", i, v)
135+
}
136+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: go-module-proxy
5+
annotations:
6+
cloud.google.com/load-balancer-type: "Internal"
7+
spec:
8+
type: NodePort
9+
ports:
10+
- name: module-proxy
11+
port: 3000
12+
targetPort: 3000
13+
nodePort: 30156
14+
protocol: TCP
15+
selector:
16+
app: athens
17+
18+
# TODO(bradfitz): migrate (destroy & recreate) symbolic-datum-552 to get it off legacy networking
19+
# so we can use an internal LoadBalancer with a static internal IP instead, and then:
20+
#
21+
#spec:
22+
# type: LoadBalancer
23+
# loadBalancerIP: "10.240.0.we-cant-do-this-because-symbolic-datum-552-is-using-legacy-networking"
24+
# loadBalancerSourceRanges:
25+
# - "10.0.0.0/8"
26+
# ports:
27+
# - port: 3000
28+
# targetPort: 3000
29+
# selector:
30+
# app: athens

dashboard/builders.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,15 @@ func (c *BuildConfig) BuildRepo(repo string) bool {
841841
// branch is the branch of the repo (usually "master").
842842
// goBranch is non-empty for a non-"go" repo, and is the branch of Go the subrepo is being tested at.
843843
func (c *BuildConfig) BuildBranch(repo, branch, goBranch string) bool {
844+
// Don't try to build oauth2 or build before Go 1.11. These
845+
// repos require modules.
846+
switch repo {
847+
case "oauth2", "build":
848+
if branch == "release-branch.go1.10" || goBranch == "release-branch.go1.10" {
849+
return false
850+
}
851+
}
852+
844853
if strings.HasPrefix(c.Name, "darwin-") {
845854
switch c.Name {
846855
case "darwin-amd64-10_8", "darwin-amd64-10_10", "darwin-amd64-10_11",
@@ -1023,8 +1032,9 @@ func defaultTrySet(extraProj ...string) func(proj string) bool {
10231032
return true
10241033
}
10251034
}
1035+
// TODO: remove items from this set once these repos have go.mod files:
10261036
switch proj {
1027-
case "grpc-review", "build", "exp", "mobile", "term", "oauth2":
1037+
case "grpc-review", "exp", "mobile", "term":
10281038
return false
10291039
}
10301040
return true

0 commit comments

Comments
 (0)