зеркало из https://github.com/mozilla/mig.git
[major] The MIG Command Line Utility
This commit is contained in:
Родитель
d456497d0b
Коммит
bfcdf3b361
2
Makefile
2
Makefile
|
@ -97,7 +97,7 @@ mig-cmd:
|
|||
if [ ! -r $(AVAILMODS) ]; then echo "$(AGTCONF) configuration file is missing" ; exit 1; fi
|
||||
cp $(AVAILMODS) src/mig/client/cmd/available_modules.go
|
||||
$(MKDIR) -p $(BINDIR)
|
||||
$(GO) build $(GOOPTS) -o $(BINDIR)/mig-cmd $(GOLDFLAGS) mig/client/cmd
|
||||
$(GO) build $(GOOPTS) -o $(BINDIR)/mig $(GOLDFLAGS) mig/client/cmd
|
||||
|
||||
mig-agentsearch:
|
||||
$(MKDIR) -p $(BINDIR)
|
||||
|
|
|
@ -8,30 +8,159 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"mig"
|
||||
"mig/client"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Printf(`%s - Mozilla InvestiGator command line client
|
||||
usage: %s <module> <global options> <module parameters>
|
||||
|
||||
--- Global options ---
|
||||
|
||||
-c <path> path to an alternative config file. If not set, use ~/.migrc
|
||||
-e <duration> time after which the action expires. 60 seconds by default.
|
||||
example: -e 300s (5 minutes)
|
||||
-show <mode> type of results to show. if not set, default is 'found'.
|
||||
* found: only print positive results
|
||||
* notfound: only print negative results
|
||||
* all: print all results
|
||||
-t <target> target to launch the action on. Defaults to all active agents.
|
||||
examples:
|
||||
* linux agents: -t "os='linux'"
|
||||
* agents named *mysql*: -t "name like '%%mysql%%'"
|
||||
* proxied linux agents: -t "os='linux' AND environment->>'isproxied' = 'true'"
|
||||
* agents operated by IT: -t "tags#>>'{operator}'='IT'"
|
||||
|
||||
--- Modules documentation ---
|
||||
Each module provides its own set of parameters. Module parameters must be set *after*
|
||||
global options for the parsing to work correctly. The following modules are available:
|
||||
`, os.Args[0], os.Args[0])
|
||||
for module, _ := range mig.AvailableModules {
|
||||
fmt.Printf("* %s\n", module)
|
||||
}
|
||||
fmt.Printf("To access a module documentation, use: %s <module> help\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func continueOnFlagError() {
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
var (
|
||||
err error
|
||||
op mig.Operation
|
||||
a mig.Action
|
||||
migrc, show, target, expiration string
|
||||
modargs []string
|
||||
)
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("FATAL: %v", e)
|
||||
}
|
||||
}()
|
||||
homedir := client.FindHomedir()
|
||||
// command line options
|
||||
var config = flag.String("c", homedir+"/.migrc", "Load configuration from file")
|
||||
var aid = flag.Float64("aid", float64(1234567890), "Retrieve and print action by ID")
|
||||
flag.Parse()
|
||||
fs := flag.NewFlagSet("mig flag", flag.ContinueOnError)
|
||||
fs.Usage = continueOnFlagError
|
||||
fs.StringVar(&migrc, "c", homedir+"/.migrc", "alternative configuration file")
|
||||
fs.StringVar(&show, "show", "found", "type of results to show")
|
||||
fs.StringVar(&target, "t", `status='online'`, "action target")
|
||||
fs.StringVar(&expiration, "e", "60s", "expiration")
|
||||
|
||||
// if first argument is missing, or is help, print help
|
||||
// otherwise, pass the remainder of the arguments to the module for parsing
|
||||
// this client is agnostic to module parameters
|
||||
if len(os.Args) < 2 || os.Args[1] == "help" || os.Args[1] == "-h" || os.Args[1] == "--help" {
|
||||
usage()
|
||||
}
|
||||
|
||||
// arguments parsing works as follow:
|
||||
// * os.Args[1] must contain the name of the module to launch. we first verify
|
||||
// that a module exist for this name and then continue parsing
|
||||
// * os.Args[2:] contains both global options and module parameters. We parse the
|
||||
// whole []string to extract global options, and module parameters will be left
|
||||
// unparsed in fs.Args()
|
||||
// * fs.Args() with the module parameters is passed as a string to the module parser
|
||||
// which will return a module operation to store in the action
|
||||
op.Module = os.Args[1]
|
||||
if _, ok := mig.AvailableModules[op.Module]; !ok {
|
||||
panic("Unknown module " + op.Module)
|
||||
}
|
||||
|
||||
err = fs.Parse(os.Args[2:])
|
||||
if err != nil {
|
||||
// ignore the flag not defined error, which is expected because
|
||||
// module parameters are defined in modules and not in main
|
||||
if len(err.Error()) > 30 && err.Error()[0:29] == "flag provided but not defined" {
|
||||
// requeue the parameter that failed
|
||||
modargs = append(modargs, err.Error()[31:])
|
||||
} else {
|
||||
// if it's another error, panic
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
for _, arg := range fs.Args() {
|
||||
modargs = append(modargs, arg)
|
||||
}
|
||||
modRunner := mig.AvailableModules[op.Module]()
|
||||
if _, ok := modRunner.(mig.HasParamsParser); !ok {
|
||||
fmt.Fprintf(os.Stderr, "[error] module '%s' does not support command line invocation\n", op.Module)
|
||||
os.Exit(2)
|
||||
}
|
||||
op.Parameters, err = modRunner.(mig.HasParamsParser).ParamsParser(modargs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.Operations = append(a.Operations, op)
|
||||
|
||||
// instanciate an API client
|
||||
conf, err := client.ReadConfiguration(*config)
|
||||
conf, err := client.ReadConfiguration(migrc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cli := client.NewClient(conf)
|
||||
|
||||
if *aid != float64(1234567890) {
|
||||
a, _, err := cli.GetAction(*aid)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Printf("%.0f; %s; %s; %s\n", a.ID, a.Name, a.Target, a.Status)
|
||||
}
|
||||
a.Name = op.Module + " on '" + target + "'"
|
||||
a.Target = target
|
||||
// set the validity 60 second in the past to deal with clock skew
|
||||
a.ValidFrom = time.Now().Add(-60 * time.Second).UTC()
|
||||
period, err := time.ParseDuration(expiration)
|
||||
a.ExpireAfter = a.ValidFrom.Add(period)
|
||||
// add extra 60 seconds taken for clock skew
|
||||
a.ExpireAfter = a.ExpireAfter.Add(60 * time.Second).UTC()
|
||||
|
||||
asig, err := cli.SignAction(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a = asig
|
||||
|
||||
// evaluate target before launch, give a change to cancel before going out to agents
|
||||
agents, err := cli.EvaluateAgentTarget(a.Target)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%d agents will be targeted. ctrl+c to cancel. launching in ", len(agents))
|
||||
for i := 5; i > 0; i-- {
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Fprintf(os.Stderr, "%d ", i)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "GO\n")
|
||||
|
||||
// launch and follow
|
||||
a, err = cli.PostAction(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = cli.FollowAction(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = cli.PrintActionResults(a, show)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,3 +62,8 @@ type HasResultsPrinter interface {
|
|||
type HasParamsCreator interface {
|
||||
ParamsCreator() (interface{}, error)
|
||||
}
|
||||
|
||||
// HasParamsParser implements a function that parses command line parameters
|
||||
type HasParamsParser interface {
|
||||
ParamsParser([]string) (interface{}, error)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче