github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/route/host_routes.go (about) 1 package route 2 3 import ( 4 "net/http" 5 6 "github.com/evergreen-ci/evergreen" 7 "github.com/evergreen-ci/evergreen/apiv3" 8 "github.com/evergreen-ci/evergreen/apiv3/model" 9 "github.com/evergreen-ci/evergreen/apiv3/servicecontext" 10 "github.com/evergreen-ci/evergreen/model/host" 11 "github.com/evergreen-ci/evergreen/model/task" 12 "github.com/pkg/errors" 13 ) 14 15 type hostGetHandler struct { 16 *PaginationExecutor 17 } 18 19 func getHostRouteManager(route string, version int) *RouteManager { 20 hgh := &hostGetHandler{} 21 hostGet := MethodHandler{ 22 Authenticator: &NoAuthAuthenticator{}, 23 RequestHandler: hgh.Handler(), 24 MethodType: evergreen.MethodGet, 25 } 26 27 hostRoute := RouteManager{ 28 Route: route, 29 Methods: []MethodHandler{hostGet}, 30 Version: version, 31 } 32 return &hostRoute 33 } 34 35 func (hgh *hostGetHandler) Handler() RequestHandler { 36 hostPaginationExecutor := &PaginationExecutor{ 37 KeyQueryParam: "host_id", 38 LimitQueryParam: "limit", 39 Paginator: hostPaginator, 40 Args: hostGetArgs{}, 41 } 42 return &hostGetHandler{hostPaginationExecutor} 43 } 44 45 type hostGetArgs struct { 46 status string 47 } 48 49 func (hgh *hostGetHandler) ParseAndValidate(r *http.Request) error { 50 hgh.Args = hostGetArgs{ 51 status: r.URL.Query().Get("status"), 52 } 53 return hgh.PaginationExecutor.ParseAndValidate(r) 54 } 55 56 // hostPaginator is an instance of a PaginatorFunc that defines how to paginate on 57 // the host collection. 58 func hostPaginator(key string, limit int, args interface{}, sc servicecontext.ServiceContext) ([]model.Model, 59 *PageResult, error) { 60 // Fetch this page of hosts, plus the next one 61 // Perhaps these could be cached in case user is making multiple calls idk? 62 hpArgs, ok := args.(hostGetArgs) 63 if !ok { 64 panic("Wrong args type passed in for host paginator") 65 } 66 hosts, err := sc.FindHostsById(key, hpArgs.status, limit*2, 1) 67 if err != nil { 68 if apiErr, ok := err.(apiv3.APIError); !ok || apiErr.StatusCode != http.StatusNotFound { 69 err = errors.Wrap(err, "Database error") 70 } 71 return []model.Model{}, nil, err 72 } 73 nextPage := makeNextHostsPage(hosts, limit) 74 75 // Make the previous page 76 prevHosts, err := sc.FindHostsById(key, hpArgs.status, limit, -1) 77 if err != nil { 78 if apiErr, ok := err.(apiv3.APIError); !ok || apiErr.StatusCode != http.StatusNotFound { 79 return []model.Model{}, nil, errors.Wrap(err, "Database error") 80 } 81 } 82 83 prevPage := makePrevHostsPage(prevHosts) 84 85 pageResults := &PageResult{ 86 Next: nextPage, 87 Prev: prevPage, 88 } 89 90 lastIndex := len(hosts) 91 if nextPage != nil { 92 lastIndex = limit 93 } 94 95 // Truncate the hosts to just those that will be returned. 96 hosts = hosts[:lastIndex] 97 98 // Grab the taskIds associated as running on the hosts. 99 taskIds := []string{} 100 for _, h := range hosts { 101 if h.RunningTask != "" { 102 taskIds = append(taskIds, h.RunningTask) 103 } 104 } 105 106 tasks, err := sc.FindTasksByIds(taskIds) 107 if err != nil { 108 if apiErr, ok := err.(*apiv3.APIError); !ok || 109 (ok && apiErr.StatusCode != http.StatusNotFound) { 110 return []model.Model{}, nil, errors.Wrap(err, "Database error") 111 } 112 } 113 models, err := makeHostModelsWithTasks(hosts, tasks) 114 if err != nil { 115 return []model.Model{}, &PageResult{}, err 116 } 117 return models, pageResults, nil 118 } 119 120 func makeHostModelsWithTasks(hosts []host.Host, tasks []task.Task) ([]model.Model, error) { 121 // Build a map of tasks indexed by their Id to make them easily referenceable. 122 tasksById := make(map[string]task.Task, len(tasks)) 123 for _, t := range tasks { 124 tasksById[t.Id] = t 125 } 126 // Create a list of host models. 127 models := make([]model.Model, len(hosts)) 128 for ix, h := range hosts { 129 apiHost := model.APIHost{} 130 err := apiHost.BuildFromService(h) 131 if err != nil { 132 return []model.Model{}, err 133 } 134 if h.RunningTask != "" { 135 runningTask, ok := tasksById[h.RunningTask] 136 if !ok { 137 continue 138 } 139 // Add the task information to the host document. 140 err := apiHost.BuildFromService(runningTask) 141 if err != nil { 142 return []model.Model{}, err 143 } 144 } 145 // Put the model into the array 146 models[ix] = &apiHost 147 } 148 return models, nil 149 150 } 151 152 func makeNextHostsPage(hosts []host.Host, limit int) *Page { 153 var nextPage *Page 154 if len(hosts) > limit { 155 nextLimit := len(hosts) - limit 156 nextPage = &Page{ 157 Relation: "next", 158 Key: hosts[limit].Id, 159 Limit: nextLimit, 160 } 161 } 162 return nextPage 163 } 164 165 func makePrevHostsPage(hosts []host.Host) *Page { 166 var prevPage *Page 167 if len(hosts) > 1 { 168 prevPage = &Page{ 169 Relation: "prev", 170 Key: hosts[0].Id, 171 Limit: len(hosts), 172 } 173 } 174 return prevPage 175 }