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  }