mirrored from https://chromium.googlesource.com/infra/luci/luci-go
/
main.go
172 lines (142 loc) · 5.08 KB
/
main.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
// Copyright 2020 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 ledcli
import (
"context"
"fmt"
"os"
"os/signal"
"github.com/maruel/subcommands"
"go.chromium.org/luci/auth/client/authcli"
"go.chromium.org/luci/cipd/version"
"go.chromium.org/luci/client/versioncli"
"go.chromium.org/luci/common/cli"
"go.chromium.org/luci/common/data/rand/mathrand"
log "go.chromium.org/luci/common/logging"
"go.chromium.org/luci/common/logging/gologger"
"go.chromium.org/luci/hardcoded/chromeinfra"
"go.chromium.org/luci/led/job"
)
// userAgent is the HTTP user agent string for led.
var userAgent = "led 1.0.0"
func init() {
ver, err := version.GetStartupVersion()
if err != nil || ver.InstanceID == "" {
return
}
userAgent += fmt.Sprintf(" (%s@%s)", ver.PackageName, ver.InstanceID)
}
func handleInterruption(ctx context.Context) context.Context {
ctx, cancel := context.WithCancel(ctx)
signalC := make(chan os.Signal)
signal.Notify(signalC, os.Interrupt)
go func() {
interrupted := false
for range signalC {
if interrupted {
os.Exit(1)
}
interrupted = true
cancel()
}
}()
return ctx
}
// Main executes the entire 'led' command line program, including argument
// parsing and exiting the binary.
//
// If you want to support 'kitchen' based swarming tasks, pass an implementation
// of `ks`. The only implementation of `ks` that matters is in the
// 'infra/tools/led2' package.
func Main(ks job.KitchenSupport) {
mathrand.SeedRandomly()
if ks == nil {
ks = job.NoKitchenSupport()
}
defaults := cmdBaseOptions{
authOpts: chromeinfra.DefaultAuthOptions(),
kitchenSupport: ks,
}
var application = cli.Application{
Name: "led",
Title: `'LUCI editor' - Multi-service LUCI job debugging tool.
Allows local modifications to LUCI jobs to be launched directly in swarming.
This is meant to aid in debugging and development for the interaction of
multiple LUCI services:
* buildbucket
* swarming
* isolate
* recipes
* logdog
* milo
This command is meant to be used multiple times in a pipeline. The flow is
generally:
get | edit* | launch
Where the edit step(s) are optional. The output of the commands on stdout is
a JobDefinition JSON document, and the input to the commands is this same
JobDefinition JSON document. At any stage in the pipeline, you may, of course,
hand-edit the JobDefinition.
Example:
led get-builder bucket_name:builder_name | \
led edit-recipe-bundle -O recipe_engine=/local/recipe_engine > job.json
# edit job.json by hand to inspect
led edit-system -e CHROME_HEADLESS=1 < job.json | \
led launch
This would pull the recipe job from the named swarming task, then isolate the
recipes from the current working directory (with an override for the
recipe_engine), and inject the isolate hash into the job, saving the result to
job.json. The user thens inspects job.json to look at the full set of flags and
features. After inspecting/editing the job, the user pipes it back through the
edit subcommand to set the swarming envvar $CHROME_HEADLESS=1, and then launches
the edited task back to swarming.
The source for led lives at:
https://chromium.googlesource.com/infra/infra/+/HEAD/go/src/infra/tools/led
The spec (as it is) for JobDefinition is at:
https://chromium.googlesource.com/infra/luci/luci-go/+/HEAD/led/job/job.proto
`,
Context: func(ctx context.Context) context.Context {
goLoggerCfg := gologger.LoggerConfig{Out: os.Stderr}
goLoggerCfg.Format = "[%{level:.1s} %{time:2006-01-02 15:04:05}] %{message}"
ctx = goLoggerCfg.Use(ctx)
ctx = (&log.Config{Level: log.Info}).Set(ctx)
return handleInterruption(ctx)
},
Commands: []*subcommands.Command{
// commands to obtain JobDescriptions. These all begin with `get`.
// TODO(iannucci): `get` to scrape from any URL
getSwarmCmd(defaults),
getBuildCmd(defaults),
getBuilderCmd(defaults),
// commands to edit JobDescriptions.
editCmd(defaults),
editSystemCmd(defaults),
editRecipeBundleCmd(defaults),
editCrCLCmd(defaults),
// commands to edit the raw isolated files.
editIsolated(defaults),
// commands to launch swarming tasks.
launchCmd(defaults),
// TODO(iannucci): launch-local to launch locally
// TODO(iannucci): launch-buildbucket to launch on buildbucket
{}, // spacer
subcommands.CmdHelp,
versioncli.CmdVersion(userAgent),
{}, // spacer
authcli.SubcommandLogin(defaults.authOpts, "auth-login", false),
authcli.SubcommandLogout(defaults.authOpts, "auth-logout", false),
authcli.SubcommandInfo(defaults.authOpts, "auth-info", false),
},
}
os.Exit(subcommands.Run(&application, nil))
}