Import changes for goma server
- a702111367735f8c0a46225ea9146dc57b3ba713 Should refer env_file_for_docker in WORK_DIR instead of c...
- 9ee4ac3baa2bfe9a6c51292aa04763b31a6371a9 remoteexec: ExecuteAndWait returns error of resp status.
- 18366bdf014af5e6e7cb79ed274ac86ad90182f0 remoteexec: don't add . for wrapper on windows
- 7ee036e7a320085d751425b91f5fafd2949496bb remoteexec: fix retry by ExecuteResponse status
- bc9eb1ff4b5995e32bedc0626580c1322b21dab2 roll cloud.google.com/go from 0.41.0 to 0.43.0
- 4bc2b91a156363be0d2404c150fd787d808d375d remoteexec: update request metadata name
- c670f55ebb2dd5f2cb9ae58b406109f6424a212c User environment should directly goes to where the compil...
- e839bb6deafc14cc6ddbd2390a9f77923b85ed34 roll github.com/golang/protobuf from 1.3.1 to 1.3.2
- c8c02f1a5bd9f80f73dffd1d6599a8288d7daac3 use go 1.12.7
- 8c85c6baeac7addfda80134578d2ac5304837ab7 Use "pwd -P" instead of pwd to get current working direct...
- b2d77a97fd319e5bec7e8de559a79fd895bbc018 roll google.golang.org/grpc from 1.21.1 to 1.22.0
- a506584bd95b470c908698c1be2ecb94d2620aa0 roll cloud.google.com/go from 0.40.0 to 0.41.0
- 96a8f21ee37900a200b3e7021d7b3cdb95e17035 remoteexec: reduce log volume
- c713279d342b08cffe62fb266c6890c9fd46598b remoteexec: set rpc id
- 8640543157f9b1cab6be2e9b5970101c248f0329 remoteexec_proxy: add document how to deploy it on appeng...
- f9dc9f386b2dc522458f68e71af052f88a184f00 nsjail: add dummy HOME directory.
- 64808c917652706de338b858213626dda987b17c nsjail: make /dev/null available.
- f0a4ba0be368a4edcbd259193d725b8700418914 nsjail: set up PATH env from ExecReq::ToolchainSpec.
- f1a01e793953c325c69576f75af614b9bbe03174 roll google.golang.org/api from 0.6.0 to 0.7.0
GitOrigin-RevId: 509e19eb587f2a5deb66290e1e70b5665b9a50d5
Change-Id: I7c08d57a3bbe51ff6c199228308ff13c0f320a49
TBR=yyanagisawa@google.com, tikuta@google.com
diff --git a/cipd_manifest.txt b/cipd_manifest.txt
index 847d7a1..9ee7676 100644
--- a/cipd_manifest.txt
+++ b/cipd_manifest.txt
@@ -13,7 +13,7 @@
# https://chrome-infra-packages.appspot.com/
# go
-infra/go/${platform} version:1.12.5
+infra/go/${platform} version:1.12.7
# protoc
# If the version you want is missing, please follow the instruction in:
diff --git a/cipd_manifest.versions b/cipd_manifest.versions
index 6dc1428..aa8ddf8 100644
--- a/cipd_manifest.versions
+++ b/cipd_manifest.versions
@@ -2,8 +2,8 @@
# Do not modify manually. All changes will be overwritten.
infra/go/linux-amd64
- version:1.12.5
- G8oyAmKE671-BJ-Mb1HdgChT7kkcoNwO-w_Z-vVnBGMC
+ version:1.12.7
+ lBm3oqkMtwrbllgPo-1cOqivkJcZpRUY-hO74LduBdMC
infra/tools/protoc/linux-amd64
protobuf_version:v3.7.0
diff --git a/cmd/remoteexec_proxy/README.md b/cmd/remoteexec_proxy/README.md
new file mode 100644
index 0000000..c89c66c
--- /dev/null
+++ b/cmd/remoteexec_proxy/README.md
@@ -0,0 +1,105 @@
+# Goma server - remoteexec_proxy
+
+# How to deploy it on Google App Engine Flexible Environment
+
+`remoteexec_proxy` can run on Google App Engine Flexible Environment.
+
+## Dependencies
+
+Need to setup [cloud memorystore](https://cloud.google.com/memorystore/)
+and [cloud storage](https://cloud.google.com/storage/).
+
+### Cloud Memorystore
+
+Cloud memorystore is used for digest cache.
+You need to create an instance in the same location as App Engine apps.
+
+NOTE If different location, your server will get many `context deadline exceeded` errors.
+
+If not created, run `gcloud app create` can create App Engine app in
+the specific region in the cloud project.
+
+```
+$ gcloud app create --region=$REGION
+```
+
+If it is already created, you can check it by `gcloud app describe`
+
+```
+$ gcloud app describe --format='get(locationId)'
+```
+
+It is sufficient with 1GB size, but you might want to set
+`maxmemory-policy: allkeys-lru`.
+
+```
+$ gcloud redis instances create $REDIS_INSTANCE_NAME \
+ --region=$REGION \
+ --redis-config='maxmemory-poclicy=allkeys-lru'
+```
+
+### Cloud Storage
+
+Cloud storage is used to store file cache.
+
+```
+$ gsutil mb gs://${PROJECT_ID}-file-cache
+$ gsutil lifecycle set '{"rule": [{"action": {"type": "Delete"}, "condition": {"age": 1}}]}' gs://${PROJECT_ID}-file-cache
+```
+
+## Deploy
+
+To deploy the server, create a workspace
+
+```
+$ mkdir /path/to/workspace
+$ cd /path/to/workspace
+$ TOPDIR=$(pwd)
+$ git clone https://chromium.googlesource.com/infra/goma/server
+$ cd server
+$ GO111MODULE=on go mod vendor
+$ mkdir ../gopath/src
+$ export GOPATH=$(TOPDIR)/gopath
+$ mv vendor/* ../gopath/src
+$ mkdir app
+$ cd app
+$ cp ../server/cmd/remoteexec_server/* .
+$ REDISHOST=$(gcloud redis instances describe $REDIS_INSTANCE_NAME \
+ --region $REGION --format='get(host)')
+$ REDISPORT=$(gcloud redis instances describe $REDIS_INSTANCE_NAME \
+ --region $REGION --format='get(port)')
+$ cat > app.yaml <<EOF
+runtime: go
+env: flex
+
+network:
+ name: default
+
+liveness_check:
+ path: "/healthz"
+
+readiness_check:
+ path: "/healthz"
+
+env_variables:
+ REDISHOST: "$REDISHOST"
+ REDISPORT: "$REDISPORT"
+EOF
+$ cat > flag.go << EOF
+package main
+
+func init() {
+ *port = 8080
+ *remoteexecAddr = "remotebuildexecution.googleapis.com:443"
+ *remoteInstanceName = "projects/$PROJECT_ID/instances/default_instance"
+ *whitelistedUsers = "<comma separated whitelisted-users-email-address>"
+ *platformContainerImage = "docker://gcr.io/..."
+ *fileCacheBucket = "$PROJECT_ID-file-cache"
+}
+EOF
+$ gcloud app deploy
+```
+
+Then, you can use `$PROJECT_ID.appspot.com` as `$GOMA_SERVER_HOST`.
+You need to specify `GOMA_ARBTRARY_TOOLCHAIN_SUPPORT=true`.
+
diff --git a/cmd/remoteexec_proxy/main.go b/cmd/remoteexec_proxy/main.go
index 8bce206..886127d 100644
--- a/cmd/remoteexec_proxy/main.go
+++ b/cmd/remoteexec_proxy/main.go
@@ -54,6 +54,7 @@
filepb "go.chromium.org/goma/server/proto/file"
"go.chromium.org/goma/server/remoteexec"
"go.chromium.org/goma/server/remoteexec/digest"
+ "go.chromium.org/goma/server/rpc"
"go.chromium.org/goma/server/server"
)
@@ -155,6 +156,35 @@
}, nil
}
+type reExecServer struct {
+ re *remoteexec.Adapter
+}
+
+func (r reExecServer) Exec(ctx context.Context, req *gomapb.ExecReq) (*gomapb.ExecResp, error) {
+ ctx, id := rpc.TagID(ctx, req.GetRequesterInfo())
+ logger := log.FromContext(ctx)
+ logger.Infof("call exec %s", id)
+ return r.re.Exec(ctx, req)
+}
+
+type reFileServer struct {
+ s filepb.FileServiceServer
+}
+
+func (r reFileServer) StoreFile(ctx context.Context, req *gomapb.StoreFileReq) (*gomapb.StoreFileResp, error) {
+ ctx, id := rpc.TagID(ctx, req.GetRequesterInfo())
+ logger := log.FromContext(ctx)
+ logger.Infof("call storefile %s", id)
+ return r.s.StoreFile(ctx, req)
+}
+
+func (r reFileServer) LookupFile(ctx context.Context, req *gomapb.LookupFileReq) (*gomapb.LookupFileResp, error) {
+ ctx, id := rpc.TagID(ctx, req.GetRequesterInfo())
+ logger := log.FromContext(ctx)
+ logger.Infof("call lookupfile %s", id)
+ return r.s.LookupFile(ctx, req)
+}
+
type localBackend struct {
ExecService execpb.ExecServiceServer
FileService filepb.FileServiceServer
@@ -387,8 +417,8 @@
mux := http.DefaultServeMux
frontend.Register(mux, frontend.Frontend{
Backend: localBackend{
- ExecService: re,
- FileService: fileServiceClient.Service,
+ ExecService: reExecServer{re},
+ FileService: reFileServer{fileServiceClient.Service},
Auth: &auth.Auth{
Client: authClient{Service: authService},
},
diff --git a/go.mod b/go.mod
index adebda3..da967e7 100644
--- a/go.mod
+++ b/go.mod
@@ -3,18 +3,15 @@
go 1.12
require (
- cloud.google.com/go v0.40.0
+ cloud.google.com/go v0.43.0
contrib.go.opencensus.io/exporter/stackdriver v0.12.2
github.com/bazelbuild/remote-apis v0.0.0-20190606163526-a5c577357528
github.com/fsnotify/fsnotify v1.4.7
github.com/gogo/protobuf v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef
- github.com/golang/mock v1.3.1 // indirect
- github.com/golang/protobuf v1.3.1
+ github.com/golang/protobuf v1.3.2
github.com/gomodule/redigo v2.0.0+incompatible
- github.com/google/btree v1.0.0 // indirect
github.com/google/go-cmp v0.3.0
- github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect
github.com/google/uuid v1.1.1
github.com/googleapis/gax-go/v2 v2.0.5
github.com/googleapis/google-cloud-go-testing v0.0.0-20190307174402-f55056552511
@@ -28,19 +25,14 @@
go.uber.org/zap v1.10.0
golang.org/x/build v0.0.0-20190314215453-3ce8d48fad73
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 // indirect
- golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 // indirect
golang.org/x/image v0.0.0-20190618124811-92942e4437e2 // indirect
golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88 // indirect
golang.org/x/mod v0.1.0 // indirect
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sync v0.0.0-20190423024810-112230192c58
- golang.org/x/sys v0.0.0-20190620070143-6f217b454f45 // indirect
- golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
- golang.org/x/tools v0.0.0-20190620191750-1fa568393b23 // indirect
- google.golang.org/api v0.6.0
- google.golang.org/appengine v1.6.1 // indirect
- google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601
- google.golang.org/grpc v1.21.1
+ google.golang.org/api v0.7.0
+ google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610
+ google.golang.org/grpc v1.22.0
honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b // indirect
)
diff --git a/go.sum b/go.sum
index 76857ab..6c2ca7f 100644
--- a/go.sum
+++ b/go.sum
@@ -8,6 +8,10 @@
cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
cloud.google.com/go v0.40.0 h1:FjSY7bOj+WzJe6TZRVtXI2b9kAYvtNg4lMbcH2+MUkk=
cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro=
+cloud.google.com/go v0.41.0 h1:NFvqUTDnSNYPX5oReekmB+D+90jrJIcVImxQ3qrBVgM=
+cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg=
+cloud.google.com/go v0.43.0 h1:banaiRPAM8kUVYneOSkhgcDsLzEvL25FinuiSZaH/2w=
+cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
contrib.go.opencensus.io/exporter/stackdriver v0.12.1 h1:Dll2uFfOVI3fa8UzsHyP6z0M6fEc9ZTAMo+Y3z282Xg=
contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
contrib.go.opencensus.io/exporter/stackdriver v0.12.2 h1:jU1p9F07ASK11wYgSTPKtFlTvTtCDj6R1d3nRt0ZHDE=
@@ -59,6 +63,8 @@
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -242,6 +248,8 @@
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45 h1:Dl2hc890lrizvUppGbRWhnIh2f8jOTCQpY5IKWRS0oM=
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -262,9 +270,12 @@
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190620191750-1fa568393b23/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
@@ -274,6 +285,8 @@
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.6.0 h1:2tJEkRfnZL5g1GeBUlITh/rqT5HG3sFcoVCUUxmgJ2g=
google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
+google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -303,6 +316,10 @@
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 h1:9VBRTdmgQxbs6HE0sUnMrSWNePppAJU07NYvX5dIB04=
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190626174449-989357319d63 h1:UsSJe9fhWNSz6emfIGPpH5DF23t7ALo2Pf3sC+/hsdg=
+google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610 h1:Ygq9/SRJX9+dU0WCIICM8RkWvDw03lvB77hrhJnpxfU=
+google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@@ -314,6 +331,8 @@
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw=
+google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@@ -326,6 +345,7 @@
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190215041234-466a0476246c/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
diff --git a/proto/auth/auth_service.pb.go b/proto/auth/auth_service.pb.go
index 2574196..827165d 100644
--- a/proto/auth/auth_service.pb.go
+++ b/proto/auth/auth_service.pb.go
@@ -8,6 +8,8 @@
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
math "math"
)
@@ -71,6 +73,14 @@
Auth(context.Context, *AuthReq) (*AuthResp, error)
}
+// UnimplementedAuthServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedAuthServiceServer struct {
+}
+
+func (*UnimplementedAuthServiceServer) Auth(ctx context.Context, req *AuthReq) (*AuthResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Auth not implemented")
+}
+
func RegisterAuthServiceServer(s *grpc.Server, srv AuthServiceServer) {
s.RegisterService(&_AuthService_serviceDesc, srv)
}
diff --git a/proto/auth/authdb_service.pb.go b/proto/auth/authdb_service.pb.go
index 1bfeb09..6cfc35b 100644
--- a/proto/auth/authdb_service.pb.go
+++ b/proto/auth/authdb_service.pb.go
@@ -8,6 +8,8 @@
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
math "math"
)
@@ -73,6 +75,14 @@
CheckMembership(context.Context, *CheckMembershipReq) (*CheckMembershipResp, error)
}
+// UnimplementedAuthDBServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedAuthDBServiceServer struct {
+}
+
+func (*UnimplementedAuthDBServiceServer) CheckMembership(ctx context.Context, req *CheckMembershipReq) (*CheckMembershipResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method CheckMembership not implemented")
+}
+
func RegisterAuthDBServiceServer(s *grpc.Server, srv AuthDBServiceServer) {
s.RegisterService(&_AuthDBService_serviceDesc, srv)
}
diff --git a/proto/cache/cache_service.pb.go b/proto/cache/cache_service.pb.go
index 30a7f60..e856ad6 100644
--- a/proto/cache/cache_service.pb.go
+++ b/proto/cache/cache_service.pb.go
@@ -8,6 +8,8 @@
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
math "math"
)
@@ -83,6 +85,17 @@
Put(context.Context, *PutReq) (*PutResp, error)
}
+// UnimplementedCacheServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedCacheServiceServer struct {
+}
+
+func (*UnimplementedCacheServiceServer) Get(ctx context.Context, req *GetReq) (*GetResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
+}
+func (*UnimplementedCacheServiceServer) Put(ctx context.Context, req *PutReq) (*PutResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Put not implemented")
+}
+
func RegisterCacheServiceServer(s *grpc.Server, srv CacheServiceServer) {
s.RegisterService(&_CacheService_serviceDesc, srv)
}
diff --git a/proto/exec/exec_service.pb.go b/proto/exec/exec_service.pb.go
index bae446b..cfa34f3 100644
--- a/proto/exec/exec_service.pb.go
+++ b/proto/exec/exec_service.pb.go
@@ -9,6 +9,8 @@
proto "github.com/golang/protobuf/proto"
api "go.chromium.org/goma/server/proto/api"
grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
math "math"
)
@@ -144,6 +146,14 @@
Exec(context.Context, *api.ExecReq) (*api.ExecResp, error)
}
+// UnimplementedExecServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedExecServiceServer struct {
+}
+
+func (*UnimplementedExecServiceServer) Exec(ctx context.Context, req *api.ExecReq) (*api.ExecResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Exec not implemented")
+}
+
func RegisterExecServiceServer(s *grpc.Server, srv ExecServiceServer) {
s.RegisterService(&_ExecService_serviceDesc, srv)
}
diff --git a/proto/execlog/log_service.pb.go b/proto/execlog/log_service.pb.go
index 2cd6d32..1384f2d 100644
--- a/proto/execlog/log_service.pb.go
+++ b/proto/execlog/log_service.pb.go
@@ -9,6 +9,8 @@
proto "github.com/golang/protobuf/proto"
api "go.chromium.org/goma/server/proto/api"
grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
math "math"
)
@@ -75,6 +77,14 @@
SaveLog(context.Context, *api.SaveLogReq) (*api.SaveLogResp, error)
}
+// UnimplementedLogServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedLogServiceServer struct {
+}
+
+func (*UnimplementedLogServiceServer) SaveLog(ctx context.Context, req *api.SaveLogReq) (*api.SaveLogResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SaveLog not implemented")
+}
+
func RegisterLogServiceServer(s *grpc.Server, srv LogServiceServer) {
s.RegisterService(&_LogService_serviceDesc, srv)
}
diff --git a/proto/file/file_service.pb.go b/proto/file/file_service.pb.go
index 7d00e6a..990b420 100644
--- a/proto/file/file_service.pb.go
+++ b/proto/file/file_service.pb.go
@@ -9,6 +9,8 @@
proto "github.com/golang/protobuf/proto"
api "go.chromium.org/goma/server/proto/api"
grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
math "math"
)
@@ -87,6 +89,17 @@
LookupFile(context.Context, *api.LookupFileReq) (*api.LookupFileResp, error)
}
+// UnimplementedFileServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedFileServiceServer struct {
+}
+
+func (*UnimplementedFileServiceServer) StoreFile(ctx context.Context, req *api.StoreFileReq) (*api.StoreFileResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method StoreFile not implemented")
+}
+func (*UnimplementedFileServiceServer) LookupFile(ctx context.Context, req *api.LookupFileReq) (*api.LookupFileResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method LookupFile not implemented")
+}
+
func RegisterFileServiceServer(s *grpc.Server, srv FileServiceServer) {
s.RegisterService(&_FileService_serviceDesc, srv)
}
diff --git a/proto/settings/settings_service.pb.go b/proto/settings/settings_service.pb.go
index 77475e9..c1d5b39 100644
--- a/proto/settings/settings_service.pb.go
+++ b/proto/settings/settings_service.pb.go
@@ -8,6 +8,8 @@
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
math "math"
)
@@ -72,6 +74,14 @@
Get(context.Context, *SettingsReq) (*SettingsResp, error)
}
+// UnimplementedSettingsServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedSettingsServiceServer struct {
+}
+
+func (*UnimplementedSettingsServiceServer) Get(ctx context.Context, req *SettingsReq) (*SettingsResp, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
+}
+
func RegisterSettingsServiceServer(s *grpc.Server, srv SettingsServiceServer) {
s.RegisterService(&_SettingsService_serviceDesc, srv)
}
diff --git a/remoteexec/adapter.go b/remoteexec/adapter.go
index 489b9ba..ec73df0 100644
--- a/remoteexec/adapter.go
+++ b/remoteexec/adapter.go
@@ -110,9 +110,10 @@
if err != nil {
return nil, err
}
+ // https://github.com/bazelbuild/remote-apis/blob/a5c577357528b33a4adff88c0c7911dd086c6923/build/bazel/remote/execution/v2/remote_execution.proto#L1460
// https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md#storing-binary-data-in-metadata
return metadata.AppendToOutgoingContext(ctx,
- "google.devtools.remoteexecution.v1test.requestmetadata-bin",
+ "build.bazel.remote.execution.v2.requestmetadata-bin",
string(b)), nil
}
diff --git a/remoteexec/adapter_test.go b/remoteexec/adapter_test.go
index 3f31caf..647e055 100644
--- a/remoteexec/adapter_test.go
+++ b/remoteexec/adapter_test.go
@@ -936,7 +936,7 @@
// files and executables might contain extra "out/Release/run.sh".
wantFiles := []string{"out/Release/run.sh", "bin/clang", "include/hello.h", "src/hello.c"}
- wantExecutables := []string{"bin/clang"}
+ wantExecutables := []string{"bin/clang", "out/Release/run.sh"}
for _, f := range wantFiles {
if !files[f].isFile {
@@ -1049,10 +1049,6 @@
Value: "/b/c/w",
},
{
- Name: "PWD",
- Value: "/b/c/w/out/Debug",
- },
- {
Name: "WORK_DIR",
Value: "out/Debug",
},
@@ -1071,8 +1067,8 @@
}
// files and executables might contain extra "out/Release/run.sh".
- wantFiles := []string{"out/Debug/run.sh", "bin/clang", "include/hello.h", "src/hello.c"}
- wantExecutables := []string{"bin/clang"}
+ wantFiles := []string{"out/Debug/run.sh", "out/Debug/env_file_for_docker", "bin/clang", "include/hello.h", "src/hello.c"}
+ wantExecutables := []string{"bin/clang", "out/Debug/run.sh"}
for _, f := range wantFiles {
if !files[f].isFile {
@@ -1088,6 +1084,9 @@
if got, want := files["out/Debug/run.sh"].digest, digest.Bytes("wrapper-script", []byte(wrapperScript)).Digest(); !proto.Equal(got, want) {
t.Errorf("digest of out/Debug/run.sh: %s != %s", got, want)
}
+ if got, want := files["out/Debug/env_file_for_docker"].digest, digest.Bytes("envfile", []byte("PWD=/b/c/w/out/Debug")).Digest(); !proto.Equal(got, want) {
+ t.Errorf("digest of out/Debug/env_file_for_docker: %s != %s", got, want)
+ }
}
func TestAdapterDockerProperties(t *testing.T) {
diff --git a/remoteexec/client.go b/remoteexec/client.go
index e691349..3e3f991 100644
--- a/remoteexec/client.go
+++ b/remoteexec/client.go
@@ -226,35 +226,46 @@
logger.Errorf("%s", err)
return err
}
- return erespErr(resp)
+ return erespErr(ctx, resp)
}
})
recordFinish()
+ if err == nil {
+ err = status.FromProto(resp.GetStatus()).Err()
+ }
return opName, resp, err
}
// erespErr returns codes.Unavailable if it has retriable failure result.
// returns nil otherwise (to terminates retrying, even if eresp contains
// error status).
-func erespErr(eresp *rpb.ExecuteResponse) error {
+func erespErr(ctx context.Context, eresp *rpb.ExecuteResponse) error {
+ logger := log.FromContext(ctx)
st := eresp.GetStatus()
- // see bazel remote retrier.
- // https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/remote/RemoteRetrier.java
- // also see https://cloud.google.com/pubsub/docs/reference/error-codes
+ // https://github.com/bazelbuild/remote-apis/blob/e7282cf0f0e16e7ba84209be5417279e6815bee7/build/bazel/remote/execution/v2/remote_execution.proto#L83
+ // FAILED_PRECONDITION:
+ // one or more errors occured in setting up the action
+ // requested, such as a missing input or command or
+ // no worker being available. The client may be able to
+ // fix the errors and retry.
+ // UNAVAILABLE:
+ // Due to transient condition, such as all workers being
+ // occupied (and the server does not support a queue), the
+ // action could not be started. The client should retry.
//
- // we don't retry codes.Unauthenticated; end user's access token would
- // be expired, so retry also get unauthenticated (we don't have
- // refresh token).
- //
- // codes.DeadlineExceeded might fail soon with codes.DeadlineExceeded,
- // but if server side sets shorter deadline and caller has more time
- // in context, retry would succeed.
+ // Other error would be non retriable.
switch codes.Code(st.GetCode()) {
- case codes.Unknown, codes.DeadlineExceeded, codes.Aborted, codes.Internal, codes.Unavailable, codes.ResourceExhausted:
+ case codes.OK:
+ case codes.FailedPrecondition:
+ logger.Warnf("execute response: failed precondition: %s", st)
+ fallthrough
+ case codes.Unavailable:
st = proto.Clone(st).(*spb.Status)
// codes.Unavailable, so that rpc.Retry will retry.
st.Code = int32(codes.Unavailable)
return status.FromProto(st).Err()
+ default:
+ logger.Errorf("execute response: error %s", st)
}
return nil
}
diff --git a/remoteexec/exec.go b/remoteexec/exec.go
index 0fc0164..f88ca88 100644
--- a/remoteexec/exec.go
+++ b/remoteexec/exec.go
@@ -202,15 +202,12 @@
}
func (r *request) addPlatformProperty(ctx context.Context, name, value string) {
- logger := log.FromContext(ctx)
for _, p := range r.platform.Properties {
if p.Name == name {
- logger.Infof("platform property update %s: %s->%s", name, p.Value, value)
p.Value = value
return
}
}
- logger.Infof("platform property add %s: %s", name, value)
r.platform.Properties = append(r.platform.Properties, &rpb.Platform_Property{
Name: name,
Value: value,
@@ -579,13 +576,13 @@
exit 1
fi
-# PWD might be /proc/self/cwd, but we need actual path for
-# INPUT_ROOT_DIR and WORK_DIR, so we can't use PWD for --workdir.
+# TODO: use PWD instead of INPUT_ROOT_DIR if appricable.
docker run \
-u "$(id -u)" \
--volume "${rundir}:${INPUT_ROOT_DIR}" \
--workdir "${INPUT_ROOT_DIR}/${WORK_DIR}" \
+ --env-file "${WORK_DIR}/env_file_for_docker" \
--rm \
"$image" \
"$@"
@@ -627,21 +624,22 @@
var files []fileDesc
args := buildArgs(ctx, cmdConfig, argv0, r.gomaReq)
+ // TODO: only allow whitelisted envs.
pathType := cmdConfig.GetCmdDescriptor().GetSetup().GetPathType()
+ const posixWrapperName = "run.sh"
switch pathType {
case cmdpb.CmdDescriptor_POSIX:
if r.needChroot {
logger.Infof("run with chroot")
- envs = append(envs, r.gomaReq.Env...)
// needed for bind mount.
r.addPlatformProperty(ctx, "dockerPrivileged", "true")
// needed for chroot command and mount command.
r.addPlatformProperty(ctx, "dockerRunAsRoot", "true")
- nsjailCfg := nsjailConfig(cwd)
+ nsjailCfg := nsjailConfig(cwd, r.filepath, r.gomaReq.GetToolchainSpecs(), r.gomaReq.Env)
files = []fileDesc{
{
- name: "run.sh",
+ name: posixWrapperName,
data: digest.Bytes("nsjail-run-wrapper-script", []byte(nsjailRunWrapperScript)),
isExecutable: true,
},
@@ -651,17 +649,25 @@
},
}
} else {
- var d digest.Data
err = cwdAgnosticReq(ctx, cmdConfig, r.filepath, r.gomaReq.Arg, r.gomaReq.Env)
if err != nil {
logger.Infof("non cwd agnostic: %v", err)
- d = digest.Bytes("wrapper-script", []byte(wrapperScript))
envs = append(envs, fmt.Sprintf("INPUT_ROOT_DIR=%s", r.tree.RootDir()))
- envs = append(envs, r.gomaReq.Env...)
+
r.addPlatformProperty(ctx, "dockerSiblingContainers", "true")
+ files = []fileDesc{
+ {
+ name: posixWrapperName,
+ data: digest.Bytes("wrapper-script", []byte(wrapperScript)),
+ isExecutable: true,
+ },
+ {
+ name: "env_file_for_docker",
+ data: digest.Bytes("envfile", []byte(strings.Join(r.gomaReq.Env, "\n"))),
+ },
+ }
} else {
logger.Infof("cwd agnostic")
- d = digest.Bytes("cwd-agnostic-wrapper-script", []byte(cwdAgnosticWrapperScript))
for _, e := range r.gomaReq.Env {
if strings.HasPrefix(e, "PWD=") {
// PWD is usually absolute path.
@@ -671,13 +677,13 @@
}
envs = append(envs, e)
}
- }
- files = []fileDesc{
- {
- name: "run.sh",
- data: d,
- isExecutable: true,
- },
+ files = []fileDesc{
+ {
+ name: posixWrapperName,
+ data: digest.Bytes("cwd-agnostic-wrapper-script", []byte(cwdAgnosticWrapperScript)),
+ isExecutable: true,
+ },
+ }
}
}
case cmdpb.CmdDescriptor_WINDOWS:
@@ -721,14 +727,9 @@
// if a wrapper exists in cwd, `wrapper` does not have a directory name.
// It cannot be callable on POSIX because POSIX do not contain "." in
- // its PATH. Although "." is included in PATH on Windows, there can be
- // a risk unexpected scripts with the same name would be called.
- // Let's avoid the situation with explicitly specifying the directory
- // name i.e. ".".
- if r.filepath.Base(wrapperPath) == wrapperPath {
- // Since Join omit "." and this is only the case Join must not
- // omit ".", we need to join by ourselves here.
- wrapperPath = "." + r.filepath.PathSep() + wrapperPath
+ // its PATH.
+ if wrapperPath == posixWrapperName {
+ wrapperPath = "./" + posixWrapperName
}
r.args = append([]string{wrapperPath}, args...)
return nil
@@ -831,7 +832,7 @@
return
}
logger := log.FromContext(ctx)
- logger.Infof("command digest: %v %s", data.Digest(), command)
+ logger.Infof("command digest: %v", data.Digest())
r.digestStore.Set(data)
r.action.CommandDigest = data.Digest()
diff --git a/remoteexec/nsjail.go b/remoteexec/nsjail.go
index 455c97e..c86532c 100644
--- a/remoteexec/nsjail.go
+++ b/remoteexec/nsjail.go
@@ -5,8 +5,12 @@
package remoteexec
import (
+ "sort"
+ "strings"
+
"github.com/golang/protobuf/proto"
+ gomapb "go.chromium.org/goma/server/proto/api"
nsjailpb "go.chromium.org/goma/server/proto/nsjail"
)
@@ -48,8 +52,9 @@
# directory will be mounted by nsjail later.
mkdir -p "$chroot_workdir/$d"
done
-# needed to make nsjail bind /dev/urandom.
+# needed to make nsjail bind device files.
touch "$chroot_workdir/dev/urandom"
+touch "$chroot_workdir/dev/null"
# currently running with root. run the command with nobody:nogroup with chroot.
# We use nsjail to chdir without running bash script inside chroot, and
@@ -58,10 +63,33 @@
`
)
+// pathFromToolchainSpec returns ':'-joined directories of paths in toolchain spec.
+// Since symlinks may point to executables, having directories with executables
+// may not work, but it is a bit cumbersome to analyze symlinks.
+// Also, having library directories in PATH should be harmless because
+// the Goma client may not include multiple subprograms with the same name.
+func pathFromToolchainSpec(cfp clientFilePath, ts []*gomapb.ToolchainSpec) string {
+ m := make(map[string]bool)
+ for _, e := range ts {
+ m[cfp.Dir(e.GetPath())] = true
+ }
+ var r []string
+ for k := range m {
+ if k == "" || k == "." {
+ continue
+ }
+ r = append(r, k)
+ }
+ // This function must return the same result for the same input, but go
+ // does not guarantee the iteration order.
+ sort.Strings(r)
+ return strings.Join(r, ":")
+}
+
// nsjailConfig returns nsjail configuration.
// When you modify followings, please make sure it matches
// nsjailRunWrapperScript above.
-func nsjailConfig(cwd string) []byte {
+func nsjailConfig(cwd string, cfp clientFilePath, ts []*gomapb.ToolchainSpec, envs []string) []byte {
chrootWorkdir := "/tmp/goma_chroot"
cfg := &nsjailpb.NsJailConfig{
Uidmap: []*nsjailpb.IdMap{
@@ -85,6 +113,12 @@
IsDir: proto.Bool(true),
},
{
+ Src: proto.String("/dev/null"),
+ Dst: proto.String("/dev/null"),
+ Rw: proto.Bool(true),
+ IsBind: proto.Bool(true),
+ },
+ {
Src: proto.String("/dev/urandom"),
Dst: proto.String("/dev/urandom"),
IsBind: proto.Bool(true),
@@ -94,15 +128,16 @@
// TODO: use log file and print to server log.
LogLevel: nsjailpb.LogLevel_WARNING.Enum(),
MountProc: proto.Bool(true),
- Envar: []string{
- // HACK: ChromeOS clang wrapper needs this.
- // https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/f15eab2d792acfe1ee5eca4d95792c081558cf84/sys-devel/gcc/files/sysroot_wrapper.body#69
- // TODO: set better path upon needs.
- // e.g. auto generate from where executables and symlink
- // to executable exists, or choose directories with
- // executables from PATH sent by clients.
- "PATH=",
- },
+ Envar: append(
+ []string{
+ "PATH=" + pathFromToolchainSpec(cfp, ts),
+ // Dummy home directory is needed by pnacl-clang to
+ // import site.py to import user-defined python
+ // packages.
+ "HOME=/",
+ },
+ // Add client-side environemnt to execution environment.
+ envs...),
RlimitAsType: nsjailpb.RLimit_INF.Enum(),
RlimitFsizeType: nsjailpb.RLimit_INF.Enum(),
// TODO: relax RLimit from the default.
diff --git a/remoteexec/nsjail_test.go b/remoteexec/nsjail_test.go
new file mode 100644
index 0000000..f9bc831
--- /dev/null
+++ b/remoteexec/nsjail_test.go
@@ -0,0 +1,133 @@
+// Copyright 2019 The Goma 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 remoteexec
+
+import (
+ "testing"
+
+ "github.com/golang/protobuf/proto"
+
+ "go.chromium.org/goma/server/command/descriptor/posixpath"
+ gomapb "go.chromium.org/goma/server/proto/api"
+)
+
+func TestPathFromToolchainSpec(t *testing.T) {
+ for _, tc := range []struct {
+ desc string
+ cfp clientFilePath
+ ts []*gomapb.ToolchainSpec
+ want string
+ }{
+ {
+ desc: "empty",
+ cfp: posixpath.FilePath{},
+ ts: nil,
+ want: "",
+ },
+ {
+ desc: "one toolchain spec",
+ cfp: posixpath.FilePath{},
+ ts: []*gomapb.ToolchainSpec{
+ {
+ Path: proto.String("/usr/bin/clang"),
+ Hash: proto.String("fe4c1bb3b68376901c9f9e87dc1196a81f598eb854061ddfc5f85ef7e054feed"),
+ Size: proto.Int64(86003704),
+ IsExecutable: proto.Bool(true),
+ },
+ },
+ want: "/usr/bin",
+ },
+ {
+ desc: "toolchain spec in the same directory",
+ cfp: posixpath.FilePath{},
+ ts: []*gomapb.ToolchainSpec{
+ {
+ Path: proto.String("/usr/bin/clang"),
+ Hash: proto.String("fe4c1bb3b68376901c9f9e87dc1196a81f598eb854061ddfc5f85ef7e054feed"),
+ Size: proto.Int64(86003704),
+ IsExecutable: proto.Bool(true),
+ },
+ {
+ Path: proto.String("/usr/bin/clang++"),
+ SymlinkPath: proto.String("clang"),
+ },
+ },
+ want: "/usr/bin",
+ },
+ {
+ desc: "toolchain spec in the different directory",
+ cfp: posixpath.FilePath{},
+ ts: []*gomapb.ToolchainSpec{
+ {
+ Path: proto.String("/usr/bin/clang"),
+ Hash: proto.String("fe4c1bb3b68376901c9f9e87dc1196a81f598eb854061ddfc5f85ef7e054feed"),
+ Size: proto.Int64(86003704),
+ IsExecutable: proto.Bool(true),
+ },
+ {
+ Path: proto.String("/bin/bash"),
+ Hash: proto.String("d80e7ffe8836eb30bafb138def4c1a6e3f586d98ec39a26d9549a92141e95281"),
+ Size: proto.Int64(715328),
+ IsExecutable: proto.Bool(true),
+ },
+ },
+ want: "/bin:/usr/bin",
+ },
+ {
+ desc: "complexed",
+ cfp: posixpath.FilePath{},
+ ts: []*gomapb.ToolchainSpec{
+ {
+ Path: proto.String("../../native_client/toolchain/linux_x86/pnacl_newlib/bin/pnacl-clang++"),
+ Hash: proto.String("dummy"),
+ Size: proto.Int64(0),
+ IsExecutable: proto.Bool(true),
+ },
+ {
+ Path: proto.String("/home/goma/chrome_root/src/native_client/toolchain/linux_x86/pnacl_newlib/bin/clang"),
+ Hash: proto.String("dummy"),
+ Size: proto.Int64(0),
+ IsExecutable: proto.Bool(true),
+ },
+ {
+ // lib directory is also included.
+ Path: proto.String("/usr/lib64/python2.7/abc.py"),
+ Hash: proto.String("dummy"),
+ Size: proto.Int64(0),
+ },
+ {
+ Path: proto.String("/usr/bin/python"),
+ SymlinkPath: proto.String("python-wrapper"),
+ },
+ {
+ Path: proto.String("/usr/bin/python-wrapper"),
+ Hash: proto.String("dummy"),
+ Size: proto.Int64(0),
+ IsExecutable: proto.Bool(true),
+ },
+ {
+ Path: proto.String("/usr/bin/bash"),
+ Hash: proto.String("dummy"),
+ Size: proto.Int64(0),
+ IsExecutable: proto.Bool(true),
+ },
+ {
+ Path: proto.String("/lib64/libc-2.27.so"),
+ Hash: proto.String("dummy"),
+ Size: proto.Int64(0),
+ IsExecutable: proto.Bool(true),
+ },
+ },
+ want: "../../native_client/toolchain/linux_x86/pnacl_newlib/bin:/home/goma/chrome_root/src/native_client/toolchain/linux_x86/pnacl_newlib/bin:/lib64:/usr/bin:/usr/lib64/python2.7",
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ actual := pathFromToolchainSpec(tc.cfp, tc.ts)
+ if actual != tc.want {
+ t.Errorf("pathFromToolchainSpec(%v, %v) = %q; want %q", tc.cfp, tc.ts, actual, tc.want)
+ }
+ })
+ }
+}