github.com/orange-cloudfoundry/cli@v7.1.0+incompatible/api/cloudcontroller/ccv3/job.go (about)

     1  package ccv3
     2  
     3  import (
     4  	"time"
     5  
     6  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
     8  )
     9  
    10  // Job represents a Cloud Controller Job.
    11  type Job struct {
    12  	// RawErrors is a list of errors that occurred while processing the job.
    13  	RawErrors []JobErrorDetails `json:"errors"`
    14  	// GUID is a unique identifier for the job.
    15  	GUID string `json:"guid"`
    16  	// State is the state of the job.
    17  	State constant.JobState `json:"state"`
    18  	// Warnings are the warnings emitted by the job during its processing.
    19  	Warnings []jobWarning `json:"warnings"`
    20  }
    21  
    22  // Errors returns back a list of
    23  func (job Job) Errors() []error {
    24  	var errs []error
    25  	for _, errDetails := range job.RawErrors {
    26  		switch errDetails.Code {
    27  		case constant.JobErrorCodeBuildpackAlreadyExistsForStack:
    28  			errs = append(errs, ccerror.BuildpackAlreadyExistsForStackError{Message: errDetails.Detail})
    29  		case constant.JobErrorCodeBuildpackInvalid:
    30  			errs = append(errs, ccerror.BuildpackInvalidError{Message: errDetails.Detail})
    31  		case constant.JobErrorCodeBuildpackStacksDontMatch:
    32  			errs = append(errs, ccerror.BuildpackStacksDontMatchError{Message: errDetails.Detail})
    33  		case constant.JobErrorCodeBuildpackStackDoesNotExist:
    34  			errs = append(errs, ccerror.BuildpackStackDoesNotExistError{Message: errDetails.Detail})
    35  		case constant.JobErrorCodeBuildpackZipInvalid:
    36  			errs = append(errs, ccerror.BuildpackZipInvalidError{Message: errDetails.Detail})
    37  		default:
    38  			errs = append(errs, ccerror.V3JobFailedError{
    39  				JobGUID: job.GUID,
    40  				Code:    errDetails.Code,
    41  				Detail:  errDetails.Detail,
    42  				Title:   errDetails.Title,
    43  			})
    44  		}
    45  	}
    46  	return errs
    47  }
    48  
    49  // HasFailed returns true when the job has completed with an error/failure.
    50  func (job Job) HasFailed() bool {
    51  	return job.State == constant.JobFailed
    52  }
    53  
    54  // IsComplete returns true when the job has completed successfully.
    55  func (job Job) IsComplete() bool {
    56  	return job.State == constant.JobComplete
    57  }
    58  
    59  type jobWarning struct {
    60  	Detail string `json:"detail"`
    61  }
    62  
    63  // JobErrorDetails provides information regarding a job's error.
    64  type JobErrorDetails struct {
    65  	// Code is a numeric code for this error.
    66  	Code constant.JobErrorCode `json:"code"`
    67  	// Detail is a verbose description of the error.
    68  	Detail string `json:"detail"`
    69  	// Title is a short description of the error.
    70  	Title string `json:"title"`
    71  }
    72  
    73  // GetJob returns a job for the provided GUID.
    74  func (client *Client) GetJob(jobURL JobURL) (Job, Warnings, error) {
    75  	var responseBody Job
    76  
    77  	_, warnings, err := client.MakeRequest(RequestParams{
    78  		URL:          string(jobURL),
    79  		ResponseBody: &responseBody,
    80  	})
    81  
    82  	for _, jobWarning := range responseBody.Warnings {
    83  		warnings = append(warnings, jobWarning.Detail)
    84  	}
    85  
    86  	return responseBody, warnings, err
    87  }
    88  
    89  // PollJob will keep polling the given job until the job has terminated, an
    90  // error is encountered, or config.OverallPollingTimeout is reached. In the
    91  // last case, a JobTimeoutError is returned.
    92  func (client *Client) PollJob(jobURL JobURL) (Warnings, error) {
    93  	var (
    94  		err         error
    95  		warnings    Warnings
    96  		allWarnings Warnings
    97  		job         Job
    98  	)
    99  
   100  	startTime := client.clock.Now()
   101  	for client.clock.Now().Sub(startTime) < client.jobPollingTimeout {
   102  		job, warnings, err = client.GetJob(jobURL)
   103  		allWarnings = append(allWarnings, warnings...)
   104  		if err != nil {
   105  			return allWarnings, err
   106  		}
   107  
   108  		if job.HasFailed() {
   109  			firstError := job.Errors()[0]
   110  			return allWarnings, firstError
   111  		}
   112  
   113  		if job.IsComplete() {
   114  			return allWarnings, nil
   115  		}
   116  
   117  		time.Sleep(client.jobPollingInterval)
   118  	}
   119  
   120  	return allWarnings, ccerror.JobTimeoutError{
   121  		JobGUID: job.GUID,
   122  		Timeout: client.jobPollingTimeout,
   123  	}
   124  }