Skip to content

Commit ed9264e

Browse files
authored
Merge pull request #53 from replicatedhq/divolgin/upload
Automatically upload generated support bundle file
2 parents 123225c + 68344b2 commit ed9264e

File tree

8 files changed

+542
-279
lines changed

8 files changed

+542
-279
lines changed

cmd/troubleshoot/cli/run_nocrd.go

Lines changed: 105 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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
105108
named %s. Please upload it on the Troubleshoot page of
106109
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
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

115134
func 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

Comments
 (0)