github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/service/task_queue.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/evergreen-ci/evergreen" 9 "github.com/evergreen-ci/evergreen/model" 10 "github.com/evergreen-ci/evergreen/model/distro" 11 "github.com/evergreen-ci/evergreen/model/host" 12 "github.com/evergreen-ci/evergreen/model/patch" 13 "github.com/evergreen-ci/evergreen/model/task" 14 "github.com/evergreen-ci/evergreen/model/user" 15 "github.com/mongodb/grip" 16 "github.com/pkg/errors" 17 ) 18 19 // ui version of a task queue item 20 type uiTaskQueueItem struct { 21 Id string `json:"_id"` 22 DisplayName string `json:"display_name"` 23 BuildVariant string `json:"build_variant"` 24 RevisionOrderNumber int `json:"order"` 25 Requester string `json:"requester"` 26 Revision string `json:"gitspec"` 27 Project string `json:"project"` 28 Version string `json:"version"` 29 Build string `json:"build"` 30 ExpectedDuration time.Duration `json:"exp_dur"` 31 Priority int64 `json:"priority"` 32 33 // only if it's a patch request task 34 User string `json:"user,omitempty"` 35 } 36 37 // ui version of a task queue, for wrapping the ui versions of task queue 38 // items 39 type uiTaskQueue struct { 40 Distro string `json:"distro"` 41 Queue []uiTaskQueueItem `json:"queue"` 42 } 43 44 // top-level ui struct for holding information on task 45 // queues and host usage 46 type uiResourceInfo struct { 47 TaskQueues []uiTaskQueue `json:"task_queues"` 48 HostStatistics uiHostStatistics `json:"host_stats"` 49 Distros []string `json:"distros"` 50 } 51 52 // information on host utilization 53 type uiHostStatistics struct { 54 IdleHosts int `json:"idle_hosts"` 55 ActiveHosts int `json:"active_hosts"` 56 ActiveStaticHosts int `json:"active_static_hosts"` 57 IdleStaticHosts int `json:"idle_static_hosts"` 58 } 59 60 func (uis *UIServer) allTaskQueues(w http.ResponseWriter, r *http.Request) { 61 projCtx := MustHaveProjectContext(r) 62 63 taskQueues, err := model.FindAllTaskQueues() 64 if err != nil { 65 uis.LoggedError(w, r, http.StatusInternalServerError, 66 errors.Wrap(err, "Error finding task queues")) 67 return 68 } 69 70 // find all distros so that we only display task queues of distros that exist. 71 allDistros, err := distro.Find(distro.All.WithFields(distro.IdKey)) 72 if err != nil { 73 message := fmt.Sprintf("error fetching distros: %v", err) 74 http.Error(w, message, http.StatusInternalServerError) 75 return 76 } 77 distroIds := []string{} 78 for _, d := range allDistros { 79 distroIds = append(distroIds, d.Id) 80 } 81 82 // cached map of version id to relevant patch 83 cachedPatches := map[string]*patch.Patch{} 84 85 // convert the task queues to the ui versions 86 uiTaskQueues := []uiTaskQueue{} 87 var tasks []task.Task 88 89 for _, tQ := range taskQueues { 90 asUI := uiTaskQueue{ 91 Distro: tQ.Distro, 92 Queue: []uiTaskQueueItem{}, 93 } 94 95 if len(tQ.Queue) == 0 { 96 uiTaskQueues = append(uiTaskQueues, asUI) 97 continue 98 } 99 100 // convert the individual task queue items 101 taskIds := []string{} 102 for _, item := range tQ.Queue { 103 104 // cache the ids, for fetching the tasks from the db 105 taskIds = append(taskIds, item.Id) 106 107 queueItemAsUI := uiTaskQueueItem{ 108 Id: item.Id, 109 DisplayName: item.DisplayName, 110 BuildVariant: item.BuildVariant, 111 RevisionOrderNumber: item.RevisionOrderNumber, 112 Requester: item.Requester, 113 Revision: item.Revision, 114 Project: item.Project, 115 ExpectedDuration: item.ExpectedDuration, 116 Priority: item.Priority, 117 } 118 119 asUI.Queue = append(asUI.Queue, queueItemAsUI) 120 } 121 122 // find all the relevant tasks 123 tasks, err = task.Find(task.ByIds(taskIds).WithFields(task.VersionKey, task.BuildIdKey)) 124 if err != nil { 125 msg := fmt.Sprintf("Error finding tasks: %v", err) 126 grip.Error(msg) 127 http.Error(w, msg, http.StatusInternalServerError) 128 return 129 } 130 131 // store all of the version and build ids in the relevant task queue 132 // items 133 for _, task := range tasks { 134 // this sucks, but it's because we're not guaranteed the order out 135 // of the db 136 for idx, queueItemAsUI := range asUI.Queue { 137 if queueItemAsUI.Id == task.Id { 138 queueItemAsUI.Version = task.Version 139 queueItemAsUI.Build = task.BuildId 140 asUI.Queue[idx] = queueItemAsUI 141 } 142 } 143 } 144 145 // add all of the necessary patch info into the relevant task queue 146 // items 147 for idx, queueItemAsUI := range asUI.Queue { 148 if queueItemAsUI.Requester == evergreen.PatchVersionRequester { 149 // fetch the patch, if necessary 150 var p *patch.Patch 151 var ok bool 152 if p, ok = cachedPatches[queueItemAsUI.Version]; ok { 153 queueItemAsUI.User = p.Author 154 asUI.Queue[idx] = queueItemAsUI 155 } else { 156 p, err = patch.FindOne( 157 patch.ByVersion(queueItemAsUI.Version).WithFields(patch.AuthorKey), 158 ) 159 if err != nil { 160 msg := fmt.Sprintf("Error finding patch: %v", err) 161 grip.Error(msg) 162 http.Error(w, msg, http.StatusInternalServerError) 163 return 164 } 165 if p == nil { 166 msg := fmt.Sprintf("Couldn't find patch for version %v", queueItemAsUI.Version) 167 grip.Error(msg) 168 http.Error(w, msg, http.StatusInternalServerError) 169 return 170 } 171 cachedPatches[queueItemAsUI.Version] = p 172 } 173 queueItemAsUI.User = p.Author 174 asUI.Queue[idx] = queueItemAsUI 175 176 } 177 } 178 179 uiTaskQueues = append(uiTaskQueues, asUI) 180 181 } 182 183 // add other useful statistics to view alongside queue 184 idleHosts, err := host.Find(host.IsIdle) 185 if err != nil { 186 msg := fmt.Sprintf("Error finding idle hosts: %v", err) 187 grip.Error(msg) 188 http.Error(w, msg, http.StatusInternalServerError) 189 return 190 } 191 activeHosts, err := host.Find(host.IsLive) 192 if err != nil { 193 msg := fmt.Sprintf("Error finding active hosts: %v", err) 194 grip.Error(msg) 195 http.Error(w, msg, http.StatusInternalServerError) 196 return 197 } 198 idleStaticHostsCount := 0 199 for _, host := range idleHosts { 200 if host.Provider == evergreen.HostTypeStatic { 201 idleStaticHostsCount++ 202 } 203 } 204 activeStaticHostsCount := 0 205 for _, host := range activeHosts { 206 if host.Provider == evergreen.HostTypeStatic { 207 activeStaticHostsCount++ 208 } 209 } 210 hostStats := uiHostStatistics{ 211 ActiveHosts: len(activeHosts), 212 ActiveStaticHosts: activeStaticHostsCount, 213 IdleHosts: len(idleHosts), 214 IdleStaticHosts: idleStaticHostsCount, 215 } 216 217 uis.WriteHTML(w, http.StatusOK, struct { 218 ProjectData projectContext 219 User *user.DBUser 220 Flashes []interface{} 221 Data uiResourceInfo 222 }{projCtx, GetUser(r), []interface{}{}, uiResourceInfo{uiTaskQueues, hostStats, distroIds}}, 223 "base", "task_queues.html", "base_angular.html", "menu.html") 224 }