open-vault/vendor/github.com/cloudfoundry-community/go-cfclient/tasks.go
2019-06-06 12:26:04 -07:00

205 lines
6.1 KiB
Go

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
}