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  }