зеркало из https://github.com/mozilla/mig.git
mig-cmd: handle SIGINT nicer when interrupting an action
Use WaitGroups to avoid interleaving text if an action is cancelled. This did not occur all the time, but this change should provide for more consistent behavior. mig-console didn't handle this at all; add a comment around this as well and adjust mig-console to provide the additional extra parameter required.
This commit is contained in:
Родитель
c6ec604c0f
Коммит
33a0a4ee8f
|
@ -1351,8 +1351,14 @@ func (cli Client) EvaluateAgentTarget(target string) (agents []mig.Agent, err er
|
|||
}
|
||||
|
||||
// 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, total int) (err error) {
|
||||
// When the action reaches its expiration date, FollowAction prints its final status and returns.
|
||||
//
|
||||
// a represents the action being followed, and total indicates the total number of agents
|
||||
// the action was submitted to and is used to initialize the progress meter.
|
||||
//
|
||||
// stop is of type chan bool, and passing a value to this channel will cause the routine to return
|
||||
// immediately.
|
||||
func (cli Client) FollowAction(a mig.Action, total int, stop chan bool) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("followAction() -> %v", e)
|
||||
|
@ -1362,12 +1368,19 @@ func (cli Client) FollowAction(a mig.Action, total int) (err error) {
|
|||
previousctr := 0
|
||||
status := ""
|
||||
attempts := 0
|
||||
cancelfollow := false
|
||||
var completion float64
|
||||
bar := pb.New(total)
|
||||
bar.ShowSpeed = true
|
||||
bar.SetMaxWidth(80)
|
||||
bar.Output = os.Stderr
|
||||
bar.Start()
|
||||
go func() {
|
||||
_ = <-stop
|
||||
bar.Postfix(" [cancelling]")
|
||||
cancelfollow = true
|
||||
bar.Finish()
|
||||
}()
|
||||
for {
|
||||
a, _, err = cli.GetAction(a.ID)
|
||||
if err != nil {
|
||||
|
@ -1390,6 +1403,10 @@ func (cli Client) FollowAction(a mig.Action, total int) (err error) {
|
|||
goto finish
|
||||
break
|
||||
}
|
||||
if cancelfollow {
|
||||
// We have been asked to stop, just return
|
||||
return nil
|
||||
}
|
||||
if a.Counters.Done > 0 && a.Counters.Done > previousctr {
|
||||
completion = (float64(a.Counters.Done) / float64(a.Counters.Sent)) * 100
|
||||
if completion < 99.5 {
|
||||
|
|
|
@ -276,7 +276,12 @@ 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 = cli.FollowAction(a, tcount)
|
||||
// XXX the sigint channel, which is used to indicate the follow
|
||||
// operation should be cancelled is not actually used right now. This
|
||||
// should likely be handled in a similar manner to how mig-cmd handles
|
||||
// interrupts.
|
||||
sigint := make(chan bool, 1)
|
||||
err = cli.FollowAction(a, tcount, sigint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"mig.ninja/mig"
|
||||
|
@ -382,30 +383,45 @@ readytolaunch:
|
|||
}
|
||||
fmt.Fprintf(os.Stderr, "\x1b[33mGO\n\x1b[0m")
|
||||
|
||||
// launch and follow
|
||||
// Launch the action
|
||||
a, err = cli.PostAction(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Follow the action for completion, and handle an interrupt to abort waiting for
|
||||
// completion, but still print out available results.
|
||||
var wg sync.WaitGroup
|
||||
c := make(chan os.Signal, 1)
|
||||
done := make(chan bool, 1)
|
||||
sigint := make(chan bool, 1)
|
||||
complete := make(chan bool, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
cancelled := false
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
err = cli.FollowAction(a, len(agents))
|
||||
defer wg.Done()
|
||||
err = cli.FollowAction(a, len(agents), sigint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
done <- true
|
||||
complete <- true
|
||||
}()
|
||||
select {
|
||||
case <-c:
|
||||
fmt.Fprintf(os.Stderr, "\n[notice] stopped following action, but agents may still be running.\n")
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
select {
|
||||
case _ = <-c:
|
||||
cancelled = true
|
||||
sigint <- true
|
||||
case _ = <-complete:
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
if cancelled {
|
||||
fmt.Fprintf(os.Stderr, "[notice] stopped following action, but agents may still be running.\n")
|
||||
fmt.Fprintf(os.Stderr, "fetching available results:\n")
|
||||
goto printresults
|
||||
case <-done:
|
||||
goto printresults
|
||||
}
|
||||
printresults:
|
||||
err = cli.PrintActionResults(a, show, render)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
Загрузка…
Ссылка в новой задаче