// clHandler serves the HTML for the /cl/<id> page. // // These are shortcuts to individual clusters. // // See alertingHandler for the JSON it uses. // func clHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") if *local { loadTemplates() } match := clHandlerPath.FindStringSubmatch(r.URL.Path) if r.Method != "GET" || match == nil || len(match) != 2 { http.NotFound(w, r) return } id, err := strconv.ParseInt(match[1], 10, 0) if err != nil { util.ReportError(w, r, err, "Failed parsing ID.") return } cl, err := alerting.Get(id) if err != nil { util.ReportError(w, r, err, "Failed to find cluster with that ID.") return } if err := templates.ExecuteTemplate(w, "cl.html", cl); err != nil { glog.Errorln("Failed to expand template:", err) } }
// Handler serves the /annotate/ endpoint for changing the status of an // alert cluster. It also writes a new types.Activity log record to the database. // // Expects a POST of JSON of the following form: // // { // Id: 20 - The id of the alerting cluster. // Status: "Ignore" - The new Status value. // Message: "SKP Update" - The new Messge value. // } // // Returns JSON of the form: // // { // "Bug": "http://" // } // // Where bug, if set, is the URL the user should be directed to to log a bug report. func Handler(w http.ResponseWriter, r *http.Request) { glog.Infof("Annotate Handler: %q\n", r.URL.Path) if login.LoggedInAs(r) == "" { util.ReportError(w, r, fmt.Errorf("Not logged in."), "You must be logged in to change an alert status.") return } if r.Method != "POST" { http.NotFound(w, r) return } if r.Body == nil { util.ReportError(w, r, fmt.Errorf("Missing POST Body."), "POST with no request body.") return } req := struct { Id int64 Status string Message string }{} dec := json.NewDecoder(r.Body) if err := dec.Decode(&req); err != nil { util.ReportError(w, r, err, "Unable to decode posted JSON.") return } if !util.In(req.Status, types.ValidStatusValues) { util.ReportError(w, r, fmt.Errorf("Invalid status value: %s", req.Status), "Unknown value.") return } // Store the updated values in the ClusterSummary. c, err := alerting.Get(req.Id) if err != nil { util.ReportError(w, r, err, "Failed to load cluster summary.") return } c.Status = req.Status c.Message = req.Message if err := alerting.Write(c); err != nil { util.ReportError(w, r, err, "Failed to save cluster summary.") return } // Write a new Activity record. // TODO(jcgregorio) Move into alerting.Write(). a := &types.Activity{ UserID: login.LoggedInAs(r), Action: "Perf Alert: " + req.Status, URL: fmt.Sprintf("https://perf.skia.org/cl/%d", req.Id), } if err := activitylog.Write(a); err != nil { util.ReportError(w, r, err, "Failed to save activity.") return } retval := map[string]string{} if req.Status == "Bug" { q := url.Values{ "labels": []string{"FromSkiaPerf,Type-Defect,Priority-Medium"}, "comment": []string{fmt.Sprintf(ISSUE_COMMENT_TEMPLATE, req.Id)}, } retval["Bug"] = "https://bugs.chromium.org/p/skia/issues/entry?" + q.Encode() } w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) if err := enc.Encode(retval); err != nil { glog.Errorf("Failed to write or encode output: %s", err) } }