Add ability to upload diagnostics to S3

Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
This commit is contained in:
Nathan LeClaire 2016-08-29 16:03:27 -07:00
parent 2121afb71d
commit 970bc31977

View File

@ -2,16 +2,24 @@ package main
import (
"archive/tar"
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"
)
const (
dockerSock = "/var/run/docker.sock"
lgtm = "LGTM"
httpMagicPort = ":44554" // chosen arbitrarily due to IANA availability -- might change
dockerSock = "/var/run/docker.sock"
lgtm = "LGTM"
httpMagicPort = ":44554" // chosen arbitrarily due to IANA availability -- might change
bucket = "editionsdiagnostics"
sessionIDField = "session"
)
var (
@ -41,24 +49,103 @@ func (h HTTPDiagnosticListener) Listen() {
})
http.HandleFunc("/diagnose", func(w http.ResponseWriter, r *http.Request) {
dir, err := ioutil.TempDir("", "diagnostics")
if err != nil {
log.Println("Error creating temp dir on diagnostic request:", err)
diagnosticsSessionID := r.FormValue(sessionIDField)
if diagnosticsSessionID == "" {
http.Error(w, "No 'session' field specified for diagnostics run", http.StatusBadRequest)
return
}
file, err := ioutil.TempFile(dir, "diagnostics")
hostname, err := os.Hostname()
if err != nil {
log.Println("Error creating temp file on diagnostic request:", err)
http.Error(w, "Error getting hostname:"+err.Error(), http.StatusInternalServerError)
return
}
tarWriter := tar.NewWriter(file)
// To keep URL cleaner
hostname = strings.Replace(hostname, ".", "-", -1)
Capture(tarWriter, cloudCaptures)
if _, err := w.Write([]byte("OK hostname=" + hostname + " session=" + diagnosticsSessionID + "\n")); err != nil {
http.Error(w, "Error writing: "+err.Error(), http.StatusInternalServerError)
return
}
// TODO: upload written (and gzipped?) tar file to our S3
// bucket with specific path convention (per-user? by date?)
// Do the actual capture and uplaod to S3 in the background.
// No need to make caller sit and wait for the result. They
// probably have a lot of other things going on, like other
// servers to request diagnostics for.
//
// TODO(nathanleclaire): Potentially, endpoint to check the
// result of this capture and upload process as well.
go func() {
dir, err := ioutil.TempDir("", "diagnostics")
if err != nil {
log.Println("Error creating temp dir on diagnostic request:: ", err)
return
}
file, err := ioutil.TempFile(dir, "diagnostics")
if err != nil {
log.Println("Error creating temp file on diagnostic request:", err)
return
}
tarWriter := tar.NewWriter(file)
Capture(tarWriter, cloudCaptures)
if err := tarWriter.Close(); err != nil {
log.Println("Error closing archive writer: ", err)
return
}
if err := file.Close(); err != nil {
log.Println("Error closing file: ", err)
return
}
readFile, err := os.Open(file.Name())
if err != nil {
log.Println("Error opening report file to upload: ", err)
return
}
defer readFile.Close()
buf := &bytes.Buffer{}
contentLength, err := io.Copy(buf, readFile)
if err != nil {
log.Println("Error copying to buffer: ", err)
return
}
reportURI := fmt.Sprintf("https://%s.s3.amazonaws.com/%s-%s.tar", bucket, diagnosticsSessionID, hostname)
uploadReq, err := http.NewRequest("PUT", reportURI, buf)
if err != nil {
log.Println("Error getting bucket request: ", err)
return
}
uploadReq.Header.Set("x-amz-acl", "bucket-owner-full-control")
uploadReq.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
uploadReq.Header.Set("Content-Length", strconv.Itoa(int(contentLength)))
client := &http.Client{}
if uploadResp, err := client.Do(uploadReq); err != nil {
log.Println("Error writing: ", err)
body, err := ioutil.ReadAll(uploadResp.Body)
if err != nil {
log.Println("Error reading response body: ", err)
}
log.Println(string(body))
return
} else {
log.Println("No error sending S3 request")
}
log.Println("Diagnostics request finished")
}()
})
// Start HTTP server to indicate general Docker health.