github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/scout/cmd/resume.go (about)

     1  // Copyright (c) 2020-2022, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package scoutcmd
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"os"
    11  	"strings"
    12  	"sync"
    13  
    14  	"github.com/choria-io/go-choria/inter"
    15  	iu "github.com/choria-io/go-choria/internal/util"
    16  	"github.com/sirupsen/logrus"
    17  
    18  	"github.com/choria-io/go-choria/client/discovery"
    19  	"github.com/choria-io/go-choria/client/scoutclient"
    20  	scoutagent "github.com/choria-io/go-choria/scout/agent/scout"
    21  )
    22  
    23  type ResumeCommand struct {
    24  	fw       inter.Framework
    25  	sopt     *discovery.StandardOptions
    26  	checks   []string
    27  	json     bool
    28  	verbose  bool
    29  	colorize bool
    30  	log      *logrus.Entry
    31  }
    32  
    33  func NewResumeCommand(sopt *discovery.StandardOptions, fw inter.Framework, checks []string, json bool, verbose bool, colorize bool, log *logrus.Entry) (*ResumeCommand, error) {
    34  	return &ResumeCommand{
    35  		fw:       fw,
    36  		sopt:     sopt,
    37  		checks:   checks,
    38  		json:     json,
    39  		log:      log,
    40  		verbose:  verbose,
    41  		colorize: colorize,
    42  	}, nil
    43  }
    44  
    45  func (t *ResumeCommand) Run(ctx context.Context, wg *sync.WaitGroup) error {
    46  	defer wg.Done()
    47  
    48  	sc, err := scoutClient(t.fw, t.sopt, t.log)
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	var checks = make([]any, len(t.checks))
    54  	for i, c := range t.checks {
    55  		checks[i] = c
    56  	}
    57  
    58  	result, err := sc.Resume().Checks(checks).Do(ctx)
    59  	if err != nil {
    60  		return err
    61  	}
    62  
    63  	if t.json {
    64  		return result.RenderResults(os.Stdout, scoutclient.JSONFormat, scoutclient.DisplayDDL, t.verbose, false, t.colorize, t.log)
    65  	}
    66  
    67  	if result.Stats().ResponsesCount() == 0 {
    68  		return fmt.Errorf("no responses received")
    69  	}
    70  
    71  	mu := sync.Mutex{}
    72  	triggered := 0
    73  	shown := 0
    74  	table := iu.NewUTF8TableWithTitle("Scout check resume", "Name", "Triggered", "Skipped", "Failed", "Message")
    75  
    76  	result.EachOutput(func(r *scoutclient.ResumeOutput) {
    77  		tr := &scoutagent.ResumeReply{}
    78  		err = r.ParseResumeOutput(tr)
    79  		if err != nil {
    80  			t.log.Errorf("Could not parse output from %s: %s", r.ResultDetails().Sender(), err)
    81  			return
    82  		}
    83  
    84  		mu.Lock()
    85  		defer mu.Unlock()
    86  
    87  		triggered += len(tr.TransitionedChecks)
    88  
    89  		if !t.verbose && r.ResultDetails().OK() && len(tr.FailedChecks) == 0 {
    90  			return
    91  		}
    92  
    93  		shown++
    94  
    95  		table.AddRow(r.ResultDetails().Sender(), strings.Join(tr.TransitionedChecks, ", "), strings.Join(tr.SkippedChecks, ", "), strings.Join(tr.FailedChecks, ", "), r.ResultDetails().StatusMessage())
    96  	})
    97  
    98  	if shown == 0 {
    99  		fmt.Printf("Placed %d checks into normal check mode on %d nodes\n", triggered, result.Stats().ResponsesCount())
   100  		fmt.Println()
   101  	} else {
   102  		fmt.Println(table.Render())
   103  	}
   104  
   105  	return result.RenderResults(os.Stdout, scoutclient.TXTFooter, scoutclient.DisplayDDL, t.verbose, false, t.colorize, t.log)
   106  }