func (as *APIServer) EndTask(w http.ResponseWriter, r *http.Request) { finishTime := time.Now() taskEndResponse := &apimodels.TaskEndResponse{} t := MustHaveTask(r) details := &apimodels.TaskEndDetail{} if err := util.ReadJSONInto(r.Body, details); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Check that finishing status is a valid constant if details.Status != evergreen.TaskSucceeded && details.Status != evergreen.TaskFailed && details.Status != evergreen.TaskUndispatched { msg := fmt.Errorf("Invalid end status '%v' for task %v", details.Status, t.Id) as.LoggedError(w, r, http.StatusBadRequest, msg) return } projectRef, err := model.FindOneProjectRef(t.Project) if err != nil { as.LoggedError(w, r, http.StatusInternalServerError, err) } if projectRef == nil { as.LoggedError(w, r, http.StatusNotFound, fmt.Errorf("empty projectRef for task")) return } project, err := model.FindProject("", projectRef) if err != nil { as.LoggedError(w, r, http.StatusInternalServerError, err) return } if !getGlobalLock(r.RemoteAddr, t.Id) { as.LoggedError(w, r, http.StatusInternalServerError, ErrLockTimeout) return } defer releaseGlobalLock(r.RemoteAddr, t.Id) // mark task as finished err = model.MarkEnd(t.Id, APIServerLockTitle, finishTime, details, project, projectRef.DeactivatePrevious) if err != nil { message := fmt.Errorf("Error calling mark finish on task %v : %v", t.Id, err) as.LoggedError(w, r, http.StatusInternalServerError, message) return } if t.Requester != evergreen.PatchVersionRequester { evergreen.Logger.Logf(slogger.INFO, "Processing alert triggers for task %v", t.Id) err := alerts.RunTaskFailureTriggers(t.Id) if err != nil { evergreen.Logger.Logf(slogger.ERROR, "Error processing alert triggers for task %v: %v", t.Id, err) } } else { //TODO(EVG-223) process patch-specific triggers } // if task was aborted, reset to inactive if details.Status == evergreen.TaskUndispatched { if err = model.SetActiveState(t.Id, "", false); err != nil { message := fmt.Sprintf("Error deactivating task after abort: %v", err) evergreen.Logger.Logf(slogger.ERROR, message) taskEndResponse.Message = message as.WriteJSON(w, http.StatusInternalServerError, taskEndResponse) return } as.taskFinished(w, t, finishTime) return } // update the bookkeeping entry for the task err = bookkeeping.UpdateExpectedDuration(t, t.TimeTaken) if err != nil { evergreen.Logger.Logf(slogger.ERROR, "Error updating expected duration: %v", err) } // log the task as finished evergreen.Logger.Logf(slogger.INFO, "Successfully marked task %v as finished", t.Id) // construct and return the appropriate response for the agent as.taskFinished(w, t, finishTime) }
// avoids type-checking json params for the below function func (uis *UIServer) taskModify(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Task == nil { http.Error(w, "Not Found", http.StatusNotFound) return } reqBody, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer r.Body.Close() putParams := struct { Action string `json:"action"` Priority string `json:"priority"` // for the set_active option Active bool `json:"active"` }{} err = json.Unmarshal(reqBody, &putParams) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } authUser := GetUser(r) authName := authUser.DisplayName() // determine what action needs to be taken switch putParams.Action { case "restart": if err := model.TryResetTask(projCtx.Task.Id, authName, evergreen.UIPackage, projCtx.Project, nil); err != nil { http.Error(w, fmt.Sprintf("Error restarting task %v: %v", projCtx.Task.Id, err), http.StatusInternalServerError) return } // Reload the task from db, send it back projCtx.Task, err = task.FindOne(task.ById(projCtx.Task.Id)) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) } uis.WriteJSON(w, http.StatusOK, projCtx.Task) return case "abort": if err := model.AbortTask(projCtx.Task.Id, authName, true); err != nil { http.Error(w, fmt.Sprintf("Error aborting task %v: %v", projCtx.Task.Id, err), http.StatusInternalServerError) return } // Reload the task from db, send it back projCtx.Task, err = task.FindOne(task.ById(projCtx.Task.Id)) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) } uis.WriteJSON(w, http.StatusOK, projCtx.Task) return case "set_active": active := putParams.Active if err := model.SetActiveState(projCtx.Task.Id, authName, active); err != nil { http.Error(w, fmt.Sprintf("Error activating task %v: %v", projCtx.Task.Id, err), http.StatusInternalServerError) return } // Reload the task from db, send it back projCtx.Task, err = task.FindOne(task.ById(projCtx.Task.Id)) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) } uis.WriteJSON(w, http.StatusOK, projCtx.Task) return case "set_priority": priority, err := strconv.ParseInt(putParams.Priority, 10, 64) if err != nil { http.Error(w, "Bad priority value, must be int", http.StatusBadRequest) return } if err = projCtx.Task.SetPriority(priority); err != nil { http.Error(w, fmt.Sprintf("Error setting task priority %v: %v", projCtx.Task.Id, err), http.StatusInternalServerError) return } // Reload the task from db, send it back projCtx.Task, err = task.FindOne(task.ById(projCtx.Task.Id)) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) } uis.WriteJSON(w, http.StatusOK, projCtx.Task) return default: uis.WriteJSON(w, http.StatusBadRequest, "Unrecognized action: "+putParams.Action) } }