github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+incompatible/api/cloudcontroller/ccv2/job.go (about) 1 package ccv2 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/url" 7 "time" 8 9 "code.cloudfoundry.org/cli/api/cloudcontroller" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/internal" 11 ) 12 13 // JobFailedError represents a failed Cloud Controller Job. It wraps the error 14 // returned back from the Cloud Controller. 15 type JobFailedError struct { 16 JobGUID string 17 Message string 18 } 19 20 func (e JobFailedError) Error() string { 21 return fmt.Sprintf("Job (%s) failed: %s", e.JobGUID, e.Message) 22 } 23 24 // JobTimeoutError is returned from PollJob when the OverallPollingTimeout has 25 // been reached. 26 type JobTimeoutError struct { 27 JobGUID string 28 Timeout time.Duration 29 } 30 31 func (e JobTimeoutError) Error() string { 32 return fmt.Sprintf("Job (%s) polling has reached the maximum timeout of %s seconds", e.JobGUID, e.Timeout) 33 } 34 35 // JobStatus is the current state of a job. 36 type JobStatus string 37 38 const ( 39 // JobStatusFailed is when the job is no longer running due to a failure. 40 JobStatusFailed JobStatus = "failed" 41 42 // JobStatusFinished is when the job is no longer and it was successful. 43 JobStatusFinished JobStatus = "finished" 44 45 // JobStatusQueued is when the job is waiting to be run. 46 JobStatusQueued JobStatus = "queued" 47 48 // JobStatusRunning is when the job is running. 49 JobStatusRunning JobStatus = "running" 50 ) 51 52 // Job represents a Cloud Controller Job. 53 type Job struct { 54 Error string 55 GUID string 56 Status JobStatus 57 } 58 59 // UnmarshalJSON helps unmarshal a Cloud Controller Job response. 60 func (job *Job) UnmarshalJSON(data []byte) error { 61 var ccJob struct { 62 Entity struct { 63 Error string `json:"error"` 64 GUID string `json:"guid"` 65 Status string `json:"status"` 66 } `json:"entity"` 67 Metadata internal.Metadata `json:"metadata"` 68 } 69 if err := json.Unmarshal(data, &ccJob); err != nil { 70 return err 71 } 72 73 job.Error = ccJob.Entity.Error 74 job.GUID = ccJob.Entity.GUID 75 job.Status = JobStatus(ccJob.Entity.Status) 76 return nil 77 } 78 79 // Finished returns true when the job has completed successfully. 80 func (job Job) Finished() bool { 81 return job.Status == JobStatusFinished 82 } 83 84 // Failed returns true when the job has completed with an error/failure. 85 func (job Job) Failed() bool { 86 return job.Status == JobStatusFailed 87 } 88 89 // GetJob returns a job for the provided GUID. 90 func (client *Client) GetJob(jobGUID string) (Job, Warnings, error) { 91 request, err := client.newHTTPRequest(requestOptions{ 92 RequestName: internal.JobRequest, 93 URIParams: map[string]string{"job_guid": jobGUID}, 94 }) 95 if err != nil { 96 return Job{}, nil, err 97 } 98 99 var job Job 100 response := cloudcontroller.Response{ 101 Result: &job, 102 } 103 104 err = client.connection.Make(request, &response) 105 return job, response.Warnings, err 106 } 107 108 // PollJob will keep polling the given job until the job has terminated, an 109 // error is encountered, or config.OverallPollingTimeout is reached. In the 110 // last case, a JobTimeoutError is returned. 111 func (client *Client) PollJob(job Job) (Warnings, error) { 112 originalJobGUID := job.GUID 113 114 var ( 115 err error 116 warnings Warnings 117 allWarnings Warnings 118 ) 119 120 startTime := time.Now() 121 for time.Now().Sub(startTime) < client.jobPollingTimeout { 122 job, warnings, err = client.GetJob(job.GUID) 123 allWarnings = append(allWarnings, Warnings(warnings)...) 124 if err != nil { 125 return allWarnings, err 126 } 127 128 if job.Failed() { 129 return allWarnings, JobFailedError{ 130 JobGUID: originalJobGUID, 131 Message: job.Error, 132 } 133 } 134 135 if job.Finished() { 136 return allWarnings, nil 137 } 138 139 time.Sleep(client.jobPollingInterval) 140 } 141 142 return allWarnings, JobTimeoutError{ 143 JobGUID: originalJobGUID, 144 Timeout: client.jobPollingTimeout, 145 } 146 } 147 148 // DeleteOrganization deletes the Organization associated with the provided 149 // GUID. It will return the Cloud Controller job that is assigned to the 150 // organization deletion. 151 func (client *Client) DeleteOrganization(orgGUID string) (Job, Warnings, error) { 152 request, err := client.newHTTPRequest(requestOptions{ 153 RequestName: internal.DeleteOrganizationRequest, 154 URIParams: map[string]string{"organization_guid": orgGUID}, 155 Query: url.Values{ 156 "recursive": {"true"}, 157 "async": {"true"}, 158 }, 159 }) 160 if err != nil { 161 return Job{}, nil, err 162 } 163 164 var job Job 165 response := cloudcontroller.Response{ 166 Result: &job, 167 } 168 169 err = client.connection.Make(request, &response) 170 return job, response.Warnings, err 171 }