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  }