1
// Nova double testing service - HTTP API tests
15
gc "gopkg.in/check.v1"
17
"gopkg.in/goose.v1/nova"
18
"gopkg.in/goose.v1/testing/httpsuite"
19
"gopkg.in/goose.v1/testservices/hook"
20
"gopkg.in/goose.v1/testservices/identityservice"
23
type NovaHTTPSuite struct {
29
var _ = gc.Suite(&NovaHTTPSuite{})
31
type NovaHTTPSSuite struct {
37
var _ = gc.Suite(&NovaHTTPSSuite{HTTPSuite: httpsuite.HTTPSuite{UseTLS: true}})
39
func (s *NovaHTTPSuite) SetUpSuite(c *gc.C) {
40
s.HTTPSuite.SetUpSuite(c)
41
identityDouble := identityservice.NewUserPass()
42
userInfo := identityDouble.AddUser("fred", "secret", "tenant")
43
s.token = userInfo.Token
44
s.service = New(s.Server.URL, versionPath, userInfo.TenantId, region, identityDouble, nil)
47
func (s *NovaHTTPSuite) TearDownSuite(c *gc.C) {
48
s.HTTPSuite.TearDownSuite(c)
51
func (s *NovaHTTPSuite) SetUpTest(c *gc.C) {
52
s.HTTPSuite.SetUpTest(c)
53
s.service.SetupHTTP(s.Mux)
54
// this is otherwise handled not directly by nova test service
55
// but by openstack that tries for / before.
56
s.Mux.Handle("/", s.service.handler((*Nova).handleRoot))
59
func (s *NovaHTTPSuite) TearDownTest(c *gc.C) {
60
s.HTTPSuite.TearDownTest(c)
63
// assertJSON asserts the passed http.Response's body can be
64
// unmarshalled into the given expected object, populating it with the
65
// successfully parsed data.
66
func assertJSON(c *gc.C, resp *http.Response, expected interface{}) {
67
body, err := ioutil.ReadAll(resp.Body)
68
defer resp.Body.Close()
69
c.Assert(err, gc.IsNil)
70
err = json.Unmarshal(body, &expected)
71
c.Assert(err, gc.IsNil)
74
// assertBody asserts the passed http.Response's body matches the
75
// expected response, replacing any variables in the expected body.
76
func assertBody(c *gc.C, resp *http.Response, expected *errorResponse) {
77
body, err := ioutil.ReadAll(resp.Body)
78
defer resp.Body.Close()
79
c.Assert(err, gc.IsNil)
80
expBody := expected.requestBody(resp.Request)
81
// cast to string for easier asserts debugging
82
c.Assert(string(body), gc.Equals, string(expBody))
85
// sendRequest constructs an HTTP request from the parameters and
86
// sends it, returning the response or an error.
87
func (s *NovaHTTPSuite) sendRequest(method, url string, body []byte, headers http.Header) (*http.Response, error) {
88
if !strings.HasPrefix(url, "http") {
89
url = "http://" + s.service.Hostname + strings.TrimLeft(url, "/")
91
req, err := http.NewRequest(method, url, bytes.NewReader(body))
95
for header, values := range headers {
96
for _, value := range values {
97
req.Header.Add(header, value)
100
// workaround for https://code.google.com/p/go/issues/detail?id=4454
101
req.Header.Set("Content-Length", strconv.Itoa(len(body)))
102
return http.DefaultClient.Do(req)
105
// authRequest is a shortcut for sending requests with pre-set token
106
// header and correct version prefix and tenant ID in the URL.
107
func (s *NovaHTTPSuite) authRequest(method, path string, body []byte, headers http.Header) (*http.Response, error) {
109
headers = make(http.Header)
111
headers.Set(authToken, s.token)
112
url := s.service.endpointURL(true, path)
113
return s.sendRequest(method, url, body, headers)
116
// jsonRequest serializes the passed body object to JSON and sends a
117
// the request with authRequest().
118
func (s *NovaHTTPSuite) jsonRequest(method, path string, body interface{}, headers http.Header) (*http.Response, error) {
119
jsonBody, err := json.Marshal(body)
123
return s.authRequest(method, path, jsonBody, headers)
126
// setHeader creates http.Header map, sets the given header, and
128
func setHeader(header, value string) http.Header {
129
h := make(http.Header)
134
// SimpleTest defines a simple request without a body and expected response.
135
type SimpleTest struct {
140
expect *errorResponse
143
func (s *NovaHTTPSuite) simpleTests() []SimpleTest {
144
var simpleTests = []SimpleTest{
149
headers: make(http.Header),
150
expect: errUnauthorized,
156
headers: setHeader(authToken, "phony"),
157
expect: errUnauthorized,
163
headers: setHeader(authToken, s.token),
164
expect: errMultipleChoices,
169
url: "/any/unknown/one",
170
headers: setHeader(authToken, s.token),
171
expect: errMultipleChoices,
175
url: "/any/unknown/one",
181
url: versionPath + "/phony_token",
182
headers: setHeader(authToken, s.token),
183
expect: errBadRequest,
192
url: "/flavors/invalid",
198
expect: errBadRequest2,
202
url: "/flavors/invalid",
212
url: "/flavors/invalid",
213
expect: errNotFoundJSON,
222
url: "/flavors/invalid",
223
expect: errForbidden,
227
url: "/flavors/detail/invalid",
232
url: "/flavors/detail",
237
url: "/flavors/detail/invalid",
242
url: "/flavors/detail",
243
expect: errNotFoundJSON,
247
url: "/flavors/detail/invalid",
252
url: "/flavors/detail",
253
expect: errForbidden,
257
url: "/flavors/detail/invalid",
262
url: "/servers/invalid",
263
expect: &errorResponse{code: 404, body: "{\"itemNotFound\":{\"message\":\"No such server \\\"invalid\\\"\", \"code\":404}}"},
268
expect: errBadRequest2,
272
url: "/servers/invalid",
282
url: "/servers/invalid",
283
expect: errBadRequest2,
292
url: "/servers/invalid",
293
expect: errNotFoundJSON,
297
url: "/servers/detail/invalid",
302
url: "/servers/detail",
307
url: "/servers/detail/invalid",
312
url: "/servers/detail",
313
expect: errBadRequest2,
317
url: "/servers/detail/invalid",
322
url: "/servers/detail",
323
expect: errNotFoundJSON,
327
url: "/servers/detail/invalid",
332
url: "/os-security-groups/42",
333
expect: errNotFoundJSONSG,
337
url: "/os-security-groups",
338
expect: errBadRequest2,
342
url: "/os-security-groups/invalid",
347
url: "/os-security-groups",
352
url: "/os-security-groups/invalid",
353
expect: errNotFoundJSONSG,
357
url: "/os-security-groups",
362
url: "/os-security-groups/42",
363
expect: errNotFoundJSONSG,
367
url: "/os-security-group-rules",
368
expect: errNotFoundJSON,
372
url: "/os-security-group-rules/invalid",
373
expect: errNotFoundJSON,
377
url: "/os-security-group-rules/42",
378
expect: errNotFoundJSON,
382
url: "/os-security-group-rules",
383
expect: errBadRequest2,
387
url: "/os-security-group-rules/invalid",
392
url: "/os-security-group-rules",
397
url: "/os-security-group-rules/invalid",
398
expect: errNotFoundJSON,
402
url: "/os-security-group-rules",
407
url: "/os-security-group-rules/42",
408
expect: errNotFoundJSONSGR,
412
url: "/os-floating-ips/42",
413
expect: errNotFoundJSON,
417
url: "/os-floating-ips/invalid",
422
url: "/os-floating-ips",
427
url: "/os-floating-ips/invalid",
428
expect: errNotFoundJSON,
432
url: "/os-floating-ips",
437
url: "/os-floating-ips/invalid",
438
expect: errNotFoundJSON,
444
func (s *NovaHTTPSuite) TestSimpleRequestTests(c *gc.C) {
445
simpleTests := s.simpleTests()
446
for i, t := range simpleTests {
447
c.Logf("#%d. %s %s -> %d", i, t.method, t.url, t.expect.code)
448
if t.headers == nil {
449
t.headers = make(http.Header)
450
t.headers.Set(authToken, s.token)
457
resp, err = s.sendRequest(t.method, t.url, nil, t.headers)
459
resp, err = s.authRequest(t.method, t.url, nil, t.headers)
461
c.Assert(err, gc.IsNil)
462
c.Assert(resp.StatusCode, gc.Equals, t.expect.code)
463
assertBody(c, resp, t.expect)
465
fmt.Printf("total: %d\n", len(simpleTests))
468
func (s *NovaHTTPSuite) TestGetFlavors(c *gc.C) {
469
// The test service has 3 default flavours.
470
var expected struct {
471
Flavors []nova.Entity
473
resp, err := s.authRequest("GET", "/flavors", nil, nil)
474
c.Assert(err, gc.IsNil)
475
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
476
assertJSON(c, resp, &expected)
477
c.Assert(expected.Flavors, gc.HasLen, 3)
478
entities := s.service.allFlavorsAsEntities()
479
c.Assert(entities, gc.HasLen, 3)
480
sort.Sort(nova.EntitySortBy{Attr: "Id", Entities: expected.Flavors})
481
sort.Sort(nova.EntitySortBy{Attr: "Id", Entities: entities})
482
c.Assert(expected.Flavors, gc.DeepEquals, entities)
483
var expectedFlavor struct {
484
Flavor nova.FlavorDetail
486
resp, err = s.authRequest("GET", "/flavors/1", nil, nil)
487
c.Assert(err, gc.IsNil)
488
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
489
assertJSON(c, resp, &expectedFlavor)
490
c.Assert(expectedFlavor.Flavor.Name, gc.Equals, "m1.tiny")
493
func (s *NovaHTTPSuite) TestGetFlavorsDetail(c *gc.C) {
494
// The test service has 3 default flavours.
495
flavors := s.service.allFlavors()
496
c.Assert(flavors, gc.HasLen, 3)
497
var expected struct {
498
Flavors []nova.FlavorDetail
500
resp, err := s.authRequest("GET", "/flavors/detail", nil, nil)
501
c.Assert(err, gc.IsNil)
502
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
503
assertJSON(c, resp, &expected)
504
c.Assert(expected.Flavors, gc.HasLen, 3)
505
sort.Sort(nova.FlavorDetailSortBy{Attr: "Id", FlavorDetails: expected.Flavors})
506
sort.Sort(nova.FlavorDetailSortBy{Attr: "Id", FlavorDetails: flavors})
507
c.Assert(expected.Flavors, gc.DeepEquals, flavors)
508
resp, err = s.authRequest("GET", "/flavors/detail/1", nil, nil)
509
c.Assert(err, gc.IsNil)
510
assertBody(c, resp, errNotFound)
513
func (s *NovaHTTPSuite) TestGetServers(c *gc.C) {
514
entities, err := s.service.allServersAsEntities(nil)
515
c.Assert(err, gc.IsNil)
516
c.Assert(entities, gc.HasLen, 0)
517
var expected struct {
518
Servers []nova.Entity
520
resp, err := s.authRequest("GET", "/servers", nil, nil)
521
c.Assert(err, gc.IsNil)
522
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
523
assertJSON(c, resp, &expected)
524
c.Assert(expected.Servers, gc.HasLen, 0)
525
servers := []nova.ServerDetail{
526
{Id: "sr1", Name: "server 1"},
527
{Id: "sr2", Name: "server 2"},
529
for i, server := range servers {
530
s.service.buildServerLinks(&server)
532
err := s.service.addServer(server)
533
c.Assert(err, gc.IsNil)
534
defer s.service.removeServer(server.Id)
536
entities, err = s.service.allServersAsEntities(nil)
537
c.Assert(err, gc.IsNil)
538
resp, err = s.authRequest("GET", "/servers", nil, nil)
539
c.Assert(err, gc.IsNil)
540
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
541
assertJSON(c, resp, &expected)
542
c.Assert(expected.Servers, gc.HasLen, 2)
543
if expected.Servers[0].Id != entities[0].Id {
544
expected.Servers[0], expected.Servers[1] = expected.Servers[1], expected.Servers[0]
546
c.Assert(expected.Servers, gc.DeepEquals, entities)
547
var expectedServer struct {
548
Server nova.ServerDetail
550
resp, err = s.authRequest("GET", "/servers/sr1", nil, nil)
551
c.Assert(err, gc.IsNil)
552
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
553
assertJSON(c, resp, &expectedServer)
554
c.Assert(expectedServer.Server, gc.DeepEquals, servers[0])
557
func (s *NovaHTTPSuite) TestGetServersWithFilters(c *gc.C) {
558
entities, err := s.service.allServersAsEntities(nil)
559
c.Assert(err, gc.IsNil)
560
c.Assert(entities, gc.HasLen, 0)
561
var expected struct {
562
Servers []nova.Entity
564
url := "/servers?status=RESCUE&status=BUILD&name=srv2&name=srv1"
565
resp, err := s.authRequest("GET", url, nil, nil)
566
c.Assert(err, gc.IsNil)
567
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
568
assertJSON(c, resp, &expected)
569
c.Assert(expected.Servers, gc.HasLen, 0)
570
servers := []nova.ServerDetail{
571
{Id: "sr1", Name: "srv1", Status: nova.StatusBuild},
572
{Id: "sr2", Name: "srv2", Status: nova.StatusRescue},
573
{Id: "sr3", Name: "srv3", Status: nova.StatusActive},
575
for i, server := range servers {
576
s.service.buildServerLinks(&server)
578
err := s.service.addServer(server)
579
c.Assert(err, gc.IsNil)
580
defer s.service.removeServer(server.Id)
582
resp, err = s.authRequest("GET", url, nil, nil)
583
c.Assert(err, gc.IsNil)
584
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
585
assertJSON(c, resp, &expected)
586
c.Assert(expected.Servers, gc.HasLen, 1)
587
c.Assert(expected.Servers[0].Id, gc.Equals, servers[0].Id)
588
c.Assert(expected.Servers[0].Name, gc.Equals, servers[0].Name)
591
func (s *NovaHTTPSuite) TestGetServersWithBadFilter(c *gc.C) {
592
url := "/servers?name=(server"
593
resp, err := s.authRequest("GET", url, nil, nil)
594
c.Assert(err, gc.IsNil)
595
c.Assert(resp.StatusCode, gc.Equals, http.StatusInternalServerError)
596
type novaError struct {
600
var expected struct {
601
novaError `json:"computeFault"`
603
assertJSON(c, resp, &expected)
604
c.Check(expected.Code, gc.Equals, 500)
605
c.Check(expected.Message, gc.Matches, `error parsing.*\(server.*`)
608
func (s *NovaHTTPSuite) TestGetServersPatchMatch(c *gc.C) {
609
cleanup := s.service.RegisterControlPoint(
611
func(sc hook.ServiceControl, args ...interface{}) error {
612
return fmt.Errorf("Unexpected error")
616
resp, err := s.authRequest("GET", "/servers", nil, nil)
617
c.Assert(err, gc.IsNil)
618
c.Assert(resp.StatusCode, gc.Equals, http.StatusInternalServerError)
619
type novaError struct {
623
var expected struct {
624
novaError `json:"computeFault"`
626
assertJSON(c, resp, &expected)
627
c.Check(expected.Code, gc.Equals, 500)
628
c.Check(expected.Message, gc.Equals, "Unexpected error")
631
func (s *NovaHTTPSuite) TestNewUUID(c *gc.C) {
632
uuid, err := newUUID()
633
c.Assert(err, gc.IsNil)
634
var p1, p2, p3, p4, p5 string
635
num, err := fmt.Sscanf(uuid, "%8x-%4x-%4x-%4x-%12x", &p1, &p2, &p3, &p4, &p5)
636
c.Assert(err, gc.IsNil)
637
c.Assert(num, gc.Equals, 5)
638
uuid2, err := newUUID()
639
c.Assert(err, gc.IsNil)
640
c.Assert(uuid2, gc.Not(gc.Equals), uuid)
643
func (s *NovaHTTPSuite) assertAddresses(c *gc.C, serverId string) {
644
server, err := s.service.server(serverId)
645
c.Assert(err, gc.IsNil)
646
c.Assert(server.Addresses, gc.HasLen, 2)
647
c.Assert(server.Addresses["public"], gc.HasLen, 2)
648
c.Assert(server.Addresses["private"], gc.HasLen, 2)
649
for network, addresses := range server.Addresses {
650
for _, addr := range addresses {
651
if addr.Version == 4 && network == "public" {
652
c.Assert(addr.Address, gc.Matches, `127\.10\.0\.\d{1,3}`)
653
} else if addr.Version == 4 && network == "private" {
654
c.Assert(addr.Address, gc.Matches, `127\.0\.0\.\d{1,3}`)
661
func (s *NovaHTTPSuite) TestRunServer(c *gc.C) {
662
entities, err := s.service.allServersAsEntities(nil)
663
c.Assert(err, gc.IsNil)
664
c.Assert(entities, gc.HasLen, 0)
667
FlavorRef string `json:"flavorRef"`
668
ImageRef string `json:"imageRef"`
669
Name string `json:"name"`
670
SecurityGroups []map[string]string `json:"security_groups"`
673
resp, err := s.jsonRequest("POST", "/servers", req, nil)
674
c.Assert(err, gc.IsNil)
675
c.Assert(resp.StatusCode, gc.Equals, http.StatusBadRequest)
676
assertBody(c, resp, errBadRequestSrvName)
677
req.Server.Name = "srv1"
678
resp, err = s.jsonRequest("POST", "/servers", req, nil)
679
c.Assert(err, gc.IsNil)
680
c.Assert(resp.StatusCode, gc.Equals, http.StatusBadRequest)
681
assertBody(c, resp, errBadRequestSrvImage)
682
req.Server.ImageRef = "image"
683
resp, err = s.jsonRequest("POST", "/servers", req, nil)
684
c.Assert(err, gc.IsNil)
685
c.Assert(resp.StatusCode, gc.Equals, http.StatusBadRequest)
686
assertBody(c, resp, errBadRequestSrvFlavor)
687
req.Server.FlavorRef = "flavor"
688
var expected struct {
690
SecurityGroups []map[string]string `json:"security_groups"`
696
resp, err = s.jsonRequest("POST", "/servers", req, nil)
697
c.Assert(err, gc.IsNil)
698
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
699
assertJSON(c, resp, &expected)
700
c.Assert(expected.Server.SecurityGroups, gc.HasLen, 1)
701
c.Assert(expected.Server.SecurityGroups[0]["name"], gc.Equals, "default")
702
c.Assert(expected.Server.Id, gc.Not(gc.Equals), "")
703
c.Assert(expected.Server.Links, gc.HasLen, 2)
704
c.Assert(expected.Server.AdminPass, gc.Not(gc.Equals), "")
705
s.assertAddresses(c, expected.Server.Id)
706
srv, err := s.service.server(expected.Server.Id)
707
c.Assert(err, gc.IsNil)
708
c.Assert(srv.Links, gc.DeepEquals, expected.Server.Links)
709
s.service.removeServer(srv.Id)
710
req.Server.Name = "test2"
711
req.Server.SecurityGroups = []map[string]string{
716
err = s.service.addSecurityGroup(nova.SecurityGroup{Id: "1", Name: "group1"})
717
c.Assert(err, gc.IsNil)
718
defer s.service.removeSecurityGroup("1")
719
err = s.service.addSecurityGroup(nova.SecurityGroup{Id: "2", Name: "group2"})
720
c.Assert(err, gc.IsNil)
721
defer s.service.removeSecurityGroup("2")
722
resp, err = s.jsonRequest("POST", "/servers", req, nil)
723
c.Assert(err, gc.IsNil)
724
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
725
assertJSON(c, resp, &expected)
726
c.Assert(expected.Server.SecurityGroups, gc.DeepEquals, req.Server.SecurityGroups)
727
srv, err = s.service.server(expected.Server.Id)
728
c.Assert(err, gc.IsNil)
729
ok := s.service.hasServerSecurityGroup(srv.Id, "1")
730
c.Assert(ok, gc.Equals, true)
731
ok = s.service.hasServerSecurityGroup(srv.Id, "2")
732
c.Assert(ok, gc.Equals, true)
733
ok = s.service.hasServerSecurityGroup(srv.Id, "999")
734
c.Assert(ok, gc.Equals, true)
735
s.service.removeServerSecurityGroup(srv.Id, "1")
736
s.service.removeServerSecurityGroup(srv.Id, "2")
737
s.service.removeServerSecurityGroup(srv.Id, "999")
738
s.service.removeServer(srv.Id)
741
func (s *NovaHTTPSuite) TestDeleteServer(c *gc.C) {
742
server := nova.ServerDetail{Id: "sr1"}
743
_, err := s.service.server(server.Id)
744
c.Assert(err, gc.NotNil)
745
err = s.service.addServer(server)
746
c.Assert(err, gc.IsNil)
747
defer s.service.removeServer(server.Id)
748
resp, err := s.authRequest("DELETE", "/servers/sr1", nil, nil)
749
c.Assert(err, gc.IsNil)
750
c.Assert(resp.StatusCode, gc.Equals, http.StatusNoContent)
751
_, err = s.service.server(server.Id)
752
c.Assert(err, gc.NotNil)
755
func (s *NovaHTTPSuite) TestGetServersDetail(c *gc.C) {
756
servers, err := s.service.allServers(nil)
757
c.Assert(err, gc.IsNil)
758
c.Assert(servers, gc.HasLen, 0)
759
var expected struct {
760
Servers []nova.ServerDetail `json:"servers"`
762
resp, err := s.authRequest("GET", "/servers/detail", nil, nil)
763
c.Assert(err, gc.IsNil)
764
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
765
assertJSON(c, resp, &expected)
766
c.Assert(expected.Servers, gc.HasLen, 0)
767
servers = []nova.ServerDetail{
768
{Id: "sr1", Name: "server 1"},
769
{Id: "sr2", Name: "server 2"},
771
for i, server := range servers {
772
s.service.buildServerLinks(&server)
774
err := s.service.addServer(server)
775
c.Assert(err, gc.IsNil)
776
defer s.service.removeServer(server.Id)
778
resp, err = s.authRequest("GET", "/servers/detail", nil, nil)
779
c.Assert(err, gc.IsNil)
780
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
781
assertJSON(c, resp, &expected)
782
c.Assert(expected.Servers, gc.HasLen, 2)
783
if expected.Servers[0].Id != servers[0].Id {
784
expected.Servers[0], expected.Servers[1] = expected.Servers[1], expected.Servers[0]
786
c.Assert(expected.Servers, gc.DeepEquals, servers)
787
resp, err = s.authRequest("GET", "/servers/detail/sr1", nil, nil)
788
c.Assert(err, gc.IsNil)
789
assertBody(c, resp, errNotFound)
792
func (s *NovaHTTPSuite) TestGetServersDetailWithFilters(c *gc.C) {
793
servers, err := s.service.allServers(nil)
794
c.Assert(err, gc.IsNil)
795
c.Assert(servers, gc.HasLen, 0)
796
var expected struct {
797
Servers []nova.ServerDetail `json:"servers"`
799
url := "/servers/detail?status=RESCUE&status=BUILD&name=srv2&name=srv1"
800
resp, err := s.authRequest("GET", url, nil, nil)
801
c.Assert(err, gc.IsNil)
802
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
803
assertJSON(c, resp, &expected)
804
c.Assert(expected.Servers, gc.HasLen, 0)
805
servers = []nova.ServerDetail{
806
{Id: "sr1", Name: "srv1", Status: nova.StatusBuild},
807
{Id: "sr2", Name: "srv2", Status: nova.StatusRescue},
808
{Id: "sr3", Name: "srv3", Status: nova.StatusActive},
810
for i, server := range servers {
811
s.service.buildServerLinks(&server)
813
err := s.service.addServer(server)
814
c.Assert(err, gc.IsNil)
815
defer s.service.removeServer(server.Id)
817
resp, err = s.authRequest("GET", url, nil, nil)
818
c.Assert(err, gc.IsNil)
819
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
820
assertJSON(c, resp, &expected)
821
c.Assert(expected.Servers, gc.HasLen, 1)
822
c.Assert(expected.Servers[0], gc.DeepEquals, servers[0])
825
func (s *NovaHTTPSuite) TestGetSecurityGroups(c *gc.C) {
826
// There is always a default security group.
827
groups := s.service.allSecurityGroups()
828
c.Assert(groups, gc.HasLen, 1)
829
var expected struct {
830
Groups []nova.SecurityGroup `json:"security_groups"`
832
resp, err := s.authRequest("GET", "/os-security-groups", nil, nil)
833
c.Assert(err, gc.IsNil)
834
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
835
assertJSON(c, resp, &expected)
836
c.Assert(expected.Groups, gc.HasLen, 1)
837
groups = []nova.SecurityGroup{
841
TenantId: s.service.TenantId,
842
Rules: []nova.SecurityGroupRule{},
847
TenantId: s.service.TenantId,
848
Rules: []nova.SecurityGroupRule{},
851
for _, group := range groups {
852
err := s.service.addSecurityGroup(group)
853
c.Assert(err, gc.IsNil)
854
defer s.service.removeSecurityGroup(group.Id)
856
resp, err = s.authRequest("GET", "/os-security-groups", nil, nil)
857
c.Assert(err, gc.IsNil)
858
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
859
assertJSON(c, resp, &expected)
860
c.Assert(expected.Groups, gc.HasLen, len(groups)+1)
861
checkGroupsInList(c, groups, expected.Groups)
862
var expectedGroup struct {
863
Group nova.SecurityGroup `json:"security_group"`
865
resp, err = s.authRequest("GET", "/os-security-groups/1", nil, nil)
866
c.Assert(err, gc.IsNil)
867
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
868
assertJSON(c, resp, &expectedGroup)
869
c.Assert(expectedGroup.Group, gc.DeepEquals, groups[0])
872
func (s *NovaHTTPSuite) TestAddSecurityGroup(c *gc.C) {
873
group := nova.SecurityGroup{
877
TenantId: s.service.TenantId,
878
Rules: []nova.SecurityGroupRule{},
880
_, err := s.service.securityGroup(group.Id)
881
c.Assert(err, gc.NotNil)
884
Name string `json:"name"`
885
Description string `json:"description"`
886
} `json:"security_group"`
888
req.Group.Name = group.Name
889
req.Group.Description = group.Description
890
var expected struct {
891
Group nova.SecurityGroup `json:"security_group"`
893
resp, err := s.jsonRequest("POST", "/os-security-groups", req, nil)
894
c.Assert(err, gc.IsNil)
895
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
896
assertJSON(c, resp, &expected)
897
c.Assert(expected.Group, gc.DeepEquals, group)
898
err = s.service.removeSecurityGroup(group.Id)
899
c.Assert(err, gc.IsNil)
902
func (s *NovaHTTPSuite) TestDeleteSecurityGroup(c *gc.C) {
903
group := nova.SecurityGroup{Id: "1", Name: "group 1"}
904
_, err := s.service.securityGroup(group.Id)
905
c.Assert(err, gc.NotNil)
906
err = s.service.addSecurityGroup(group)
907
c.Assert(err, gc.IsNil)
908
defer s.service.removeSecurityGroup(group.Id)
909
resp, err := s.authRequest("DELETE", "/os-security-groups/1", nil, nil)
910
c.Assert(err, gc.IsNil)
911
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
912
_, err = s.service.securityGroup(group.Id)
913
c.Assert(err, gc.NotNil)
916
func (s *NovaHTTPSuite) TestAddSecurityGroupRule(c *gc.C) {
917
group1 := nova.SecurityGroup{Id: "1", Name: "src"}
918
group2 := nova.SecurityGroup{Id: "2", Name: "tgt"}
919
err := s.service.addSecurityGroup(group1)
920
c.Assert(err, gc.IsNil)
921
defer s.service.removeSecurityGroup(group1.Id)
922
err = s.service.addSecurityGroup(group2)
923
c.Assert(err, gc.IsNil)
924
defer s.service.removeSecurityGroup(group2.Id)
925
riIngress := nova.RuleInfo{
932
riGroup := nova.RuleInfo{
933
ParentGroupId: group2.Id,
936
iprange := make(map[string]string)
937
iprange["cidr"] = riIngress.Cidr
938
rule1 := nova.SecurityGroupRule{
940
ParentGroupId: group1.Id,
941
FromPort: &riIngress.FromPort,
942
ToPort: &riIngress.ToPort,
943
IPProtocol: &riIngress.IPProtocol,
946
rule2 := nova.SecurityGroupRule{
948
ParentGroupId: group2.Id,
949
Group: nova.SecurityGroupRef{
951
TenantId: s.service.TenantId,
954
ok := s.service.hasSecurityGroupRule(group1.Id, rule1.Id)
955
c.Assert(ok, gc.Equals, false)
956
ok = s.service.hasSecurityGroupRule(group2.Id, rule2.Id)
957
c.Assert(ok, gc.Equals, false)
959
Rule nova.RuleInfo `json:"security_group_rule"`
962
var expected struct {
963
Rule nova.SecurityGroupRule `json:"security_group_rule"`
965
resp, err := s.jsonRequest("POST", "/os-security-group-rules", req, nil)
966
c.Assert(err, gc.IsNil)
967
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
968
assertJSON(c, resp, &expected)
969
c.Assert(expected.Rule.Id, gc.Equals, rule1.Id)
970
c.Assert(expected.Rule.ParentGroupId, gc.Equals, rule1.ParentGroupId)
971
c.Assert(expected.Rule.Group, gc.Equals, nova.SecurityGroupRef{})
972
c.Assert(*expected.Rule.FromPort, gc.Equals, *rule1.FromPort)
973
c.Assert(*expected.Rule.ToPort, gc.Equals, *rule1.ToPort)
974
c.Assert(*expected.Rule.IPProtocol, gc.Equals, *rule1.IPProtocol)
975
c.Assert(expected.Rule.IPRange, gc.DeepEquals, rule1.IPRange)
976
defer s.service.removeSecurityGroupRule(rule1.Id)
978
resp, err = s.jsonRequest("POST", "/os-security-group-rules", req, nil)
979
c.Assert(err, gc.IsNil)
980
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
981
assertJSON(c, resp, &expected)
982
c.Assert(expected.Rule.Id, gc.Equals, rule2.Id)
983
c.Assert(expected.Rule.ParentGroupId, gc.Equals, rule2.ParentGroupId)
984
c.Assert(expected.Rule.Group, gc.DeepEquals, rule2.Group)
985
err = s.service.removeSecurityGroupRule(rule2.Id)
986
c.Assert(err, gc.IsNil)
989
func (s *NovaHTTPSuite) TestDeleteSecurityGroupRule(c *gc.C) {
990
group1 := nova.SecurityGroup{Id: "1", Name: "src"}
991
group2 := nova.SecurityGroup{Id: "2", Name: "tgt"}
992
err := s.service.addSecurityGroup(group1)
993
c.Assert(err, gc.IsNil)
994
defer s.service.removeSecurityGroup(group1.Id)
995
err = s.service.addSecurityGroup(group2)
996
c.Assert(err, gc.IsNil)
997
defer s.service.removeSecurityGroup(group2.Id)
998
riGroup := nova.RuleInfo{
999
ParentGroupId: group2.Id,
1000
GroupId: &group1.Id,
1002
rule := nova.SecurityGroupRule{
1004
ParentGroupId: group2.Id,
1005
Group: nova.SecurityGroupRef{
1007
TenantId: group1.TenantId,
1010
err = s.service.addSecurityGroupRule(rule.Id, riGroup)
1011
c.Assert(err, gc.IsNil)
1012
resp, err := s.authRequest("DELETE", "/os-security-group-rules/1", nil, nil)
1013
c.Assert(err, gc.IsNil)
1014
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
1015
ok := s.service.hasSecurityGroupRule(group2.Id, rule.Id)
1016
c.Assert(ok, gc.Equals, false)
1019
func (s *NovaHTTPSuite) TestAddServerSecurityGroup(c *gc.C) {
1020
group := nova.SecurityGroup{Id: "1", Name: "group"}
1021
err := s.service.addSecurityGroup(group)
1022
c.Assert(err, gc.IsNil)
1023
defer s.service.removeSecurityGroup(group.Id)
1024
server := nova.ServerDetail{Id: "sr1"}
1025
err = s.service.addServer(server)
1026
c.Assert(err, gc.IsNil)
1027
defer s.service.removeServer(server.Id)
1028
ok := s.service.hasServerSecurityGroup(server.Id, group.Id)
1029
c.Assert(ok, gc.Equals, false)
1032
Name string `json:"name"`
1033
} `json:"addSecurityGroup"`
1035
req.Group.Name = group.Name
1036
resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
1037
c.Assert(err, gc.IsNil)
1038
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
1039
ok = s.service.hasServerSecurityGroup(server.Id, group.Id)
1040
c.Assert(ok, gc.Equals, true)
1041
err = s.service.removeServerSecurityGroup(server.Id, group.Id)
1042
c.Assert(err, gc.IsNil)
1045
func (s *NovaHTTPSuite) TestGetServerSecurityGroups(c *gc.C) {
1046
server := nova.ServerDetail{Id: "sr1"}
1047
groups := []nova.SecurityGroup{
1051
TenantId: s.service.TenantId,
1052
Rules: []nova.SecurityGroupRule{},
1057
TenantId: s.service.TenantId,
1058
Rules: []nova.SecurityGroupRule{},
1061
srvGroups := s.service.allServerSecurityGroups(server.Id)
1062
c.Assert(srvGroups, gc.HasLen, 0)
1063
err := s.service.addServer(server)
1064
c.Assert(err, gc.IsNil)
1065
defer s.service.removeServer(server.Id)
1066
for _, group := range groups {
1067
err = s.service.addSecurityGroup(group)
1068
c.Assert(err, gc.IsNil)
1069
defer s.service.removeSecurityGroup(group.Id)
1070
err = s.service.addServerSecurityGroup(server.Id, group.Id)
1071
c.Assert(err, gc.IsNil)
1072
defer s.service.removeServerSecurityGroup(server.Id, group.Id)
1074
srvGroups = s.service.allServerSecurityGroups(server.Id)
1075
var expected struct {
1076
Groups []nova.SecurityGroup `json:"security_groups"`
1078
resp, err := s.authRequest("GET", "/servers/"+server.Id+"/os-security-groups", nil, nil)
1079
c.Assert(err, gc.IsNil)
1080
assertJSON(c, resp, &expected)
1081
c.Assert(expected.Groups, gc.DeepEquals, groups)
1084
func (s *NovaHTTPSuite) TestDeleteServerSecurityGroup(c *gc.C) {
1085
group := nova.SecurityGroup{Id: "1", Name: "group"}
1086
err := s.service.addSecurityGroup(group)
1087
c.Assert(err, gc.IsNil)
1088
defer s.service.removeSecurityGroup(group.Id)
1089
server := nova.ServerDetail{Id: "sr1"}
1090
err = s.service.addServer(server)
1091
c.Assert(err, gc.IsNil)
1092
defer s.service.removeServer(server.Id)
1093
ok := s.service.hasServerSecurityGroup(server.Id, group.Id)
1094
c.Assert(ok, gc.Equals, false)
1095
err = s.service.addServerSecurityGroup(server.Id, group.Id)
1096
c.Assert(err, gc.IsNil)
1099
Name string `json:"name"`
1100
} `json:"removeSecurityGroup"`
1102
req.Group.Name = group.Name
1103
resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
1104
c.Assert(err, gc.IsNil)
1105
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
1106
ok = s.service.hasServerSecurityGroup(server.Id, group.Id)
1107
c.Assert(ok, gc.Equals, false)
1110
func (s *NovaHTTPSuite) TestPostFloatingIP(c *gc.C) {
1111
fip := nova.FloatingIP{Id: "1", IP: "10.0.0.1", Pool: "nova"}
1112
c.Assert(s.service.allFloatingIPs(), gc.HasLen, 0)
1113
var expected struct {
1114
IP nova.FloatingIP `json:"floating_ip"`
1116
resp, err := s.authRequest("POST", "/os-floating-ips", nil, nil)
1117
c.Assert(err, gc.IsNil)
1118
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
1119
assertJSON(c, resp, &expected)
1120
c.Assert(expected.IP, gc.DeepEquals, fip)
1121
err = s.service.removeFloatingIP(fip.Id)
1122
c.Assert(err, gc.IsNil)
1125
func (s *NovaHTTPSuite) TestGetFloatingIPs(c *gc.C) {
1126
c.Assert(s.service.allFloatingIPs(), gc.HasLen, 0)
1127
var expected struct {
1128
IPs []nova.FloatingIP `json:"floating_ips"`
1130
resp, err := s.authRequest("GET", "/os-floating-ips", nil, nil)
1131
c.Assert(err, gc.IsNil)
1132
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
1133
assertJSON(c, resp, &expected)
1134
c.Assert(expected.IPs, gc.HasLen, 0)
1135
fips := []nova.FloatingIP{
1136
{Id: "1", IP: "1.2.3.4", Pool: "nova"},
1137
{Id: "2", IP: "4.3.2.1", Pool: "nova"},
1139
for _, fip := range fips {
1140
err := s.service.addFloatingIP(fip)
1141
defer s.service.removeFloatingIP(fip.Id)
1142
c.Assert(err, gc.IsNil)
1144
resp, err = s.authRequest("GET", "/os-floating-ips", nil, nil)
1145
c.Assert(err, gc.IsNil)
1146
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
1147
assertJSON(c, resp, &expected)
1148
if expected.IPs[0].Id != fips[0].Id {
1149
expected.IPs[0], expected.IPs[1] = expected.IPs[1], expected.IPs[0]
1151
c.Assert(expected.IPs, gc.DeepEquals, fips)
1152
var expectedIP struct {
1153
IP nova.FloatingIP `json:"floating_ip"`
1155
resp, err = s.authRequest("GET", "/os-floating-ips/1", nil, nil)
1156
c.Assert(err, gc.IsNil)
1157
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
1158
assertJSON(c, resp, &expectedIP)
1159
c.Assert(expectedIP.IP, gc.DeepEquals, fips[0])
1162
func (s *NovaHTTPSuite) TestDeleteFloatingIP(c *gc.C) {
1163
fip := nova.FloatingIP{Id: "1", IP: "10.0.0.1", Pool: "nova"}
1164
err := s.service.addFloatingIP(fip)
1165
c.Assert(err, gc.IsNil)
1166
defer s.service.removeFloatingIP(fip.Id)
1167
resp, err := s.authRequest("DELETE", "/os-floating-ips/1", nil, nil)
1168
c.Assert(err, gc.IsNil)
1169
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
1170
_, err = s.service.floatingIP(fip.Id)
1171
c.Assert(err, gc.NotNil)
1174
func (s *NovaHTTPSuite) TestAddServerFloatingIP(c *gc.C) {
1175
fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
1176
server := nova.ServerDetail{Id: "sr1"}
1177
err := s.service.addFloatingIP(fip)
1178
c.Assert(err, gc.IsNil)
1179
defer s.service.removeFloatingIP(fip.Id)
1180
err = s.service.addServer(server)
1181
c.Assert(err, gc.IsNil)
1182
defer s.service.removeServer(server.Id)
1183
c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, false)
1185
AddFloatingIP struct {
1186
Address string `json:"address"`
1187
} `json:"addFloatingIp"`
1189
req.AddFloatingIP.Address = fip.IP
1190
resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
1191
c.Assert(err, gc.IsNil)
1192
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
1193
c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, true)
1194
err = s.service.removeServerFloatingIP(server.Id, fip.Id)
1195
c.Assert(err, gc.IsNil)
1198
func (s *NovaHTTPSuite) TestRemoveServerFloatingIP(c *gc.C) {
1199
fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
1200
server := nova.ServerDetail{Id: "sr1"}
1201
err := s.service.addFloatingIP(fip)
1202
c.Assert(err, gc.IsNil)
1203
defer s.service.removeFloatingIP(fip.Id)
1204
err = s.service.addServer(server)
1205
c.Assert(err, gc.IsNil)
1206
defer s.service.removeServer(server.Id)
1207
err = s.service.addServerFloatingIP(server.Id, fip.Id)
1208
c.Assert(err, gc.IsNil)
1209
defer s.service.removeServerFloatingIP(server.Id, fip.Id)
1210
c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, true)
1212
RemoveFloatingIP struct {
1213
Address string `json:"address"`
1214
} `json:"removeFloatingIp"`
1216
req.RemoveFloatingIP.Address = fip.IP
1217
resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
1218
c.Assert(err, gc.IsNil)
1219
c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
1220
c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, false)
1223
func (s *NovaHTTPSuite) TestListAvailabilityZones(c *gc.C) {
1224
resp, err := s.jsonRequest("GET", "/os-availability-zone", nil, nil)
1225
c.Assert(err, gc.IsNil)
1226
assertBody(c, resp, errNotFoundJSON)
1228
zones := []nova.AvailabilityZone{
1231
Name: "az2", State: nova.AvailabilityZoneState{Available: true},
1234
s.service.SetAvailabilityZones(zones...)
1235
resp, err = s.jsonRequest("GET", "/os-availability-zone", nil, nil)
1236
c.Assert(err, gc.IsNil)
1237
var expected struct {
1238
Zones []nova.AvailabilityZone `json:"availabilityZoneInfo"`
1240
assertJSON(c, resp, &expected)
1241
c.Assert(expected.Zones, gc.DeepEquals, zones)
1244
func (s *NovaHTTPSSuite) SetUpSuite(c *gc.C) {
1245
s.HTTPSuite.SetUpSuite(c)
1246
identityDouble := identityservice.NewUserPass()
1247
userInfo := identityDouble.AddUser("fred", "secret", "tenant")
1248
s.token = userInfo.Token
1249
c.Assert(s.Server.URL[:8], gc.Equals, "https://")
1250
s.service = New(s.Server.URL, versionPath, userInfo.TenantId, region, identityDouble, nil)
1253
func (s *NovaHTTPSSuite) TearDownSuite(c *gc.C) {
1254
s.HTTPSuite.TearDownSuite(c)
1257
func (s *NovaHTTPSSuite) SetUpTest(c *gc.C) {
1258
s.HTTPSuite.SetUpTest(c)
1259
s.service.SetupHTTP(s.Mux)
1262
func (s *NovaHTTPSSuite) TearDownTest(c *gc.C) {
1263
s.HTTPSuite.TearDownTest(c)
1266
func (s *NovaHTTPSSuite) TestHasHTTPSServiceURL(c *gc.C) {
1267
endpoints := s.service.Endpoints()
1268
c.Assert(endpoints[0].PublicURL[:8], gc.Equals, "https://")
1271
func (s *NovaHTTPSuite) TestSetServerMetadata(c *gc.C) {
1272
const serverId = "sr1"
1274
err := s.service.addServer(nova.ServerDetail{Id: serverId})
1275
c.Assert(err, gc.IsNil)
1276
defer s.service.removeServer(serverId)
1278
Metadata map[string]string `json:"metadata"`
1280
req.Metadata = map[string]string{
1284
resp, err := s.jsonRequest("POST", "/servers/"+serverId+"/metadata", req, nil)
1285
c.Assert(err, gc.IsNil)
1286
c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
1288
server, err := s.service.server(serverId)
1289
c.Assert(err, gc.IsNil)
1290
c.Assert(server.Metadata, gc.DeepEquals, req.Metadata)