[minor] move common client functions to mig/client

This commit is contained in:
Julien Vehent 2014-11-24 12:01:26 -05:00
Родитель 46a62a107c
Коммит abed1dce2f
4 изменённых файлов: 179 добавлений и 108 удалений

Просмотреть файл

@ -570,3 +570,170 @@ func (cli Client) EvaluateAgentTarget(target string) (agents []mig.Agent, err er
}
return
}
// FollowAction continuously loops over an action and prints its completion status in os.Stderr.
// when the action reaches its expiration date, FollowAction prints its final status and returns.
func (cli Client) FollowAction(a mig.Action) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("followAction() -> %v", e)
}
}()
fmt.Fprintf(os.Stderr, "Following action ID %.0f. ", a.ID)
sent := 0
dotter := 0
previousctr := 0
status := ""
attempts := 0
var completion float64
for {
a, _, err = cli.GetAction(a.ID)
if err != nil {
attempts++
time.Sleep(1 * time.Second)
if attempts >= 30 {
panic("failed to retrieve action after 30 seconds. launch may have failed")
}
continue
}
if status == "" {
status = a.Status
}
if status != a.Status {
fmt.Fprintf(os.Stderr, "status=%s\n", a.Status)
status = a.Status
}
// exit follower mode if status isn't one we follow,
// or enough commands have returned
// or expiration time has passed
if (status != "init" && status != "preparing" && status != "inflight") ||
(a.Counters.Done > 0 && a.Counters.Done >= a.Counters.Sent) ||
(time.Now().After(a.ExpireAfter)) {
goto finish
break
}
// init counters
if sent == 0 {
if a.Counters.Sent == 0 {
time.Sleep(1 * time.Second)
continue
} else {
sent = a.Counters.Sent
}
}
if a.Counters.Done > 0 && a.Counters.Done > previousctr {
completion = (float64(a.Counters.Done) / float64(a.Counters.Sent)) * 100
if completion > 99.9 && a.Counters.Done != a.Counters.Sent {
completion = 99.9
}
previousctr = a.Counters.Done
fmt.Fprintf(os.Stderr, "%.0f%% ", completion)
}
fmt.Fprintf(os.Stderr, ".")
time.Sleep(2 * time.Second)
dotter++
}
finish:
fmt.Fprintf(os.Stderr, "done in %s\n", time.Now().Sub(a.StartTime).String())
a.PrintCounters()
return
}
func (cli Client) PrintActionResults(a mig.Action, show string) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("PrintActionResults() -> %v", e)
}
}()
found := false
var resource *cljs.Resource
switch show {
case "found":
found = true
target := fmt.Sprintf("search?type=command&limit=1000000&foundanything=true&actionid=%.0f", a.ID)
resource, err = cli.GetAPIResource(target)
if err != nil {
panic(err)
}
case "notfound":
target := fmt.Sprintf("search?type=command&limit=1000000&foundanything=false&actionid=%.0f", a.ID)
resource, err = cli.GetAPIResource(target)
if err != nil {
panic(err)
}
case "all":
target := fmt.Sprintf("search?type=command&limit=1000000&actionid=%.0f", a.ID)
resource, err = cli.GetAPIResource(target)
if err != nil {
panic(err)
}
default:
return fmt.Errorf("invalid parameter '%s'", show)
}
count := 0
for _, item := range resource.Collection.Items {
for _, data := range item.Data {
if data.Name != "command" {
continue
}
cmd, err := ValueToCommand(data.Value)
if err != nil {
panic(err)
}
err = PrintCommandResults(cmd, found, true)
if err != nil {
panic(err)
}
count++
}
}
fmt.Fprintf(os.Stderr, "%d agents have %s results\n", count, show)
return
}
func PrintCommandResults(cmd mig.Command, found, showAgent bool) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("PrintCommandResults() -> %v", e)
}
}()
for i, result := range cmd.Results {
buf, err := json.Marshal(result)
if err != nil {
panic(err)
}
if len(cmd.Action.Operations) <= i {
fmt.Fprintf(os.Stderr, "[error] no operation maps results %d\n", i)
for _, rerr := range result.Errors {
fmt.Fprintf(os.Stderr, "[error] %s\n", rerr)
}
continue
}
// verify that we know the module
moduleName := cmd.Action.Operations[i].Module
if _, ok := mig.AvailableModules[moduleName]; !ok {
fmt.Fprintf(os.Stderr, "Skipping unknown module '%s'\n", moduleName)
continue
}
modRunner := mig.AvailableModules[moduleName]()
// look for a result printer in the module
if _, ok := modRunner.(mig.HasResultsPrinter); ok {
results, err := modRunner.(mig.HasResultsPrinter).PrintResults(buf, found)
if err != nil {
panic(err)
}
for _, res := range results {
if showAgent {
agtname := cmd.Agent.Name
fmt.Printf("%s %s\n", agtname, res)
} else {
fmt.Println(res)
}
}
} else {
fmt.Fprintf(os.Stderr, "no printer available for module '%s'\n", moduleName)
}
}
fmt.Fprintf(os.Stderr, "command status: %s\n", cmd.Status)
return
}

Просмотреть файл

@ -229,7 +229,7 @@ times show the various timestamps of the action
fmt.Printf("Action '%s' successfully launched with ID '%.0f' on target '%s'\n",
a.Name, a.ID, a.Target)
if follow {
err = followAction(a, cli)
err = cli.FollowAction(a)
if err != nil {
panic(err)
}

Просмотреть файл

@ -143,7 +143,16 @@ times show the various timestamps of the action
}
fmt.Println("Reload succeeded")
case "results":
err = actionPrintResults(a, links, orders, cli)
show := "all"
if len(orders) > 1 {
switch orders[1] {
case "found":
show = "found"
case "notfound":
show = "notfound"
}
}
err = cli.PrintActionResults(a, show)
if err != nil {
panic(err)
}
@ -330,65 +339,3 @@ func actionPrintLinks(links []cljs.Link, orders []string) (err error) {
fmt.Printf(" found\n")
return
}
func actionPrintResults(a mig.Action, links []cljs.Link, orders []string, cli client.Client) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("actionPrintResuls() -> %v", e)
}
}()
found := false
if len(orders) > 1 {
if orders[1] == "found" {
found = true
} else {
fmt.Printf("Unknown option '%s'\n", orders[1])
}
}
if found {
// if we want foundes, use the search api, it's faster than
// iterating through each link when we have thousands of them
target := "search?type=command&limit=1000000&foundanything=true"
target += "&actionid=" + fmt.Sprintf("%.0f", a.ID)
resource, err := cli.GetAPIResource(target)
if err != nil {
panic(err)
}
for _, item := range resource.Collection.Items {
for _, data := range item.Data {
if data.Name != "command" {
continue
}
cmd, err := client.ValueToCommand(data.Value)
if err != nil {
panic(err)
}
err = commandPrintResults(cmd, true, true)
if err != nil {
panic(err)
}
}
}
} else {
for _, link := range links {
// TODO: replace the url parsing hack with proper link creation in API response
id := strings.Split(link.Href, "=")[1]
cmdid, err := strconv.ParseFloat(id, 64)
if err != nil {
fmt.Println("ERROR: invalid command id in link:", link)
continue
}
cmd, err := cli.GetCommand(cmdid)
if err != nil {
fmt.Println("ERROR: failed to get command id", cmdid)
continue
}
err = commandPrintResults(cmd, found, true)
if err != nil {
fmt.Println("ERROR: failed to print results from command id", cmdid)
continue
}
}
}
return
}

Просмотреть файл

@ -10,7 +10,6 @@ import (
"fmt"
"github.com/bobappleyard/readline"
"io"
"mig"
"mig/client"
"strconv"
"strings"
@ -101,7 +100,7 @@ results <found> print the results. if "found" is set, only print results that ha
fmt.Printf("Unknown option '%s'\n", orders[1])
}
}
err = commandPrintResults(cmd, found, false)
err = client.PrintCommandResults(cmd, found, false)
if err != nil {
panic(err)
}
@ -117,48 +116,6 @@ exit:
return
}
func commandPrintResults(cmd mig.Command, found, showAgent bool) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("commandPrintResults() -> %v", e)
}
}()
for i, result := range cmd.Results {
buf, err := json.Marshal(result)
if err != nil {
panic(err)
}
// verify that we know the module
moduleName := cmd.Action.Operations[i].Module
if _, ok := mig.AvailableModules[moduleName]; !ok {
fmt.Println("Skipping unknown module", moduleName)
continue
}
modRunner := mig.AvailableModules[moduleName]()
// look for a result printer in the module
if _, ok := modRunner.(mig.HasResultsPrinter); ok {
results, err := modRunner.(mig.HasResultsPrinter).PrintResults(buf, found)
if err != nil {
panic(err)
}
for _, res := range results {
if showAgent {
agtname := cmd.Agent.Name
if useShortNames {
agtname = shorten(agtname)
}
fmt.Printf("%s %s\n", agtname, res)
} else {
fmt.Println(res)
}
}
} else {
fmt.Printf("no result printer available for module '%s'. try `json pretty`\n", moduleName)
}
}
return
}
func commandPrintShort(data interface{}) (idstr, agtname, duration, status string, err error) {
defer func() {
if e := recover(); e != nil {