mirrored from https://chromium.googlesource.com/infra/luci/luci-go
-
Notifications
You must be signed in to change notification settings - Fork 43
/
options.go
206 lines (178 loc) · 6.12 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright 2019 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package host
import (
"context"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"go.chromium.org/luci/auth"
"go.chromium.org/luci/auth/authctx"
bbpb "go.chromium.org/luci/buildbucket/proto"
"go.chromium.org/luci/common/errors"
"go.chromium.org/luci/common/logging"
"go.chromium.org/luci/hardcoded/chromeinfra"
ldOutput "go.chromium.org/luci/logdog/client/butler/output"
"go.chromium.org/luci/logdog/client/butler/output/null"
"go.chromium.org/luci/logdog/client/butlerlib/streamproto"
)
// Options is an optional struct which allows you to control how Run operates.
type Options struct {
// Where the butler will sink its data to.
//
// This is typically one of the implementations in
// go.chromium.org/luci/logdog/client/butler/output.
//
// If nil, will use the 'null' logdog Output.
LogdogOutput ldOutput.Output
// Butler is VERY noisy at debug level, potentially amplifying client writes
// by up to two orders of magnitude.
//
// If this is higher than the log level in the context, this will be applied
// to the butler agent.
ButlerLogLevel logging.Level
// If set, enables logging at context level for the butler streamserver.
// If unset (the default), logging in the butler streamserver is set to
// Warning.
//
// Streamsever logging is generally redundant with the butler logs at level
// Info or Debug.
StreamServerDisableLogAdjustment bool
// ExeAuth describes the LUCI Auth environment to run the user code within.
//
// `Run` will manage the lifecycle of ExeAuth entirely.
//
// If nil, defaults to `DefaultExeAuth("luciexe", nil)`.
//
// It's recommended to use DefaultExeAuth() explicitly with reasonable values
// for `id` and `knownGerritHosts`.
ExeAuth *authctx.Context
// The BaseDir becomes the root of this hosted luciexe session; All
// directories (workdirs, tempdirs, etc.) are derived relative to this.
//
// If not provided, Run will pick a random directory under os.TempDir as the
// value for BaseDir.
//
// The BaseDir (provided or picked) will be managed by Run; Prior to
// execution, Run will ensure that the directory is empty by removing its
// contents.
BaseDir string
// The base Build message to use as the template for all merged Build
// messages.
BaseBuild *bbpb.Build
// If LeakBaseDir is true, Run will not try to remove BaseDir at the end if
// it's execution.
//
// If BaseDir is not provided, this must be false.
LeakBaseDir bool
// The viewer URL for this hosted execution (if any). This will be used to
// apply the "logdog.viewer_url" tag to all logdog streams (the tag which is
// used to implement the "Back to build" link in Milo).
ViewerURL string
authDir string
lucictxDir string
streamServerPath string
logdogTags streamproto.TagMap
}
// The function below is in `var name = func` form so that it shows up in godoc.
// DefaultExeAuth returns a copy of the default value for Options.ExeAuth.
var DefaultExeAuth = func(id string, knownGerritHosts []string) *authctx.Context {
return &authctx.Context{
ID: id,
Options: chromeinfra.SetDefaultAuthOptions(auth.Options{
Scopes: []string{
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/gerritcodereview",
"https://www.googleapis.com/auth/firebase",
},
}),
EnableGitAuth: true,
EnableGCEEmulation: true,
EnableDockerAuth: true,
EnableFirebaseAuth: true,
KnownGerritHosts: knownGerritHosts,
}
}
type pathToMake struct {
path string // unique directory name under BaseDir
name string // human readable name of this dir (i.e. it's purpose)
dest *string // output destination in Options struct
}
func (p pathToMake) create(base string) error {
*p.dest = filepath.Join(base, p.path)
return errors.Annotate(os.Mkdir(*p.dest, 0777), "making %q dir", p.name).Err()
}
func (o *Options) initialize() (err error) {
if o.BaseDir == "" {
if o.LeakBaseDir {
return errors.New("BaseDir was provided but LeakBaseDir == true")
}
o.BaseDir, err = ioutil.TempDir("", "luciexe-host-")
if err != nil {
return errors.Annotate(err, "Cannot create BaseDir").Err()
}
} else {
if o.BaseDir, err = filepath.Abs(o.BaseDir); err != nil {
return errors.Annotate(err, "resolving BaseDir").Err()
}
if err := os.RemoveAll(o.BaseDir); err != nil && !os.IsNotExist(err) {
return errors.Annotate(err, "clearing options.BaseDir").Err()
}
if err := os.Mkdir(o.BaseDir, 0777); err != nil {
return errors.Annotate(err, "creating options.BaseDir").Err()
}
}
if o.BaseBuild == nil {
o.BaseBuild = &bbpb.Build{}
}
pathsToMake := []pathToMake{
{"a", "auth", &o.authDir},
{"l", "luci context", &o.lucictxDir},
}
if runtime.GOOS != "windows" {
pathsToMake = append(
pathsToMake, pathToMake{"ld", "logdog socket", &o.streamServerPath})
} else {
o.streamServerPath = "luciexe/host"
}
merr := errors.NewLazyMultiError(len(pathsToMake))
for i, paths := range pathsToMake {
merr.Assign(i, paths.create(o.BaseDir))
}
if err := merr.Get(); err != nil {
return err
}
if runtime.GOOS != "windows" {
o.streamServerPath = filepath.Join(o.streamServerPath, "sock")
}
if o.LogdogOutput == nil {
o.LogdogOutput = &null.Output{}
}
if o.ExeAuth == nil {
o.ExeAuth = DefaultExeAuth("luciexe", nil)
}
if o.ViewerURL != "" {
o.logdogTags = streamproto.TagMap{"logdog.viewer_url": o.ViewerURL}
}
return nil
}
func (o *Options) cleanup(ctx context.Context) {
if !o.LeakBaseDir {
if err := os.RemoveAll(o.BaseDir); err != nil {
logging.WithError(err).Errorf(ctx, "removing BaseDir")
}
}
}