45
func NewOpenStackClient(creds *identity.Credentials, auth_method int) *OpenStackClient {
44
func NewOpenStackClient(creds *identity.Credentials, auth_method identity.AuthMethod) *OpenStackClient {
46
45
client := OpenStackClient{creds: creds}
47
46
client.creds.URL = client.creds.URL + OS_API_TOKENS
48
47
switch auth_method {
50
49
panic(fmt.Errorf("Invalid identity authorisation method: %d", auth_method))
51
case identity.AUTH_LEGACY:
50
case identity.AuthLegacy:
52
51
client.auth = &identity.Legacy{}
53
case identity.AUTH_USERPASS:
52
case identity.AuthUserPass:
54
53
client.auth = &identity.UserPass{}
100
99
requestData := goosehttp.RequestData{RespValue: &resp}
101
err = c.authRequest(GET, "compute", OS_API_FLAVORS, nil, &requestData)
103
gooseerrors.AddErrorContext(&err, "failed to get list of flavors")
107
return resp.Flavors, nil
100
err = c.sendRequest(GET, "compute", OS_API_FLAVORS, &requestData, "failed to get list of flavors")
101
return resp.Flavors, err
110
104
type FlavorDetail struct {
122
116
Flavors []FlavorDetail
124
118
requestData := goosehttp.RequestData{RespValue: &resp}
125
err = c.authRequest(GET, "compute", OS_API_FLAVORS_DETAIL, nil, &requestData)
127
gooseerrors.AddErrorContext(&err, "failed to get list of flavors details")
131
return resp.Flavors, nil
119
err = c.sendRequest(GET, "compute", OS_API_FLAVORS_DETAIL, &requestData,
120
"failed to get list of flavors details")
121
return resp.Flavors, err
134
124
func (c *OpenStackClient) ListServers() (servers []Entity, err error) {
139
129
requestData := goosehttp.RequestData{RespValue: &resp, ExpectedStatus: []int{http.StatusOK}}
140
err = c.authRequest(GET, "compute", OS_API_SERVERS, nil, &requestData)
142
gooseerrors.AddErrorContext(&err, "failed to get list of servers")
145
return resp.Servers, nil
130
err = c.sendRequest(GET, "compute", OS_API_SERVERS, &requestData,
131
"failed to get list of servers")
132
return resp.Servers, err
148
135
type ServerDetail struct {
168
155
Servers []ServerDetail
170
157
requestData := goosehttp.RequestData{RespValue: &resp}
171
err = c.authRequest(GET, "compute", OS_API_SERVERS_DETAIL, nil, &requestData)
173
gooseerrors.AddErrorContext(&err, "failed to get list of servers details")
177
return resp.Servers, nil
158
err = c.sendRequest(GET, "compute", OS_API_SERVERS_DETAIL, &requestData,
159
"failed to get list of servers details")
160
return resp.Servers, err
180
163
func (c *OpenStackClient) GetServer(serverId string) (ServerDetail, error) {
185
168
url := fmt.Sprintf("%s/%s", OS_API_SERVERS, serverId)
186
169
requestData := goosehttp.RequestData{RespValue: &resp}
187
err := c.authRequest(GET, "compute", url, nil, &requestData)
189
gooseerrors.AddErrorContext(&err, "failed to get details for serverId=%s", serverId)
190
return ServerDetail{}, err
193
return resp.Server, nil
170
err := c.sendRequest(GET, "compute", url, &requestData,
171
"failed to get details for serverId=%s", serverId)
172
return resp.Server, err
196
func (c *OpenStackClient) DeleteServer(serverId string) error {
175
func (c *OpenStackClient) DeleteServer(serverId string) (err error) {
198
177
var resp struct {
199
178
Server ServerDetail
201
180
url := fmt.Sprintf("%s/%s", OS_API_SERVERS, serverId)
202
181
requestData := goosehttp.RequestData{RespValue: &resp, ExpectedStatus: []int{http.StatusNoContent}}
203
err := c.authRequest(DELETE, "compute", url, nil, &requestData)
205
gooseerrors.AddErrorContext(&err, "failed to delete server with serverId=%s", serverId)
182
err = c.sendRequest(DELETE, "compute", url, &requestData,
183
"failed to delete server with serverId=%s", serverId)
212
187
type RunServerOpts struct {
231
206
req.Server.UserData = &encoded
233
208
requestData := goosehttp.RequestData{ReqValue: req, ExpectedStatus: []int{http.StatusAccepted}}
234
err = c.authRequest(POST, "compute", OS_API_SERVERS, nil, &requestData)
236
gooseerrors.AddErrorContext(&err, "failed to run a server with %#v", opts)
209
err = c.sendRequest(POST, "compute", OS_API_SERVERS, &requestData,
210
"failed to run a server with %#v", opts)
263
235
Groups []SecurityGroup `json:"security_groups"`
265
237
requestData := goosehttp.RequestData{RespValue: &resp}
266
err = c.authRequest(GET, "compute", OS_API_SECURITY_GROUPS, nil, &requestData)
268
gooseerrors.AddErrorContext(&err, "failed to list security groups")
272
return resp.Groups, nil
238
err = c.sendRequest(GET, "compute", OS_API_SECURITY_GROUPS, &requestData,
239
"failed to list security groups")
240
return resp.Groups, err
275
243
func (c *OpenStackClient) GetServerSecurityGroups(serverId string) (groups []SecurityGroup, err error) {
280
248
url := fmt.Sprintf("%s/%s/%s", OS_API_SERVERS, serverId, OS_API_SECURITY_GROUPS)
281
249
requestData := goosehttp.RequestData{RespValue: &resp}
282
err = c.authRequest(GET, "compute", url, nil, &requestData)
284
gooseerrors.AddErrorContext(&err, "failed to list server (%s) security groups", serverId)
288
return resp.Groups, nil
250
err = c.sendRequest(GET, "compute", url, &requestData,
251
"failed to list server (%s) security groups", serverId)
252
return resp.Groups, err
291
255
func (c *OpenStackClient) CreateSecurityGroup(name, description string) (group SecurityGroup, err error) {
303
267
SecurityGroup SecurityGroup `json:"security_group"`
305
269
requestData := goosehttp.RequestData{ReqValue: req, RespValue: &resp, ExpectedStatus: []int{http.StatusOK}}
306
err = c.authRequest(POST, "compute", OS_API_SECURITY_GROUPS, nil, &requestData)
308
gooseerrors.AddErrorContext(&err, "failed to create a security group with name=%s", name)
310
group = resp.SecurityGroup
270
err = c.sendRequest(POST, "compute", OS_API_SECURITY_GROUPS, &requestData,
271
"failed to create a security group with name=%s", name)
272
return resp.SecurityGroup, err
315
275
func (c *OpenStackClient) DeleteSecurityGroup(groupId int) (err error) {
317
277
url := fmt.Sprintf("%s/%d", OS_API_SECURITY_GROUPS, groupId)
318
278
requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusAccepted}}
319
err = c.authRequest(DELETE, "compute", url, nil, &requestData)
321
gooseerrors.AddErrorContext(&err, "failed to delete a security group with id=%d", groupId)
279
err = c.sendRequest(DELETE, "compute", url, &requestData,
280
"failed to delete a security group with id=%d", groupId)
347
304
requestData := goosehttp.RequestData{ReqValue: req, RespValue: &resp}
348
err = c.authRequest(POST, "compute", OS_API_SECURITY_GROUP_RULES, nil, &requestData)
350
gooseerrors.AddErrorContext(&err, "failed to create a rule for the security group with id=%s", ruleInfo.GroupId)
305
err = c.sendRequest(POST, "compute", OS_API_SECURITY_GROUP_RULES, &requestData,
306
"failed to create a rule for the security group with id=%s", ruleInfo.GroupId)
353
307
return resp.SecurityGroupRule, err
358
312
url := fmt.Sprintf("%s/%d", OS_API_SECURITY_GROUP_RULES, ruleId)
359
313
requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusAccepted}}
360
err = c.authRequest(DELETE, "compute", url, nil, &requestData)
362
gooseerrors.AddErrorContext(&err, "failed to delete a security group rule with id=%d", ruleId)
314
err = c.sendRequest(DELETE, "compute", url, &requestData,
315
"failed to delete a security group rule with id=%d", ruleId)
377
328
url := fmt.Sprintf("%s/%s/action", OS_API_SERVERS, serverId)
378
329
requestData := goosehttp.RequestData{ReqValue: req, ExpectedStatus: []int{http.StatusAccepted}}
379
err = c.authRequest(POST, "compute", url, nil, &requestData)
381
gooseerrors.AddErrorContext(&err, "failed to add security group '%s' from server with id=%s", groupName, serverId)
330
err = c.sendRequest(POST, "compute", url, &requestData,
331
"failed to add security group '%s' from server with id=%s", groupName, serverId)
395
344
url := fmt.Sprintf("%s/%s/action", OS_API_SERVERS, serverId)
396
345
requestData := goosehttp.RequestData{ReqValue: req, ExpectedStatus: []int{http.StatusAccepted}}
397
err = c.authRequest(POST, "compute", url, nil, &requestData)
399
gooseerrors.AddErrorContext(&err, "failed to remove security group '%s' from server with id=%s", groupName, serverId)
346
err = c.sendRequest(POST, "compute", url, &requestData,
347
"failed to remove security group '%s' from server with id=%s", groupName, serverId)
418
365
requestData := goosehttp.RequestData{RespValue: &resp}
419
err = c.authRequest(GET, "compute", OS_API_FLOATING_IPS, nil, &requestData)
421
gooseerrors.AddErrorContext(&err, "failed to list floating ips")
366
err = c.sendRequest(GET, "compute", OS_API_FLOATING_IPS, &requestData,
367
"failed to list floating ips")
424
368
return resp.FloatingIPs, err
433
377
url := fmt.Sprintf("%s/%d", OS_API_FLOATING_IPS, ipId)
434
378
requestData := goosehttp.RequestData{RespValue: &resp}
435
err = c.authRequest(GET, "compute", url, nil, &requestData)
437
gooseerrors.AddErrorContext(&err, "failed to get floating ip %d details", ipId)
379
err = c.sendRequest(GET, "compute", url, &requestData,
380
"failed to get floating ip %d details", ipId)
440
381
return resp.FloatingIP, err
449
390
requestData := goosehttp.RequestData{RespValue: &resp}
450
err = c.authRequest(POST, "compute", OS_API_FLOATING_IPS, nil, &requestData)
452
gooseerrors.AddErrorContext(&err, "failed to allocate a floating ip")
391
err = c.sendRequest(POST, "compute", OS_API_FLOATING_IPS, &requestData,
392
"failed to allocate a floating ip")
455
393
return resp.FloatingIP, err
460
398
url := fmt.Sprintf("%s/%d", OS_API_FLOATING_IPS, ipId)
461
399
requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusAccepted}}
462
err = c.authRequest(DELETE, "compute", url, nil, &requestData)
464
gooseerrors.AddErrorContext(&err, "failed to delete floating ip %d details", ipId)
400
err = c.sendRequest(DELETE, "compute", url, &requestData,
401
"failed to delete floating ip %d details", ipId)
479
414
url := fmt.Sprintf("%s/%s/action", OS_API_SERVERS, serverId)
480
415
requestData := goosehttp.RequestData{ReqValue: req, ExpectedStatus: []int{http.StatusAccepted}}
481
err = c.authRequest(POST, "compute", url, nil, &requestData)
483
gooseerrors.AddErrorContext(&err, "failed to add floating ip %s to server %s", address, serverId)
416
err = c.sendRequest(POST, "compute", url, &requestData,
417
"failed to add floating ip %s to server %s", address, serverId)
498
430
url := fmt.Sprintf("%s/%s/action", OS_API_SERVERS, serverId)
499
431
requestData := goosehttp.RequestData{ReqValue: req, ExpectedStatus: []int{http.StatusAccepted}}
500
err = c.authRequest(POST, "compute", url, nil, &requestData)
502
gooseerrors.AddErrorContext(&err, "failed to remove floating ip %s to server %s", address, serverId)
432
err = c.sendRequest(POST, "compute", url, &requestData,
433
"failed to remove floating ip %s to server %s", address, serverId)
514
443
headers.Add("X-Container-Read", ".r:*")
515
444
url := fmt.Sprintf("/%s", containerName)
516
445
requestData := goosehttp.RequestData{ReqHeaders: headers, ExpectedStatus: []int{http.StatusAccepted, http.StatusCreated}}
517
err = c.authRequest(PUT, "object-store", url, nil, &requestData)
519
gooseerrors.AddErrorContext(&err, "failed to create container %s.", containerName)
446
err = c.sendRequest(PUT, "object-store", url, &requestData,
447
"failed to create container %s.", containerName)
527
453
url := fmt.Sprintf("/%s", containerName)
528
454
requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusNoContent}}
529
err = c.authRequest(DELETE, "object-store", url, nil, &requestData)
531
gooseerrors.AddErrorContext(&err, "failed to delete container %s.", containerName)
455
err = c.sendRequest(DELETE, "object-store", url, &requestData,
456
"failed to delete container %s.", containerName)
537
460
func (c *OpenStackClient) PublicObjectURL(containerName, objectName string) (url string, err error) {
538
461
path := fmt.Sprintf("/%s/%s", containerName, objectName)
539
return c.makeUrl("object-store", []string{path}, nil)
462
return c.makeServiceURL("object-store", []string{path})
542
465
func (c *OpenStackClient) HeadObject(containerName, objectName string) (headers http.Header, err error) {
548
471
requestData := goosehttp.RequestData{ReqHeaders: headers, ExpectedStatus: []int{http.StatusOK}}
549
err = c.authRequest(HEAD, "object-store", url, nil, &requestData)
551
gooseerrors.AddErrorContext(&err, "failed to HEAD object %s from container %s", objectName, containerName)
472
err = c.sendRequest(HEAD, "object-store", url, &requestData,
473
"failed to HEAD object %s from container %s", objectName, containerName)
557
477
func (c *OpenStackClient) GetObject(containerName, objectName string) (obj []byte, err error) {
563
483
requestData := goosehttp.RequestData{RespData: &obj, ExpectedStatus: []int{http.StatusOK}}
564
err = c.authBinaryRequest(GET, "object-store", url, nil, &requestData)
566
gooseerrors.AddErrorContext(&err, "failed to GET object %s content from container %s", objectName, containerName)
484
err = c.sendRequest(GET, "object-store", url, &requestData,
485
"failed to GET object %s content from container %s", objectName, containerName)
572
489
func (c *OpenStackClient) DeleteObject(containerName, objectName string) (err error) {
578
495
requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusAccepted}}
579
err = c.authRequest(DELETE, "object-store", url, nil, &requestData)
581
gooseerrors.AddErrorContext(&err, "failed to DELETE object %s content from container %s", objectName, containerName)
496
err = c.sendRequest(DELETE, "object-store", url, &requestData,
497
"failed to DELETE object %s content from container %s", objectName, containerName)
592
507
requestData := goosehttp.RequestData{ReqData: data, ExpectedStatus: []int{http.StatusAccepted}}
593
err = c.authBinaryRequest(PUT, "object-store", url, nil, &requestData)
595
gooseerrors.AddErrorContext(&err, "failed to PUT object %s content from container %s", objectName, containerName)
508
err = c.sendRequest(PUT, "object-store", url, &requestData,
509
"failed to PUT object %s content from container %s", objectName, containerName)
600
513
////////////////////////////////////////////////////////////////////////
601
514
// Private helpers
603
// makeUrl prepares a full URL to a service endpoint, with optional
604
// URL parts, appended to it and optional query string params. It
605
// uses the first endpoint it can find for the given service type
606
func (c *OpenStackClient) makeUrl(serviceType string, parts []string, params url.Values) (string, error) {
516
// makeServiceURL prepares a full URL to a service endpoint, with optional
517
// URL parts. It uses the first endpoint it can find for the given service type.
518
func (c *OpenStackClient) makeServiceURL(serviceType string, parts []string) (string, error) {
607
519
url, ok := c.ServiceURLs[serviceType]
609
521
return "", errors.New("no endpoints known for service type: " + serviceType)
611
523
for _, part := range parts {
615
url += "?" + params.Encode()
620
func (c *OpenStackClient) setupRequest(svcType, apiCall string, params url.Values, requestData *goosehttp.RequestData) (url string, err error) {
529
func (c *OpenStackClient) sendRequest(method, svcType, apiCall string, requestData *goosehttp.RequestData,
530
context string, contextArgs ...interface{}) (err error) {
621
531
if !c.IsAuthenticated() {
622
return "", errors.New("not authenticated")
532
err = gooseerrors.AddContext(errors.New("not authenticated"), context, contextArgs...)
625
url, err = c.makeUrl(svcType, []string{apiCall}, params)
536
url, err := c.makeServiceURL(svcType, []string{apiCall})
627
gooseerrors.AddErrorContext(&err, "cannot find a '%s' node endpoint", svcType)
538
err = gooseerrors.AddContext(err, "cannot find a '%s' node endpoint", svcType)
631
542
if c.client == nil {
632
c.client = &goosehttp.GooseHTTPClient{http.Client{CheckRedirect: nil}}
635
if requestData.ReqHeaders == nil {
636
requestData.ReqHeaders = make(http.Header)
638
requestData.ReqHeaders.Add("X-Auth-Token", c.Token)
642
func (c *OpenStackClient) authRequest(method, svcType, apiCall string, params url.Values, requestData *goosehttp.RequestData) (err error) {
643
url, err := c.setupRequest(svcType, apiCall, params, requestData)
647
err = c.client.JsonRequest(method, url, requestData)
651
func (c *OpenStackClient) authBinaryRequest(method, svcType, apiCall string, params url.Values, requestData *goosehttp.RequestData) (err error) {
652
url, err := c.setupRequest(svcType, apiCall, params, requestData)
656
err = c.client.BinaryRequest(method, url, requestData)
543
c.client = &goosehttp.Client{http.Client{CheckRedirect: nil}, c.Token}
545
if requestData.ReqValue != nil || requestData.RespValue != nil {
546
err = c.client.JsonRequest(method, url, requestData)
548
err = c.client.BinaryRequest(method, url, requestData)
551
err = gooseerrors.AddContext(err, context, contextArgs...)