github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/service/rest_task.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/evergreen-ci/evergreen/model" 9 "github.com/evergreen-ci/evergreen/model/artifact" 10 "github.com/evergreen-ci/evergreen/model/task" 11 "github.com/mongodb/grip" 12 ) 13 14 type taskStatusContent struct { 15 Id string `json:"task_id"` 16 Name string `json:"task_name"` 17 Status string `json:"status"` 18 StatusDetails taskStatusDetails `json:"status_details"` 19 Tests taskStatusByTest `json:"tests"` 20 } 21 22 type RestTask struct { 23 Id string `json:"id"` 24 CreateTime time.Time `json:"create_time"` 25 ScheduledTime time.Time `json:"scheduled_time"` 26 DispatchTime time.Time `json:"dispatch_time"` 27 StartTime time.Time `json:"start_time"` 28 FinishTime time.Time `json:"finish_time"` 29 PushTime time.Time `json:"push_time"` 30 Version string `json:"version"` 31 Project string `json:"project"` 32 Revision string `json:"revision"` 33 Priority int64 `json:"priority"` 34 LastHeartbeat time.Time `json:"last_heartbeat"` 35 Activated bool `json:"activated"` 36 BuildId string `json:"build_id"` 37 DistroId string `json:"distro"` 38 BuildVariant string `json:"build_variant"` 39 DependsOn []task.Dependency `json:"depends_on"` 40 DisplayName string `json:"display_name"` 41 HostId string `json:"host_id"` 42 Restarts int `json:"restarts"` 43 Execution int `json:"execution"` 44 Archived bool `json:"archived"` 45 RevisionOrderNumber int `json:"order"` 46 Requester string `json:"requester"` 47 Status string `json:"status"` 48 StatusDetails taskStatusDetails `json:"status_details"` 49 Aborted bool `json:"aborted"` 50 TimeTaken time.Duration `json:"time_taken"` 51 ExpectedDuration time.Duration `json:"expected_duration"` 52 TestResults taskTestResultsByName `json:"test_results"` 53 MinQueuePos int `json:"min_queue_pos"` 54 PatchNumber int `json:"patch_number,omitempty"` 55 PatchId string `json:"patch_id,omitempty"` 56 57 // Artifacts and binaries 58 Files []taskFile `json:"files"` 59 } 60 61 type taskStatusDetails struct { 62 TimedOut bool `json:"timed_out"` 63 TimeoutStage string `json:"timeout_stage"` 64 } 65 66 type taskTestResult struct { 67 Status string `json:"status"` 68 TimeTaken time.Duration `json:"time_taken"` 69 Logs interface{} `json:"logs"` 70 } 71 72 type taskTestLogURL struct { 73 URL string `json:"url"` 74 } 75 76 type taskFile struct { 77 Name string `json:"name"` 78 URL string `json:"url"` 79 } 80 81 type taskTestResultsByName map[string]taskTestResult 82 83 type taskStatusByTest map[string]taskTestResult 84 85 // Returns a JSON response with the marshaled output of the task 86 // specified in the request. 87 func (restapi restAPI) getTaskInfo(w http.ResponseWriter, r *http.Request) { 88 projCtx := MustHaveRESTContext(r) 89 srcTask := projCtx.Task 90 if srcTask == nil { 91 restapi.WriteJSON(w, http.StatusNotFound, responseError{Message: "error finding task"}) 92 return 93 } 94 95 destTask := &RestTask{} 96 destTask.Id = srcTask.Id 97 destTask.CreateTime = srcTask.CreateTime 98 destTask.ScheduledTime = srcTask.ScheduledTime 99 destTask.DispatchTime = srcTask.DispatchTime 100 destTask.StartTime = srcTask.StartTime 101 destTask.FinishTime = srcTask.FinishTime 102 destTask.PushTime = srcTask.PushTime 103 destTask.Version = srcTask.Version 104 destTask.Project = srcTask.Project 105 destTask.Revision = srcTask.Revision 106 destTask.Priority = srcTask.Priority 107 destTask.LastHeartbeat = srcTask.LastHeartbeat 108 destTask.Activated = srcTask.Activated 109 destTask.BuildId = srcTask.BuildId 110 destTask.DistroId = srcTask.DistroId 111 destTask.BuildVariant = srcTask.BuildVariant 112 destTask.DependsOn = srcTask.DependsOn 113 destTask.DisplayName = srcTask.DisplayName 114 destTask.HostId = srcTask.HostId 115 destTask.Restarts = srcTask.Restarts 116 destTask.Execution = srcTask.Execution 117 destTask.Archived = srcTask.Archived 118 destTask.RevisionOrderNumber = srcTask.RevisionOrderNumber 119 destTask.Requester = srcTask.Requester 120 destTask.Status = srcTask.Status 121 destTask.Aborted = srcTask.Aborted 122 destTask.TimeTaken = srcTask.TimeTaken 123 destTask.ExpectedDuration = srcTask.ExpectedDuration 124 125 var err error 126 destTask.MinQueuePos, err = model.FindMinimumQueuePositionForTask(destTask.Id) 127 if err != nil { 128 msg := fmt.Sprintf("Error calculating task queue position for '%v'", srcTask.Id) 129 grip.Errorf("%v: %+v", msg, err) 130 restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg}) 131 return 132 } 133 134 if destTask.MinQueuePos < 0 { 135 destTask.MinQueuePos = 0 136 } 137 138 // Copy over the status details 139 destTask.StatusDetails.TimedOut = srcTask.Details.TimedOut 140 destTask.StatusDetails.TimeoutStage = srcTask.Details.Description 141 142 // Copy over the test results 143 destTask.TestResults = make(taskTestResultsByName, len(srcTask.TestResults)) 144 for _, _testResult := range srcTask.TestResults { 145 numSecs := _testResult.EndTime - _testResult.StartTime 146 testResult := taskTestResult{ 147 Status: _testResult.Status, 148 TimeTaken: time.Duration(numSecs * float64(time.Second)), 149 Logs: taskTestLogURL{_testResult.URL}, 150 } 151 destTask.TestResults[_testResult.TestFile] = testResult 152 } 153 154 // Copy over artifacts and binaries 155 entries, err := artifact.FindAll(artifact.ByTaskId(srcTask.Id)) 156 if err != nil { 157 msg := fmt.Sprintf("Error finding task '%v'", srcTask.Id) 158 grip.Errorf("%v: %+v", msg, err) 159 restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg}) 160 return 161 162 } 163 for _, entry := range entries { 164 for _, _file := range entry.Files { 165 file := taskFile{ 166 Name: _file.Name, 167 URL: _file.Link, 168 } 169 destTask.Files = append(destTask.Files, file) 170 } 171 } 172 173 if projCtx.Patch != nil { 174 destTask.PatchNumber = projCtx.Patch.PatchNumber 175 destTask.PatchId = projCtx.Patch.Id.Hex() 176 } 177 178 restapi.WriteJSON(w, http.StatusOK, destTask) 179 return 180 181 } 182 183 // getTaskStatus returns a JSON response with the status of the specified task. 184 // The keys of the object are the test names. 185 func (restapi restAPI) getTaskStatus(w http.ResponseWriter, r *http.Request) { 186 projCtx := MustHaveRESTContext(r) 187 task := projCtx.Task 188 if task == nil { 189 restapi.WriteJSON(w, http.StatusNotFound, responseError{Message: "error finding task"}) 190 return 191 } 192 193 result := taskStatusContent{ 194 Id: task.Id, 195 Name: task.DisplayName, 196 Status: task.Status, 197 } 198 199 // Copy over the status details 200 result.StatusDetails.TimedOut = task.Details.TimedOut 201 result.StatusDetails.TimeoutStage = task.Details.Description 202 203 // Copy over the test results 204 result.Tests = make(taskStatusByTest, len(task.TestResults)) 205 for _, _testResult := range task.TestResults { 206 numSecs := _testResult.EndTime - _testResult.StartTime 207 testResult := taskTestResult{ 208 Status: _testResult.Status, 209 TimeTaken: time.Duration(numSecs * float64(time.Second)), 210 Logs: taskTestLogURL{_testResult.URL}, 211 } 212 result.Tests[_testResult.TestFile] = testResult 213 } 214 215 restapi.WriteJSON(w, http.StatusOK, result) 216 return 217 218 }