cli_tools/diagnostics/main.go (144 lines of code) (raw):

// Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "archive/zip" "errors" "flag" "fmt" "io" "io/ioutil" "log" "net/http" "os" "path/filepath" "time" ) var ( tmpFolder = "" errNonFatal = errors.New("method succeeded with errors") ) type runner interface { run() (string, error) } type logFolder struct { name string files []string } func zipFiles(logs []logFolder, outputPath string) (err error) { newFile, err := os.Create(outputPath) if err != nil { return err } defer func() { // This takes priority over the non-fatal errors if cErr := newFile.Close(); cErr != nil && (err == nil || err == errNonFatal) { err = cErr } }() writer := zip.NewWriter(newFile) defer writer.Close() err = nil for _, folder := range logs { for _, path := range folder.files { file, zErr := os.Open(path) if zErr != nil { log.Printf("Error opening file %s for zipping with error %v\n", path, err) err = errNonFatal continue } defer func() { if cErr := file.Close(); cErr != nil { err = errNonFatal } }() p := fmt.Sprintf("%s/%s", folder.name, filepath.Base(path)) zf, zErr := writer.Create(p) if zErr != nil { log.Printf("Error saving file %s to zip with error %v\n", path, err) err = errNonFatal continue } if _, zErr = io.Copy(zf, file); zErr != nil { log.Printf("Error saving contents of file %s with error %v\n", path, err) err = errNonFatal } } } return err } func uploadToSignedURL(uploadPath string, signedURL string) error { client := &http.Client{ Timeout: 10 * time.Second, } // The signed Url gives us the actual url to upload to req, err := http.NewRequest("POST", signedURL, nil) if err != nil { return err } req.Header.Set("x-goog-resumable", "start") resp, err := client.Do(req) if err != nil { return err } uploadURL := resp.Header.Get("Location") // Upload the file f, err := os.Open(uploadPath) if err != nil { return err } bodyReader, bodyWriter := io.Pipe() go func() { defer bodyWriter.Close() defer f.Close() io.Copy(bodyWriter, f) }() req, err = http.NewRequest("PUT", uploadURL, bodyReader) if err != nil { return err } _, err = client.Do(req) return err } func moveZipFile(path string) (string, error) { currDir, err := os.Getwd() if err != nil { return "", err } knownZipPath := filepath.Join(currDir, filepath.Base(path)) return knownZipPath, os.Rename(path, knownZipPath) } func main() { var err error tmpFolder, err = ioutil.TempDir("", "diagnostics") if err != nil { log.Fatal("Error creating a temporary folder. Exiting") } signedURL := flag.String("signedUrl", "", "The Signed Url to upload the zipped logs to.") traceFlag := flag.Bool("trace", false, "Take a 10 minute trace of the system using wpr.") flag.Parse() nonFatalErrorsPresent := false paths, err := gatherLogs(*traceFlag) if err != nil { nonFatalErrorsPresent = true } zipFile := filepath.Join(tmpFolder, "logs.zip") err = zipFiles(paths, zipFile) if err == errNonFatal { nonFatalErrorsPresent = true } else if err != nil { log.Fatalf("Error zipping files: %v", err) } if *signedURL != "" { log.Printf("Diagnostics: logs uploading to [[%s]].", *signedURL) if err = uploadToSignedURL(zipFile, *signedURL); err != nil { log.Fatalf("Error uploading to signed url: %v. Logs can be found at %s", err, zipFile) } log.Print("Diagnostics: logs uploaded to the supplied url successfully.") } else { knownZipPath, err := moveZipFile(zipFile) if err != nil { log.Fatalf("Error moving logs to well known directory. They can be found instead at: %s", zipFile) } log.Printf("Logs can be found at %s", knownZipPath) } os.RemoveAll(tmpFolder) if nonFatalErrorsPresent { log.Fatal("Errors occured while collecting and zipping some logs.\nUnaffected logs were still packaged and available.") } }