forked from cloudfoundry/go-cfclient
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtasks.go
204 lines (178 loc) · 6.07 KB
/
tasks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package cfclient
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/url"
"time"
"github.com/pkg/errors"
)
// TaskListResponse is the JSON response from the API.
type TaskListResponse struct {
Pagination Pagination `json:"pagination"`
Tasks []Task `json:"resources"`
}
// Task is a description of a task element.
type Task struct {
GUID string `json:"guid"`
SequenceID int `json:"sequence_id"`
Name string `json:"name"`
Command string `json:"command"`
State string `json:"state"`
MemoryInMb int `json:"memory_in_mb"`
DiskInMb int `json:"disk_in_mb"`
Result struct {
FailureReason string `json:"failure_reason"`
} `json:"result"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DropletGUID string `json:"droplet_guid"`
Links struct {
Self Link `json:"self"`
App Link `json:"app"`
Droplet Link `json:"droplet"`
} `json:"links"`
}
// TaskRequest is a v3 JSON object as described in:
// http://v3-apidocs.cloudfoundry.org/version/3.0.0/index.html#create-a-task
type TaskRequest struct {
Command string `json:"command"`
Name string `json:"name"`
MemoryInMegabyte int `json:"memory_in_mb"`
DiskInMegabyte int `json:"disk_in_mb"`
DropletGUID string `json:"droplet_guid"`
}
func (c *Client) makeTaskListRequestWithParams(baseUrl string, query url.Values) ([]byte, error) {
requestUrl := baseUrl + "?" + query.Encode()
req := c.NewRequest("GET", requestUrl)
resp, err := c.DoRequest(req)
if err != nil {
return nil, errors.Wrap(err, "Error requesting tasks")
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, errors.Wrapf(err, "Error requesting tasks: status code not 200, it was %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
func parseTaskListRespones(answer []byte) (TaskListResponse, error) {
var response TaskListResponse
err := json.Unmarshal(answer, &response)
if err != nil {
return response, errors.Wrap(err, "Error unmarshaling response %v")
}
return response, nil
}
func (c *Client) handleTasksApiCall(apiUrl string, query url.Values) ([]Task, error) {
body, err := c.makeTaskListRequestWithParams(apiUrl, query)
if err != nil {
return nil, errors.Wrap(err, "Error requesting tasks")
}
response, err := parseTaskListRespones(body)
if err != nil {
return nil, errors.Wrap(err, "Error reading tasks")
}
return response.Tasks, nil
}
// ListTasks returns all tasks the user has access to.
// See http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks
func (c *Client) ListTasks() ([]Task, error) {
return c.handleTasksApiCall("/v3/tasks", url.Values{})
}
// ListTasksByQuery returns all tasks the user has access to, with query parameters.
// See http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks
func (c *Client) ListTasksByQuery(query url.Values) ([]Task, error) {
return c.handleTasksApiCall("/v3/tasks", query)
}
// TasksByApp returns task structures which aligned to an app identified by the given guid.
// See: http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks-for-an-app
func (c *Client) TasksByApp(guid string) ([]Task, error) {
return c.TasksByAppByQuery(guid, url.Values{})
}
// TasksByAppByQuery returns task structures which aligned to an app identified by the given guid
// and filtered by the given query parameters.
// See: http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks-for-an-app
func (c *Client) TasksByAppByQuery(guid string, query url.Values) ([]Task, error) {
uri := fmt.Sprintf("/v3/apps/%s/tasks", guid)
return c.handleTasksApiCall(uri, query)
}
func createReader(tr TaskRequest) (io.Reader, error) {
rmap := make(map[string]string)
rmap["command"] = tr.Command
if tr.Name != "" {
rmap["name"] = tr.Name
}
// setting droplet GUID causing issues
if tr.MemoryInMegabyte != 0 {
rmap["memory_in_mb"] = fmt.Sprintf("%d", tr.MemoryInMegabyte)
}
if tr.DiskInMegabyte != 0 {
rmap["disk_in_mb"] = fmt.Sprintf("%d", tr.DiskInMegabyte)
}
bodyReader := bytes.NewBuffer(nil)
enc := json.NewEncoder(bodyReader)
if err := enc.Encode(rmap); err != nil {
return nil, errors.Wrap(err, "Error during encoding task request")
}
return bodyReader, nil
}
// CreateTask creates a new task in CF system and returns its structure.
func (c *Client) CreateTask(tr TaskRequest) (task Task, err error) {
bodyReader, err := createReader(tr)
if err != nil {
return task, err
}
request := fmt.Sprintf("/v3/apps/%s/tasks", tr.DropletGUID)
req := c.NewRequestWithBody("POST", request, bodyReader)
resp, err := c.DoRequest(req)
if err != nil {
return task, errors.Wrap(err, "Error creating task")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return task, errors.Wrap(err, "Error reading task after creation")
}
err = json.Unmarshal(body, &task)
if err != nil {
return task, errors.Wrap(err, "Error unmarshaling task")
}
return task, err
}
// GetTaskByGuid returns a task structure by requesting it with the tasks GUID.
func (c *Client) GetTaskByGuid(guid string) (task Task, err error) {
request := fmt.Sprintf("/v3/tasks/%s", guid)
req := c.NewRequest("GET", request)
resp, err := c.DoRequest(req)
if err != nil {
return task, errors.Wrap(err, "Error requesting task")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return task, errors.Wrap(err, "Error reading task")
}
err = json.Unmarshal(body, &task)
if err != nil {
return task, errors.Wrap(err, "Error unmarshaling task")
}
return task, err
}
func (c *Client) TaskByGuid(guid string) (task Task, err error) {
return c.GetTaskByGuid(guid)
}
// TerminateTask cancels a task identified by its GUID.
func (c *Client) TerminateTask(guid string) error {
req := c.NewRequest("PUT", fmt.Sprintf("/v3/tasks/%s/cancel", guid))
resp, err := c.DoRequest(req)
if err != nil {
return errors.Wrap(err, "Error terminating task")
}
defer resp.Body.Close()
if resp.StatusCode != 202 {
return errors.Wrapf(err, "Failed terminating task, response status code %d", resp.StatusCode)
}
return nil
}