@@ -6,13 +6,15 @@ import (
6
6
"fmt"
7
7
"io/ioutil"
8
8
"net/http"
9
+ "net/url"
9
10
"os"
10
11
"path/filepath"
11
12
"time"
12
13
13
14
"github.com/ahmetalpbalkan/go-cursor"
14
15
"github.com/fatih/color"
15
16
"github.com/mholt/archiver"
17
+ "github.com/pkg/errors"
16
18
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
17
19
"github.com/replicatedhq/troubleshoot/pkg/collect"
18
20
"github.com/spf13/viper"
@@ -32,25 +34,25 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
32
34
33
35
b , err := ioutil .ReadFile (arg )
34
36
if err != nil {
35
- return err
37
+ return errors . Wrap ( err , "read spec file" )
36
38
}
37
39
38
40
collectorContent = string (b )
39
41
} else {
40
42
req , err := http .NewRequest ("GET" , arg , nil )
41
43
if err != nil {
42
- return err
44
+ return errors . Wrap ( err , "make request" )
43
45
}
44
46
req .Header .Set ("User-Agent" , "Replicated_Troubleshoot/v1beta1" )
45
47
resp , err := http .DefaultClient .Do (req )
46
48
if err != nil {
47
- return err
49
+ return errors . Wrap ( err , "execute request" )
48
50
}
49
51
defer resp .Body .Close ()
50
52
51
53
body , err := ioutil .ReadAll (resp .Body )
52
54
if err != nil {
53
- return err
55
+ return errors . Wrap ( err , "read responce body" )
54
56
}
55
57
56
58
collectorContent = string (body )
@@ -83,7 +85,7 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
83
85
if currentDir == "" {
84
86
fmt .Printf ("\r %s \033 [36mCollecting support bundle\033 [m %s" , cursor .ClearEntireLine (), s .Next ())
85
87
} else {
86
- fmt .Printf ("\r %s \033 [36mCollecting support bundle\033 [m %s: %s" , cursor .ClearEntireLine (), s .Next (), currentDir )
88
+ fmt .Printf ("\r %s \033 [36mCollecting support bundle\033 [m %s %s" , cursor .ClearEntireLine (), s .Next (), currentDir )
87
89
}
88
90
}
89
91
}
@@ -94,38 +96,55 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
94
96
95
97
archivePath , err := runCollectors (v , collector , progressChan )
96
98
if err != nil {
97
- return err
99
+ return errors . Wrap ( err , "run collectors" )
98
100
}
99
101
100
102
fmt .Printf ("\r %s" , cursor .ClearEntireLine ())
101
103
102
- msg := archivePath
103
- if appName := collector .Labels ["applicationName" ]; appName != "" {
104
- f := `A support bundle for %s has been created in this directory
104
+ if len (collector .Spec .AfterCollection ) == 0 {
105
+ msg := archivePath
106
+ if appName := collector .Labels ["applicationName" ]; appName != "" {
107
+ f := `A support bundle for %s has been created in this directory
105
108
named %s. Please upload it on the Troubleshoot page of
106
109
the %s Admin Console to begin analysis.`
107
- msg = fmt .Sprintf (f , appName , archivePath , appName )
110
+ msg = fmt .Sprintf (f , appName , archivePath , appName )
111
+ }
112
+
113
+ fmt .Printf ("%s\n " , msg )
114
+
115
+ return nil
108
116
}
109
117
110
- fmt .Printf ("%s\n " , msg )
118
+ for _ , ac := range collector .Spec .AfterCollection {
119
+ if ac .UploadResultsTo != nil {
120
+ if err := uploadSupportBundle (ac .UploadResultsTo , archivePath ); err != nil {
121
+ return errors .Wrap (err , "upload support bundle" )
122
+ }
123
+ } else if ac .Callback != nil {
124
+ if err := callbackSupportBundleAPI (ac .Callback , archivePath ); err != nil {
125
+ return errors .Wrap (err , "execute callback" )
126
+ }
127
+ }
128
+ }
111
129
130
+ fmt .Printf ("A support bundle has been created in the current directory named %q\n " , archivePath )
112
131
return nil
113
132
}
114
133
115
134
func runCollectors (v * viper.Viper , collector troubleshootv1beta1.Collector , progressChan chan interface {}) (string , error ) {
116
135
bundlePath , err := ioutil .TempDir ("" , "troubleshoot" )
117
136
if err != nil {
118
- return "" , err
137
+ return "" , errors . Wrap ( err , "create temp dir" )
119
138
}
120
139
defer os .RemoveAll (bundlePath )
121
140
122
141
versionFilename , err := writeVersionFile (bundlePath )
123
142
if err != nil {
124
- return "" , err
143
+ return "" , errors . Wrap ( err , "write version file" )
125
144
}
126
145
127
146
desiredCollectors := make ([]* troubleshootv1beta1.Collect , 0 , 0 )
128
- for _ , definedCollector := range collector .Spec {
147
+ for _ , definedCollector := range collector .Spec . Collectors {
129
148
desiredCollectors = append (desiredCollectors , definedCollector )
130
149
}
131
150
desiredCollectors = ensureCollectorInList (desiredCollectors , troubleshootv1beta1.Collect {ClusterInfo : & troubleshootv1beta1.ClusterInfo {}})
@@ -175,7 +194,7 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, prog
175
194
}
176
195
177
196
if err := tarGz .Archive (paths , "support-bundle.tar.gz" ); err != nil {
178
- return "" , err
197
+ return "" , errors . Wrap ( err , "create archive" )
179
198
}
180
199
181
200
return "support-bundle.tar.gz" , nil
@@ -186,7 +205,7 @@ func parseAndSaveCollectorOutput(output string, bundlePath string) (string, erro
186
205
187
206
input := make (map [string ]interface {})
188
207
if err := json .Unmarshal ([]byte (output ), & input ); err != nil {
189
- return "" , err
208
+ return "" , errors . Wrap ( err , "unmarshal output" )
190
209
}
191
210
192
211
for filename , maybeContents := range input {
@@ -195,37 +214,101 @@ func parseAndSaveCollectorOutput(output string, bundlePath string) (string, erro
195
214
dir = outPath
196
215
197
216
if err := os .MkdirAll (outPath , 0777 ); err != nil {
198
- return "" , err
217
+ return "" , errors . Wrap ( err , "create output file" )
199
218
}
200
219
201
220
switch maybeContents .(type ) {
202
221
case string :
203
222
decoded , err := base64 .StdEncoding .DecodeString (maybeContents .(string ))
204
223
if err != nil {
205
- return "" , err
224
+ return "" , errors . Wrap ( err , "decode collector output" )
206
225
}
207
226
208
227
if err := writeFile (filepath .Join (outPath , fileName ), decoded ); err != nil {
209
- return "" , err
228
+ return "" , errors . Wrap ( err , "write collector output" )
210
229
}
211
230
212
231
case map [string ]interface {}:
213
232
for k , v := range maybeContents .(map [string ]interface {}) {
214
233
s , _ := filepath .Split (filepath .Join (outPath , fileName , k ))
215
234
if err := os .MkdirAll (s , 0777 ); err != nil {
216
- return "" , err
235
+ return "" , errors . Wrap ( err , "write output directories" )
217
236
}
218
237
219
238
decoded , err := base64 .StdEncoding .DecodeString (v .(string ))
220
239
if err != nil {
221
- return "" , err
240
+ return "" , errors . Wrap ( err , "decode output" )
222
241
}
223
242
if err := writeFile (filepath .Join (outPath , fileName , k ), decoded ); err != nil {
224
- return "" , err
243
+ return "" , errors . Wrap ( err , "write output" )
225
244
}
226
245
}
227
246
}
228
247
}
229
248
230
249
return dir , nil
231
250
}
251
+
252
+ func uploadSupportBundle (r * troubleshootv1beta1.ResultRequest , archivePath string ) error {
253
+ contentType := getExpectedContentType (r .URI )
254
+ if contentType != "" && contentType != "application/tar+gzip" {
255
+ return fmt .Errorf ("cannot upload content type %s" , contentType )
256
+ }
257
+
258
+ f , err := os .Open (archivePath )
259
+ if err != nil {
260
+ return errors .Wrap (err , "open file" )
261
+ }
262
+ defer f .Close ()
263
+
264
+ fileStat , err := f .Stat ()
265
+ if err != nil {
266
+ return errors .Wrap (err , "stat file" )
267
+ }
268
+
269
+ req , err := http .NewRequest (r .Method , r .URI , f )
270
+ if err != nil {
271
+ return errors .Wrap (err , "create request" )
272
+ }
273
+ req .ContentLength = fileStat .Size ()
274
+ if contentType != "" {
275
+ req .Header .Set ("Content-Type" , contentType )
276
+ }
277
+
278
+ resp , err := http .DefaultClient .Do (req )
279
+ if err != nil {
280
+ return errors .Wrap (err , "execute request" )
281
+ }
282
+
283
+ if resp .StatusCode >= 300 {
284
+ return fmt .Errorf ("unexpected status code %d" , resp .StatusCode )
285
+ }
286
+
287
+ return nil
288
+ }
289
+
290
+ func getExpectedContentType (uploadURL string ) string {
291
+ parsedURL , err := url .Parse (uploadURL )
292
+ if err != nil {
293
+ return ""
294
+ }
295
+ return parsedURL .Query ().Get ("Content-Type" )
296
+ }
297
+
298
+ func callbackSupportBundleAPI (r * troubleshootv1beta1.ResultRequest , archivePath string ) error {
299
+ req , err := http .NewRequest (r .Method , r .URI , nil )
300
+ if err != nil {
301
+ return errors .Wrap (err , "create request" )
302
+ }
303
+
304
+ resp , err := http .DefaultClient .Do (req )
305
+ if err != nil {
306
+ return errors .Wrap (err , "execute request" )
307
+ }
308
+
309
+ if resp .StatusCode >= 300 {
310
+ return fmt .Errorf ("unexpected status code %d" , resp .StatusCode )
311
+ }
312
+
313
+ return nil
314
+ }
0 commit comments