Skip to content

Commit e0f6cab

Browse files
authored
Fix removes control characters from non interactive preflight runs (#394)
1 parent 8dcfa98 commit e0f6cab

File tree

4 files changed

+84
-61
lines changed

4 files changed

+84
-61
lines changed

cmd/preflight/cli/run.go

Lines changed: 77 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"context"
45
"fmt"
56
"io/ioutil"
67
"net/http"
@@ -21,19 +22,21 @@ import (
2122
"github.com/replicatedhq/troubleshoot/pkg/specs"
2223
"github.com/spf13/viper"
2324
spin "github.com/tj/go-spin"
25+
"golang.org/x/sync/errgroup"
2426
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2527
"k8s.io/client-go/kubernetes/scheme"
2628
)
2729

2830
func runPreflights(v *viper.Viper, arg string) error {
29-
fmt.Print(cursor.Hide())
30-
defer fmt.Print(cursor.Show())
31+
if v.GetBool("interactive") {
32+
fmt.Print(cursor.Hide())
33+
defer fmt.Print(cursor.Show())
34+
}
3135

3236
go func() {
3337
signalChan := make(chan os.Signal, 1)
3438
signal.Notify(signalChan, os.Interrupt)
3539
<-signalChan
36-
fmt.Print(cursor.Show())
3740
os.Exit(0)
3841
}()
3942

@@ -97,70 +100,30 @@ func runPreflights(v *viper.Viper, arg string) error {
97100

98101
var collectResults preflight.CollectResult
99102
preflightSpecName := ""
100-
finishedCh := make(chan bool, 1)
101-
progressCh := make(chan interface{}, 0) // non-zero buffer will result in missed messages
103+
104+
progressCh := make(chan interface{})
105+
defer close(progressCh)
106+
107+
ctx, stopProgressCollection := context.WithCancel(context.Background())
108+
// make sure we shut down progress collection goroutines if an error occurs
109+
defer stopProgressCollection()
110+
progressCollection, ctx := errgroup.WithContext(ctx)
102111

103112
if v.GetBool("interactive") {
104-
s := spin.New()
105-
go func() {
106-
lastMsg := ""
107-
for {
108-
select {
109-
case msg, ok := <-progressCh:
110-
if !ok {
111-
continue
112-
}
113-
switch msg := msg.(type) {
114-
case error:
115-
c := color.New(color.FgHiRed)
116-
c.Println(fmt.Sprintf("%s\r * %v", cursor.ClearEntireLine(), msg))
117-
case string:
118-
if lastMsg == msg {
119-
break
120-
}
121-
lastMsg = msg
122-
c := color.New(color.FgCyan)
123-
c.Println(fmt.Sprintf("%s\r * %s", cursor.ClearEntireLine(), msg))
124-
}
125-
case <-time.After(time.Millisecond * 100):
126-
fmt.Printf("\r \033[36mRunning Preflight checks\033[m %s ", s.Next())
127-
case <-finishedCh:
128-
fmt.Printf("\r%s\r", cursor.ClearEntireLine())
129-
return
130-
}
131-
}
132-
}()
113+
progressCollection.Go(collectInteractiveProgress(ctx, progressCh))
133114
} else {
134-
// make sure we don't block any senders
135-
go func() {
136-
for {
137-
select {
138-
case msg, ok := <-progressCh:
139-
if !ok {
140-
return
141-
}
142-
fmt.Fprintf(os.Stderr, "%v\n", msg)
143-
case <-finishedCh:
144-
return
145-
}
146-
}
147-
}()
115+
progressCollection.Go(collectNonInteractiveProgess(ctx, progressCh))
148116
}
149117

150-
defer func() {
151-
close(finishedCh)
152-
close(progressCh)
153-
}()
154-
155118
if preflightSpec, ok := obj.(*troubleshootv1beta2.Preflight); ok {
156-
r, err := collectInCluster(preflightSpec, finishedCh, progressCh)
119+
r, err := collectInCluster(preflightSpec, progressCh)
157120
if err != nil {
158121
return errors.Wrap(err, "failed to collect in cluster")
159122
}
160123
collectResults = *r
161124
preflightSpecName = preflightSpec.Name
162125
} else if hostPreflightSpec, ok := obj.(*troubleshootv1beta2.HostPreflight); ok {
163-
r, err := collectHost(hostPreflightSpec, finishedCh, progressCh)
126+
r, err := collectHost(hostPreflightSpec, progressCh)
164127
if err != nil {
165128
return errors.Wrap(err, "failed to collect from host")
166129
}
@@ -183,7 +146,8 @@ func runPreflights(v *viper.Viper, arg string) error {
183146
}
184147
}
185148

186-
finishedCh <- true
149+
stopProgressCollection()
150+
progressCollection.Wait()
187151

188152
if v.GetBool("interactive") {
189153
if len(analyzeResults) == 0 {
@@ -195,7 +159,60 @@ func runPreflights(v *viper.Viper, arg string) error {
195159
return showStdoutResults(v.GetString("format"), preflightSpecName, analyzeResults)
196160
}
197161

198-
func collectInCluster(preflightSpec *troubleshootv1beta2.Preflight, finishedCh chan bool, progressCh chan interface{}) (*preflight.CollectResult, error) {
162+
func collectInteractiveProgress(ctx context.Context, progressCh <-chan interface{}) func() error {
163+
return func() error {
164+
spinner := spin.New()
165+
lastMsg := ""
166+
167+
errorTxt := color.New(color.FgHiRed)
168+
infoTxt := color.New(color.FgCyan)
169+
170+
for {
171+
select {
172+
case msg := <-progressCh:
173+
switch msg := msg.(type) {
174+
case error:
175+
errorTxt.Printf("%s\r * %v\n", cursor.ClearEntireLine(), msg)
176+
case string:
177+
if lastMsg == msg {
178+
break
179+
}
180+
lastMsg = msg
181+
infoTxt.Printf("%s\r * %s\n", cursor.ClearEntireLine(), msg)
182+
183+
}
184+
case <-time.After(time.Millisecond * 100):
185+
fmt.Printf("\r %s %s ", color.CyanString("Running Preflight Checks"), spinner.Next())
186+
case <-ctx.Done():
187+
fmt.Printf("\r%s\r", cursor.ClearEntireLine())
188+
return nil
189+
}
190+
}
191+
}
192+
}
193+
194+
func collectNonInteractiveProgess(ctx context.Context, progressCh <-chan interface{}) func() error {
195+
return func() error {
196+
for {
197+
select {
198+
case msg := <-progressCh:
199+
switch msg := msg.(type) {
200+
case error:
201+
fmt.Fprintf(os.Stderr, "error - %v\n", msg)
202+
case string:
203+
fmt.Fprintf(os.Stderr, "%s\n", msg)
204+
case preflight.CollectProgress:
205+
fmt.Fprintf(os.Stderr, "%s\n", msg.String())
206+
207+
}
208+
case <-ctx.Done():
209+
return nil
210+
}
211+
}
212+
}
213+
}
214+
215+
func collectInCluster(preflightSpec *troubleshootv1beta2.Preflight, progressCh chan interface{}) (*preflight.CollectResult, error) {
199216
v := viper.GetViper()
200217

201218
restConfig, err := k8sutil.GetRESTConfig()
@@ -217,7 +234,7 @@ func collectInCluster(preflightSpec *troubleshootv1beta2.Preflight, finishedCh c
217234
}
218235

219236
if v.GetString("since") != "" || v.GetString("since-time") != "" {
220-
err := parseTimeFlags(v, progressCh, preflightSpec.Spec.Collectors)
237+
err := parseTimeFlags(v, preflightSpec.Spec.Collectors)
221238
if err != nil {
222239
return nil, err
223240
}
@@ -240,7 +257,7 @@ func collectInCluster(preflightSpec *troubleshootv1beta2.Preflight, finishedCh c
240257
return &collectResults, nil
241258
}
242259

243-
func collectHost(hostPreflightSpec *troubleshootv1beta2.HostPreflight, finishedCh chan bool, progressCh chan interface{}) (*preflight.CollectResult, error) {
260+
func collectHost(hostPreflightSpec *troubleshootv1beta2.HostPreflight, progressCh chan interface{}) (*preflight.CollectResult, error) {
244261
collectOpts := preflight.CollectOpts{
245262
ProgressChan: progressCh,
246263
}
@@ -253,7 +270,7 @@ func collectHost(hostPreflightSpec *troubleshootv1beta2.HostPreflight, finishedC
253270
return &collectResults, nil
254271
}
255272

256-
func parseTimeFlags(v *viper.Viper, progressChan chan interface{}, collectors []*troubleshootv1beta2.Collect) error {
273+
func parseTimeFlags(v *viper.Viper, collectors []*troubleshootv1beta2.Collect) error {
257274
var (
258275
sinceTime time.Time
259276
err error

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ require (
3939
github.com/spf13/viper v1.7.0
4040
github.com/stretchr/testify v1.7.0
4141
github.com/tj/go-spin v1.1.0
42-
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect
42+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
4343
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
4444
golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3 // indirect
4545
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
11331133
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
11341134
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
11351135
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
1136+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
1137+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
11361138
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
11371139
golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
11381140
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

pkg/preflight/collect.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ type CollectProgress struct {
2626
TotalCount int
2727
}
2828

29+
func (cp *CollectProgress) String() string {
30+
return fmt.Sprintf("name: %-20s status: %-15s completed: %-4d total: %-4d", cp.CurrentName, cp.CurrentStatus, cp.CompletedCount, cp.TotalCount)
31+
}
32+
2933
type CollectResult interface {
3034
Analyze() []*analyze.AnalyzeResult
3135
IsRBACAllowed() bool

0 commit comments

Comments
 (0)