-
Notifications
You must be signed in to change notification settings - Fork 86
/
cloudbrain_client.go
130 lines (105 loc) · 3.22 KB
/
cloudbrain_client.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
package backend
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
"github.com/cenk/backoff"
"github.com/pkg/errors"
)
type cbInstanceData struct {
ID string `json:"id"`
Image string `json:"image"`
IPAddress string `json:"ip_address"`
Provider string `json:"provider"`
State string `json:"state"`
UpstreamID string `json:"upstream_id"`
ErrorReason string `json:"error_reason"`
}
type cbInstanceRequest struct {
Provider string `json:"provider"`
Image string `json:"image"`
InstanceType string `json:"instance_type"`
PublicSSHKey string `json:"public_ssh_key"`
}
type cbClient struct {
baseURL *url.URL
provider string
httpClient *http.Client
}
func (c *cbClient) Create(instRequest *cbInstanceRequest) (*cbInstanceData, error) {
u, err := c.baseURL.Parse("instances")
if err != nil {
return nil, errors.Wrap(err, "error creating instance create URL")
}
jsonBody, err := json.Marshal(instRequest)
if err != nil {
return nil, errors.Wrap(err, "couldn't marshal instance create request to JSON")
}
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(jsonBody))
if err != nil {
return nil, errors.Wrap(err, "error creating instance create request")
}
instance, err := c.httpRequest(req, 200)
if err != nil {
return nil, errors.Wrap(err, "error creating instance")
}
return instance, nil
}
func (c *cbClient) Get(id string) (*cbInstanceData, error) {
u, err := c.baseURL.Parse(fmt.Sprintf("instances/%s", url.QueryEscape(id)))
if err != nil {
return nil, errors.Wrap(err, "error creating instance get URL")
}
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, errors.Wrap(err, "error creating instance get request")
}
instance, err := c.httpRequest(req, 200)
if err != nil {
return nil, errors.Wrap(err, "error getting instance")
}
return instance, nil
}
func (c *cbClient) Delete(id string) (*cbInstanceData, error) {
u, err := c.baseURL.Parse(fmt.Sprintf("instances/%s", url.QueryEscape(id)))
if err != nil {
return nil, errors.Wrap(err, "error creating instance delete URL")
}
req, err := http.NewRequest("DELETE", u.String(), nil)
if err != nil {
return nil, errors.Wrap(err, "error creating instance delete request")
}
instance, err := c.httpRequest(req, 200)
if err != nil {
return nil, errors.Wrap(err, "error deleting instance")
}
return instance, nil
}
func (c *cbClient) httpRequest(req *http.Request, expectedStatus int) (*cbInstanceData, error) {
b := backoff.NewExponentialBackOff()
b.MaxInterval = 10 * time.Second
b.MaxElapsedTime = time.Minute
var resp *http.Response
err := backoff.Retry(func() (err error) {
resp, err = c.httpClient.Do(req)
return
}, b)
if err != nil {
return nil, errors.Wrap(err, "error sending request")
}
defer resp.Body.Close()
if resp.StatusCode != expectedStatus {
body := new(bytes.Buffer)
body.ReadFrom(resp.Body)
return nil, errors.Errorf("expected %v response code, got status=%v body=%v", expectedStatus, resp.StatusCode, body.String())
}
instance := &cbInstanceData{}
err = json.NewDecoder(resp.Body).Decode(instance)
if err != nil {
return nil, errors.Wrap(err, "couldn't decode json response")
}
return instance, nil
}