| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package cli | 5 package cli |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "flag" | 8 "flag" |
| 9 "fmt" | 9 "fmt" |
| 10 "net/http" |
| 10 "os" | 11 "os" |
| 11 "os/signal" | 12 "os/signal" |
| 12 "strings" | 13 "strings" |
| 13 "time" | 14 "time" |
| 14 | 15 |
| 15 "github.com/maruel/subcommands" | 16 "github.com/maruel/subcommands" |
| 16 "golang.org/x/net/context" | 17 "golang.org/x/net/context" |
| 17 | 18 |
| 18 "github.com/luci/luci-go/client/authcli" | 19 "github.com/luci/luci-go/client/authcli" |
| 19 "github.com/luci/luci-go/common/auth" | 20 "github.com/luci/luci-go/common/auth" |
| 20 "github.com/luci/luci-go/common/cli" | 21 "github.com/luci/luci-go/common/cli" |
| 21 "github.com/luci/luci-go/common/clock/clockflag" | 22 "github.com/luci/luci-go/common/clock/clockflag" |
| 23 "github.com/luci/luci-go/common/errors" |
| 22 log "github.com/luci/luci-go/common/logging" | 24 log "github.com/luci/luci-go/common/logging" |
| 23 "github.com/luci/luci-go/common/logging/gologger" | 25 "github.com/luci/luci-go/common/logging/gologger" |
| 24 "github.com/luci/luci-go/grpc/prpc" | 26 "github.com/luci/luci-go/grpc/prpc" |
| 25 "github.com/luci/luci-go/logdog/client/coordinator" | 27 "github.com/luci/luci-go/logdog/client/coordinator" |
| 26 "github.com/luci/luci-go/logdog/common/types" | 28 "github.com/luci/luci-go/logdog/common/types" |
| 27 "github.com/luci/luci-go/luci_config/common/cfgtypes" | 29 "github.com/luci/luci-go/luci_config/common/cfgtypes" |
| 28 ) | 30 ) |
| 29 | 31 |
| 30 func init() { | 32 func init() { |
| 31 prpc.DefaultUserAgent = "logdog CLI" | 33 prpc.DefaultUserAgent = "logdog CLI" |
| (...skipping 22 matching lines...) Expand all Loading... |
| 54 | 56 |
| 55 // project is the project name. This may either be a valid project name
or | 57 // project is the project name. This may either be a valid project name
or |
| 56 // empty. Subcommands that support "unified" project-in-path paths shoul
d use | 58 // empty. Subcommands that support "unified" project-in-path paths shoul
d use |
| 57 // splitPath to get the project form the path. Those that don't should a
ssert | 59 // splitPath to get the project form the path. Those that don't should a
ssert |
| 58 // that this is non-empty. | 60 // that this is non-empty. |
| 59 project cfgtypes.ProjectName | 61 project cfgtypes.ProjectName |
| 60 authFlags authcli.Flags | 62 authFlags authcli.Flags |
| 61 insecure bool | 63 insecure bool |
| 62 timeout clockflag.Duration | 64 timeout clockflag.Duration |
| 63 | 65 |
| 64 » coord *coordinator.Client | 66 » // httpClient is an authenticated HTTP client to use for connections to
the |
| 67 » // Coordinator. |
| 68 » httpClient *http.Client |
| 65 } | 69 } |
| 66 | 70 |
| 67 func (a *application) addToFlagSet(ctx context.Context, fs *flag.FlagSet) { | 71 func (a *application) addToFlagSet(ctx context.Context, fs *flag.FlagSet) { |
| 68 fs.StringVar(&a.p.Host, "host", a.p.Host, | 72 fs.StringVar(&a.p.Host, "host", a.p.Host, |
| 69 "The LogDog Coordinator [host][:port].") | 73 "The LogDog Coordinator [host][:port].") |
| 70 fs.BoolVar(&a.insecure, "insecure", false, | 74 fs.BoolVar(&a.insecure, "insecure", false, |
| 71 "Use insecure transport for RPC.") | 75 "Use insecure transport for RPC.") |
| 72 fs.Var(&a.project, "project", | 76 fs.Var(&a.project, "project", |
| 73 "The log stream's project.") | 77 "The log stream's project.") |
| 74 | 78 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 96 } | 100 } |
| 97 | 101 |
| 98 if len(parts) == 2 { | 102 if len(parts) == 2 { |
| 99 p = parts[1] | 103 p = parts[1] |
| 100 } else { | 104 } else { |
| 101 p = "" | 105 p = "" |
| 102 } | 106 } |
| 103 return project, p, true, nil | 107 return project, p, true, nil |
| 104 } | 108 } |
| 105 | 109 |
| 110 func (a *application) resolveHost(host string) (string, error) { |
| 111 switch { |
| 112 case host != "": |
| 113 return host, nil |
| 114 case a.p.Host != "": |
| 115 return a.p.Host, nil |
| 116 default: |
| 117 return "", errors.New("a Coordinator host must be specified (-ho
st)") |
| 118 } |
| 119 } |
| 120 |
| 121 // coordinatorClient returns a Coordinator client for the specified host. If |
| 122 // no host is provided, the command-line host will be used. |
| 123 func (a *application) coordinatorClient(host string) (*coordinator.Client, error
) { |
| 124 host, err := a.resolveHost(host) |
| 125 if err != nil { |
| 126 return nil, errors.Annotate(err).Err() |
| 127 } |
| 128 |
| 129 // Get our Coordinator client instance. |
| 130 prpcClient := prpc.Client{ |
| 131 C: a.httpClient, |
| 132 Host: host, |
| 133 Options: prpc.DefaultOptions(), |
| 134 } |
| 135 prpcClient.Options.Insecure = a.insecure |
| 136 return coordinator.NewClient(&prpcClient), nil |
| 137 } |
| 138 |
| 106 func (a *application) timeoutCtx(c context.Context) (context.Context, context.Ca
ncelFunc) { | 139 func (a *application) timeoutCtx(c context.Context) (context.Context, context.Ca
ncelFunc) { |
| 107 if a.timeout <= 0 { | 140 if a.timeout <= 0 { |
| 108 return context.WithCancel(c) | 141 return context.WithCancel(c) |
| 109 } | 142 } |
| 110 return context.WithTimeout(c, time.Duration(a.timeout)) | 143 return context.WithTimeout(c, time.Duration(a.timeout)) |
| 111 } | 144 } |
| 112 | 145 |
| 113 // Main is the entry point for the CLI application. | 146 // Main is the entry point for the CLI application. |
| 114 func Main(ctx context.Context, params Parameters) int { | 147 func Main(ctx context.Context, params Parameters) int { |
| 115 ctx = gologger.StdConfig.Use(ctx) | 148 ctx = gologger.StdConfig.Use(ctx) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 127 subcommands.CmdHelp, | 160 subcommands.CmdHelp, |
| 128 newCatCommand(), | 161 newCatCommand(), |
| 129 newQueryCommand(), | 162 newQueryCommand(), |
| 130 newListCommand(), | 163 newListCommand(), |
| 131 newLatestCommand(), | 164 newLatestCommand(), |
| 132 authcli.SubcommandLogin(authOptions, "auth-login
", false), | 165 authcli.SubcommandLogin(authOptions, "auth-login
", false), |
| 133 authcli.SubcommandLogout(authOptions, "auth-logo
ut", false), | 166 authcli.SubcommandLogout(authOptions, "auth-logo
ut", false), |
| 134 authcli.SubcommandInfo(authOptions, "auth-info",
false), | 167 authcli.SubcommandInfo(authOptions, "auth-info",
false), |
| 135 }, | 168 }, |
| 136 }, | 169 }, |
| 137 » » p: params, | 170 » » p: params, |
| 171 » » authFlags: authcli.Flags{}, |
| 138 } | 172 } |
| 139 loggingConfig := log.Config{ | 173 loggingConfig := log.Config{ |
| 140 Level: log.Level(log.Info), | 174 Level: log.Level(log.Info), |
| 141 } | 175 } |
| 142 | 176 |
| 143 flags := &flag.FlagSet{} | 177 flags := &flag.FlagSet{} |
| 144 a.addToFlagSet(ctx, flags) | 178 a.addToFlagSet(ctx, flags) |
| 145 loggingConfig.AddFlags(flags) | 179 loggingConfig.AddFlags(flags) |
| 146 a.authFlags.Register(flags, authOptions) | 180 a.authFlags.Register(flags, authOptions) |
| 147 | 181 |
| 148 // Parse flags. | 182 // Parse flags. |
| 149 if err := flags.Parse(params.Args); err != nil { | 183 if err := flags.Parse(params.Args); err != nil { |
| 150 log.Errorf(log.SetError(ctx, err), "Failed to parse command-line
.") | 184 log.Errorf(log.SetError(ctx, err), "Failed to parse command-line
.") |
| 151 return 1 | 185 return 1 |
| 152 } | 186 } |
| 153 | 187 |
| 154 // Install our log formatter. | 188 // Install our log formatter. |
| 155 ctx = loggingConfig.Set(ctx) | 189 ctx = loggingConfig.Set(ctx) |
| 156 | 190 |
| 157 if a.p.Host == "" { | |
| 158 log.Errorf(ctx, "Missing coordinator host (-host).") | |
| 159 return 1 | |
| 160 } | |
| 161 | |
| 162 // Signal handler will cancel our context when interrupted. | 191 // Signal handler will cancel our context when interrupted. |
| 163 ctx, cancelFunc := context.WithCancel(ctx) | 192 ctx, cancelFunc := context.WithCancel(ctx) |
| 164 signalC := make(chan os.Signal) | 193 signalC := make(chan os.Signal) |
| 165 signal.Notify(signalC, os.Interrupt, os.Kill) | 194 signal.Notify(signalC, os.Interrupt, os.Kill) |
| 166 go func() { | 195 go func() { |
| 167 triggered := false | 196 triggered := false |
| 168 for sig := range signalC { | 197 for sig := range signalC { |
| 169 if triggered { | 198 if triggered { |
| 170 os.Exit(2) | 199 os.Exit(2) |
| 171 } | 200 } |
| 172 | 201 |
| 173 triggered = true | 202 triggered = true |
| 174 log.Fields{ | 203 log.Fields{ |
| 175 "signal": sig, | 204 "signal": sig, |
| 176 }.Warningf(ctx, "Caught signal; terminating.") | 205 }.Warningf(ctx, "Caught signal; terminating.") |
| 177 cancelFunc() | 206 cancelFunc() |
| 178 } | 207 } |
| 179 }() | 208 }() |
| 180 defer func() { | 209 defer func() { |
| 181 signal.Stop(signalC) | 210 signal.Stop(signalC) |
| 182 close(signalC) | 211 close(signalC) |
| 183 }() | 212 }() |
| 184 | 213 |
| 185 // Instantiate our authenticated HTTP client. | 214 // Instantiate our authenticated HTTP client. |
| 186 authOpts, err := a.authFlags.Options() | 215 authOpts, err := a.authFlags.Options() |
| 187 if err != nil { | 216 if err != nil { |
| 188 log.Errorf(log.SetError(ctx, err), "Failed to create auth option
s.") | 217 log.Errorf(log.SetError(ctx, err), "Failed to create auth option
s.") |
| 189 return 1 | 218 return 1 |
| 190 } | 219 } |
| 191 » httpClient, err := auth.NewAuthenticator(ctx, auth.OptionalLogin, authOp
ts).Client() | 220 |
| 192 » if err != nil { | 221 » if a.httpClient, err = auth.NewAuthenticator(ctx, auth.OptionalLogin, au
thOpts).Client(); err != nil { |
| 193 log.Errorf(log.SetError(ctx, err), "Failed to create authenticat
ed client.") | 222 log.Errorf(log.SetError(ctx, err), "Failed to create authenticat
ed client.") |
| 194 return 1 | 223 return 1 |
| 195 } | 224 } |
| 196 | 225 |
| 197 // Get our Coordinator client instance. | |
| 198 prpcClient := &prpc.Client{ | |
| 199 C: httpClient, | |
| 200 Host: a.p.Host, | |
| 201 Options: prpc.DefaultOptions(), | |
| 202 } | |
| 203 prpcClient.Options.Insecure = a.insecure | |
| 204 | |
| 205 a.coord = coordinator.NewClient(prpcClient) | |
| 206 a.Context = ctx | 226 a.Context = ctx |
| 207 return subcommands.Run(&a, flags.Args()) | 227 return subcommands.Run(&a, flags.Args()) |
| 208 } | 228 } |
| OLD | NEW |