github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+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 if jobURL == "" { 94 return nil, nil 95 } 96 97 var ( 98 err error 99 warnings Warnings 100 allWarnings Warnings 101 job Job 102 ) 103 104 startTime := client.clock.Now() 105 for client.clock.Now().Sub(startTime) < client.jobPollingTimeout { 106 job, warnings, err = client.GetJob(jobURL) 107 allWarnings = append(allWarnings, warnings...) 108 if err != nil { 109 return allWarnings, err 110 } 111 112 if job.HasFailed() { 113 if len(job.Errors()) > 0 { 114 firstError := job.Errors()[0] 115 return allWarnings, firstError 116 } else { 117 return allWarnings, ccerror.JobFailedNoErrorError{ 118 JobGUID: job.GUID, 119 } 120 } 121 } 122 123 if job.IsComplete() { 124 return allWarnings, nil 125 } 126 127 time.Sleep(client.jobPollingInterval) 128 } 129 130 return allWarnings, ccerror.JobTimeoutError{ 131 JobGUID: job.GUID, 132 Timeout: client.jobPollingTimeout, 133 } 134 }