@@ -6,13 +6,15 @@ import (
66 "fmt"
77 "io/ioutil"
88 "net/http"
9+ "net/url"
910 "os"
1011 "path/filepath"
1112 "time"
1213
1314 "github.com/ahmetalpbalkan/go-cursor"
1415 "github.com/fatih/color"
1516 "github.com/mholt/archiver"
17+ "github.com/pkg/errors"
1618 troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
1719 "github.com/replicatedhq/troubleshoot/pkg/collect"
1820 "github.com/spf13/viper"
@@ -32,25 +34,25 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
3234
3335 b , err := ioutil .ReadFile (arg )
3436 if err != nil {
35- return err
37+ return errors . Wrap ( err , "read spec file" )
3638 }
3739
3840 collectorContent = string (b )
3941 } else {
4042 req , err := http .NewRequest ("GET" , arg , nil )
4143 if err != nil {
42- return err
44+ return errors . Wrap ( err , "make request" )
4345 }
4446 req .Header .Set ("User-Agent" , "Replicated_Troubleshoot/v1beta1" )
4547 resp , err := http .DefaultClient .Do (req )
4648 if err != nil {
47- return err
49+ return errors . Wrap ( err , "execute request" )
4850 }
4951 defer resp .Body .Close ()
5052
5153 body , err := ioutil .ReadAll (resp .Body )
5254 if err != nil {
53- return err
55+ return errors . Wrap ( err , "read responce body" )
5456 }
5557
5658 collectorContent = string (body )
@@ -83,7 +85,7 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
8385 if currentDir == "" {
8486 fmt .Printf ("\r %s \033 [36mCollecting support bundle\033 [m %s" , cursor .ClearEntireLine (), s .Next ())
8587 } 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 )
8789 }
8890 }
8991 }
@@ -94,38 +96,55 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
9496
9597 archivePath , err := runCollectors (v , collector , progressChan )
9698 if err != nil {
97- return err
99+ return errors . Wrap ( err , "run collectors" )
98100 }
99101
100102 fmt .Printf ("\r %s" , cursor .ClearEntireLine ())
101103
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
105108named %s. Please upload it on the Troubleshoot page of
106109the %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
108116 }
109117
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+ }
111129
130+ fmt .Printf ("A support bundle has been created in the current directory named %q\n " , archivePath )
112131 return nil
113132}
114133
115134func runCollectors (v * viper.Viper , collector troubleshootv1beta1.Collector , progressChan chan interface {}) (string , error ) {
116135 bundlePath , err := ioutil .TempDir ("" , "troubleshoot" )
117136 if err != nil {
118- return "" , err
137+ return "" , errors . Wrap ( err , "create temp dir" )
119138 }
120139 defer os .RemoveAll (bundlePath )
121140
122141 versionFilename , err := writeVersionFile (bundlePath )
123142 if err != nil {
124- return "" , err
143+ return "" , errors . Wrap ( err , "write version file" )
125144 }
126145
127146 desiredCollectors := make ([]* troubleshootv1beta1.Collect , 0 , 0 )
128- for _ , definedCollector := range collector .Spec {
147+ for _ , definedCollector := range collector .Spec . Collectors {
129148 desiredCollectors = append (desiredCollectors , definedCollector )
130149 }
131150 desiredCollectors = ensureCollectorInList (desiredCollectors , troubleshootv1beta1.Collect {ClusterInfo : & troubleshootv1beta1.ClusterInfo {}})
@@ -175,7 +194,7 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, prog
175194 }
176195
177196 if err := tarGz .Archive (paths , "support-bundle.tar.gz" ); err != nil {
178- return "" , err
197+ return "" , errors . Wrap ( err , "create archive" )
179198 }
180199
181200 return "support-bundle.tar.gz" , nil
@@ -186,7 +205,7 @@ func parseAndSaveCollectorOutput(output string, bundlePath string) (string, erro
186205
187206 input := make (map [string ]interface {})
188207 if err := json .Unmarshal ([]byte (output ), & input ); err != nil {
189- return "" , err
208+ return "" , errors . Wrap ( err , "unmarshal output" )
190209 }
191210
192211 for filename , maybeContents := range input {
@@ -195,37 +214,101 @@ func parseAndSaveCollectorOutput(output string, bundlePath string) (string, erro
195214 dir = outPath
196215
197216 if err := os .MkdirAll (outPath , 0777 ); err != nil {
198- return "" , err
217+ return "" , errors . Wrap ( err , "create output file" )
199218 }
200219
201220 switch maybeContents .(type ) {
202221 case string :
203222 decoded , err := base64 .StdEncoding .DecodeString (maybeContents .(string ))
204223 if err != nil {
205- return "" , err
224+ return "" , errors . Wrap ( err , "decode collector output" )
206225 }
207226
208227 if err := writeFile (filepath .Join (outPath , fileName ), decoded ); err != nil {
209- return "" , err
228+ return "" , errors . Wrap ( err , "write collector output" )
210229 }
211230
212231 case map [string ]interface {}:
213232 for k , v := range maybeContents .(map [string ]interface {}) {
214233 s , _ := filepath .Split (filepath .Join (outPath , fileName , k ))
215234 if err := os .MkdirAll (s , 0777 ); err != nil {
216- return "" , err
235+ return "" , errors . Wrap ( err , "write output directories" )
217236 }
218237
219238 decoded , err := base64 .StdEncoding .DecodeString (v .(string ))
220239 if err != nil {
221- return "" , err
240+ return "" , errors . Wrap ( err , "decode output" )
222241 }
223242 if err := writeFile (filepath .Join (outPath , fileName , k ), decoded ); err != nil {
224- return "" , err
243+ return "" , errors . Wrap ( err , "write output" )
225244 }
226245 }
227246 }
228247 }
229248
230249 return dir , nil
231250}
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