blob: aeffe13b72880c0466beb29bba6bbc3cbd82ab65 [file] [log] [blame]
// Copyright 2018 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 swarmingimpl
import (
"context"
"flag"
"fmt"
"github.com/maruel/subcommands"
"go.chromium.org/luci/client/cmd/swarming/swarmingimpl/base"
"go.chromium.org/luci/client/cmd/swarming/swarmingimpl/output"
"go.chromium.org/luci/common/errors"
luciflag "go.chromium.org/luci/common/flag"
"go.chromium.org/luci/common/flag/stringmapflag"
"go.chromium.org/luci/swarming/client/swarming"
swarmingv2 "go.chromium.org/luci/swarming/proto/api_v2"
)
// CmdBots returns an object for the `bots` subcommand.
func CmdBots(authFlags base.AuthFlags) *subcommands.Command {
return &subcommands.Command{
UsageLine: "bots -S <server>",
ShortDesc: "lists or counts bots matching a filter",
LongDesc: "Lists or counts bots matching a filter.",
CommandRun: func() subcommands.CommandRun {
return base.NewCommandRun(authFlags, &botsImpl{}, base.Features{
MinArgs: 0,
MaxArgs: 0,
OutputJSON: base.OutputJSON{
Enabled: true,
DeprecatedAliasFlag: "json",
DefaultToStdout: true,
},
})
},
}
}
// TODO(crbug.com/1467263): `fields` do nothing currently. Used to be a set of
// fields to include in a partial response.
type botsImpl struct {
dimensions stringmapflag.Value
fields []string
count bool
botIDOnly bool
}
func (cmd *botsImpl) RegisterFlags(fs *flag.FlagSet) {
fs.Var(&cmd.dimensions, "dimension", "Dimension to select the right kind of bot. In the form of `key=value`.")
fs.Var(luciflag.StringSlice(&cmd.fields), "field", "This flag currently does nothing (https://crbug.com/1467263).")
fs.BoolVar(&cmd.count, "count", false, "Report the count of bots instead of listing them.")
fs.BoolVar(&cmd.botIDOnly, "bare", false, "Print bot IDs to stdout as a list.")
}
func (cmd *botsImpl) ParseInputs(args []string, env subcommands.Env) error {
if cmd.count && len(cmd.fields) > 0 {
return errors.Reason("-field cannot be used with -count").Err()
}
if cmd.count && cmd.botIDOnly {
return errors.Reason("-bare cannot be used with -count").Err()
}
return nil
}
func (cmd *botsImpl) Execute(ctx context.Context, svc swarming.Client, sink *output.Sink, extra base.Extra) error {
// TODO(vadimsh): Reuse from utils.
dims := make([]*swarmingv2.StringPair, 0, len(cmd.dimensions))
for k, v := range cmd.dimensions {
dims = append(dims, &swarmingv2.StringPair{
Key: k,
Value: v,
})
}
if cmd.count {
count, err := svc.CountBots(ctx, dims)
if err != nil {
return err
}
return output.Proto(sink, count)
}
bots, err := svc.ListBots(ctx, dims)
if err != nil {
return err
}
if cmd.botIDOnly {
for _, bot := range bots {
fmt.Fprintln(extra.Stdout, bot.GetBotId())
}
// Skip writing JSON to the stdout, since we already written to stdout.
if extra.OutputJSON == "-" {
return nil
}
}
return output.List(sink, bots)
}