Merge lp:goose into lp:~go-bot/goose/test

Proposed by John A Meinel on 2013-05-13
Status: Merged
Approved by: John A Meinel on 2013-07-01
Approved revision: 99
Merge reported by: John A Meinel
Merged at revision: not available
Proposed branch: lp:goose
Merge into: lp:~go-bot/goose/test
Diff against target: 2679 lines (+931/-386)
32 files modified
client/client.go (+2/-0)
client/client_test.go (+5/-3)
client/live_test.go (+5/-5)
client/local_test.go (+10/-2)
goose.go (+3/-0)
http/client.go (+1/-0)
http/client_test.go (+51/-7)
identity/identity.go (+9/-3)
identity/identity_test.go (+51/-0)
identity/keypair.go (+41/-0)
identity/keystone.go (+89/-0)
identity/local_test.go (+22/-1)
identity/userpass.go (+1/-75)
nova/json.go (+167/-66)
nova/json_test.go (+1/-1)
nova/local_test.go (+7/-5)
nova/nova.go (+19/-24)
nova/nova_test.go (+2/-2)
swift/local_test.go (+2/-1)
testservices/identityservice/identityservice.go (+1/-0)
testservices/identityservice/keypair.go (+123/-0)
testservices/identityservice/keypair_test.go (+130/-0)
testservices/identityservice/legacy.go (+4/-0)
testservices/identityservice/userpass.go (+5/-3)
testservices/novaservice/service.go (+38/-38)
testservices/novaservice/service_http.go (+12/-35)
testservices/novaservice/service_http_test.go (+34/-49)
testservices/novaservice/service_test.go (+61/-61)
testservices/openstackservice/openstack.go (+27/-3)
tools/secgroup-delete-all/main_test.go (+2/-2)
version.go (+3/-0)
version_test.go (+3/-0)
To merge this branch: bzr merge lp:goose
Reviewer Review Type Date Requested Status
Juju Engineering 2013-05-13 Pending
Review via email: mp+163468@code.launchpad.net

Commit message

Merge trunk into test branch.

Description of the change

Seeing if we get proper test hook triggers.

To post a comment you must log in.
Go Bot (go-bot) wrote :
Download full text (4.9 KiB)

The attempt to merge lp:goose into lp:~go-bot/goose/test failed. Below is the output from the failed tests.

cd /home/tarmac/trees/src/launchpad.net/juju-core
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/juju-core
bzr tags
cd /home/tarmac/trees/src/launchpad.net/juju-core
bzr update -r revno:-1
cd /home/tarmac/trees/src/labix.org/v2/mgo
bzr pull --overwrite
cd /home/tarmac/trees/src/labix.org/v2/mgo
bzr tags
cd /home/tarmac/trees/src/labix.org/v2/mgo
bzr update -r go1
cd /home/tarmac/trees/src/launchpad.net/goyaml
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/goyaml
bzr tags
cd /home/tarmac/trees/src/launchpad.net/goyaml
bzr update -r revno:-1
cd /home/tarmac/trees/src/launchpad.net/gnuflag
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/gnuflag
bzr tags
cd /home/tarmac/trees/src/launchpad.net/gnuflag
bzr update -r revno:-1
cd /home/tarmac/trees/src/code.google.com/p/go.net
hg pull
cd /home/tarmac/trees/src/code.google.com/p/go.net
hg tags
cd /home/tarmac/trees/src/code.google.com/p/go.net
hg branches
cd /home/tarmac/trees/src/code.google.com/p/go.net
hg update default
cd /home/tarmac/trees/src/launchpad.net/goamz
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/goamz
bzr tags
cd /home/tarmac/trees/src/launchpad.net/goamz
bzr update -r revno:-1
cd /home/tarmac/trees/src/launchpad.net/gomaasapi
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/gomaasapi
bzr tags
cd /home/tarmac/trees/src/launchpad.net/gomaasapi
bzr update -r revno:-1
cd /home/tarmac/trees/src/launchpad.net/goose
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/tomb
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/tomb
bzr tags
cd /home/tarmac/trees/src/launchpad.net/tomb
bzr update -r revno:-1
cd /home/tarmac/trees/src/launchpad.net/lpad
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/lpad
bzr tags
cd /home/tarmac/trees/src/launchpad.net/lpad
bzr update -r revno:-1
cd /home/tarmac/trees/src/launchpad.net/gocheck
bzr pull --overwrite
cd /home/tarmac/trees/src/launchpad.net/gocheck
bzr tags
cd /home/tarmac/trees/src/launchpad.net/gocheck
bzr update -r revno:-1

----------------------------------------------------------------------
PANIC: local_test.go:39: localLiveSuite.SetUpSuite

Using identity service test double
... Panic: interface conversion: identityservice.IdentityService is *identityservice.KeyPair, not *identityservice.UserPass (PC=0x4112F8)

/build/buildd/golang-1/src/pkg/runtime/proc.c:1443
  in panic
/build/buildd/golang-1/src/pkg/runtime/iface.c:247
  in assertI2Tret
/build/buildd/golang-1/src/pkg/runtime/iface.c:227
  in assertI2T
/home/tarmac/trees/src/launchpad.net/goose/testservices/openstackservice/openstack.go:52
  in New
local_test.go:54
  in localLiveSuite.SetUpSuite
OOPS: 16 passed, 4 skipped, 1 FIXTURE-PANICKED, 10 MISSED
--- FAIL: Test (0.01 seconds)
FAIL
FAIL launchpad.net/goose/client 0.025s
ok launchpad.net/goose/errors 0.007s
ok launchpad.net/goose/glance 0.012s
ok launchpad.net/goose/http 0.014s
ok launchpad.net/goose/identity 0.021s
ok launchpad.net/goose/nova 0.093s
ok launchpad.net/goose/swift 0.051s
ok launchpad.net/goose/sync 0....

Read more...

Go Bot (go-bot) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'client/client.go'
2--- client/client.go 2013-03-28 12:36:12 +0000
3+++ client/client.go 2013-07-01 07:24:26 +0000
4@@ -106,6 +106,8 @@
5 client.authMode = &identity.Legacy{}
6 case identity.AuthUserPass:
7 client.authMode = &identity.UserPass{}
8+ case identity.AuthKeyPair:
9+ client.authMode = &identity.KeyPair{}
10 }
11 return &client
12 }
13
14=== modified file 'client/client_test.go'
15--- client/client_test.go 2013-02-04 01:01:12 +0000
16+++ client/client_test.go 2013-07-01 07:24:26 +0000
17@@ -9,10 +9,10 @@
18
19 var live = flag.Bool("live", false, "Include live OpenStack (Canonistack) tests")
20 var liveAuthMode = flag.String(
21- "live-auth-mode", "userpass", "The authentication mode to use when running live tests [all|legacy|userpass]")
22+ "live-auth-mode", "userpass", "The authentication mode to use when running live tests [all|legacy|userpass|keypair]")
23
24 func Test(t *testing.T) {
25- var allAuthModes = []identity.AuthMode{identity.AuthLegacy, identity.AuthUserPass}
26+ var allAuthModes = []identity.AuthMode{identity.AuthLegacy, identity.AuthUserPass, identity.AuthKeyPair}
27 var liveAuthModes []identity.AuthMode
28 switch *liveAuthMode {
29 default:
30@@ -20,6 +20,8 @@
31 case "all":
32 liveAuthModes = allAuthModes
33 case "":
34+ case "keypair":
35+ liveAuthModes = []identity.AuthMode{identity.AuthKeyPair}
36 case "userpass":
37 liveAuthModes = []identity.AuthMode{identity.AuthUserPass}
38 case "legacy":
39@@ -29,7 +31,7 @@
40 if *live {
41 cred, err := identity.CompleteCredentialsFromEnv()
42 if err != nil {
43- t.Fatalf("Error setting up test suite: %s", err.Error())
44+ t.Fatalf("Error setting up test suite: %v", err)
45 }
46 registerOpenStackTests(cred, liveAuthModes)
47 }
48
49=== modified file 'client/live_test.go'
50--- client/live_test.go 2013-03-28 09:06:20 +0000
51+++ client/live_test.go 2013-07-01 07:24:26 +0000
52@@ -48,16 +48,16 @@
53 }
54
55 func (s *LiveTests) TestAuthenticate(c *C) {
56- client := client.NewClient(s.cred, s.authMode, nil)
57- err := client.Authenticate()
58+ cl := client.NewClient(s.cred, s.authMode, nil)
59+ err := cl.Authenticate()
60 c.Assert(err, IsNil)
61- c.Assert(client.IsAuthenticated(), Equals, true)
62+ c.Assert(cl.IsAuthenticated(), Equals, true)
63
64 // Check service endpoints are discovered
65- url, err := client.MakeServiceURL("compute", nil)
66+ url, err := cl.MakeServiceURL("compute", nil)
67 c.Check(err, IsNil)
68 c.Check(url, NotNil)
69- url, err = client.MakeServiceURL("object-store", nil)
70+ url, err = cl.MakeServiceURL("object-store", nil)
71 c.Check(err, IsNil)
72 c.Check(url, NotNil)
73 }
74
75=== modified file 'client/local_test.go'
76--- client/local_test.go 2013-03-28 12:36:12 +0000
77+++ client/local_test.go 2013-07-01 07:24:26 +0000
78@@ -49,14 +49,22 @@
79 switch s.authMode {
80 default:
81 panic("Invalid authentication method")
82+ case identity.AuthKeyPair:
83+ // The openstack test service sets up keypair authentication.
84+ s.service = openstackservice.New(s.cred, identity.AuthKeyPair)
85+ // Add an additional endpoint so region filtering can be properly tested.
86+ serviceDef := identityservice.Service{"nova", "compute", []identityservice.Endpoint{
87+ identityservice.Endpoint{PublicURL: "http://nova2", Region: "zone2.RegionOne"},
88+ }}
89+ s.service.(*openstackservice.Openstack).Identity.AddService(serviceDef)
90 case identity.AuthUserPass:
91 // The openstack test service sets up userpass authentication.
92- s.service = openstackservice.New(s.cred)
93+ s.service = openstackservice.New(s.cred, identity.AuthUserPass)
94 // Add an additional endpoint so region filtering can be properly tested.
95 serviceDef := identityservice.Service{"nova", "compute", []identityservice.Endpoint{
96 identityservice.Endpoint{PublicURL: "http://nova2", Region: "zone2.RegionOne"},
97 }}
98- s.service.(*openstackservice.Openstack).Identity.(*identityservice.UserPass).AddService(serviceDef)
99+ s.service.(*openstackservice.Openstack).Identity.AddService(serviceDef)
100
101 case identity.AuthLegacy:
102 legacy := identityservice.NewLegacy()
103
104=== modified file 'goose.go'
105--- goose.go 2012-10-31 15:50:00 +0000
106+++ goose.go 2013-07-01 07:24:26 +0000
107@@ -1,1 +1,4 @@
108+// Copyright 2013 Canonical Ltd.
109+// Licensed under the LGPLv3, see COPYING and COPYING.LESSER file for details.
110+
111 package goose
112
113=== modified file 'http/client.go'
114--- http/client.go 2013-04-19 09:19:53 +0000
115+++ http/client.go 2013-07-01 07:24:26 +0000
116@@ -209,6 +209,7 @@
117 req.Header.Add(header, value)
118 }
119 }
120+ req.ContentLength = int64(len(reqData))
121 resp, err = c.Do(req)
122 if err != nil {
123 return nil, errors.Newf(err, "failed executing the request %s", URL)
124
125=== modified file 'http/client_test.go'
126--- http/client_test.go 2013-02-22 00:36:43 +0000
127+++ http/client_test.go 2013-07-01 07:24:26 +0000
128@@ -1,6 +1,9 @@
129 package http
130
131 import (
132+ "bytes"
133+ "fmt"
134+ "io/ioutil"
135 . "launchpad.net/gocheck"
136 "launchpad.net/goose/testing/httpsuite"
137 "net/http"
138@@ -52,21 +55,25 @@
139 http.Header{"Foo": []string{"Bar"}, "Content-Type": contentTypes, "Accept": contentTypes, "User-Agent": []string{gooseAgent()}})
140 }
141
142-func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, *Client) {
143- headers := http.Header{}
144+func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, chan string, *Client) {
145+ var headers http.Header
146+ bodyChan := make(chan string, 1)
147 handler := func(resp http.ResponseWriter, req *http.Request) {
148 headers = req.Header
149+ bodyBytes, _ := ioutil.ReadAll(req.Body)
150+ req.Body.Close()
151+ bodyChan <- string(bodyBytes)
152 resp.Header().Add("Content-Length", "0")
153 resp.WriteHeader(http.StatusNoContent)
154 resp.Write([]byte{})
155 }
156 s.Mux.HandleFunc("/", handler)
157 client := New()
158- return &headers, client
159+ return &headers, bodyChan, client
160 }
161
162 func (s *HTTPClientTestSuite) TestBinaryRequestSetsUserAgent(c *C) {
163- headers, client := s.setupLoopbackRequest()
164+ headers, _, client := s.setupLoopbackRequest()
165 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
166 err := client.BinaryRequest("POST", s.Server.URL, "", req, nil)
167 c.Assert(err, IsNil)
168@@ -76,7 +83,7 @@
169 }
170
171 func (s *HTTPClientTestSuite) TestJSONRequestSetsUserAgent(c *C) {
172- headers, client := s.setupLoopbackRequest()
173+ headers, _, client := s.setupLoopbackRequest()
174 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
175 err := client.JsonRequest("POST", s.Server.URL, "", req, nil)
176 c.Assert(err, IsNil)
177@@ -85,8 +92,45 @@
178 c.Check(agent, Equals, gooseAgent())
179 }
180
181+func (s *HTTPClientTestSuite) TestBinaryRequestSetsContentLength(c *C) {
182+ headers, bodyChan, client := s.setupLoopbackRequest()
183+ content := "binary\ncontent\n"
184+ req := &RequestData{
185+ ExpectedStatus: []int{http.StatusNoContent},
186+ ReqReader: bytes.NewBufferString(content),
187+ ReqLength: len(content),
188+ }
189+ err := client.BinaryRequest("POST", s.Server.URL, "", req, nil)
190+ c.Assert(err, IsNil)
191+ encoding := headers.Get("Transfer-Encoding")
192+ c.Check(encoding, Equals, "")
193+ length := headers.Get("Content-Length")
194+ c.Check(length, Equals, fmt.Sprintf("%d", len(content)))
195+ body, ok := <-bodyChan
196+ c.Assert(ok, Equals, true)
197+ c.Check(body, Equals, content)
198+}
199+
200+func (s *HTTPClientTestSuite) TestJSONRequestSetsContentLength(c *C) {
201+ headers, bodyChan, client := s.setupLoopbackRequest()
202+ reqMap := map[string]string{"key": "value"}
203+ req := &RequestData{
204+ ExpectedStatus: []int{http.StatusNoContent},
205+ ReqValue: reqMap,
206+ }
207+ err := client.JsonRequest("POST", s.Server.URL, "", req, nil)
208+ c.Assert(err, IsNil)
209+ encoding := headers.Get("Transfer-Encoding")
210+ c.Check(encoding, Equals, "")
211+ length := headers.Get("Content-Length")
212+ body, ok := <-bodyChan
213+ c.Assert(ok, Equals, true)
214+ c.Check(body, Not(Equals), "")
215+ c.Check(length, Equals, fmt.Sprintf("%d", len(body)))
216+}
217+
218 func (s *HTTPClientTestSuite) TestBinaryRequestSetsToken(c *C) {
219- headers, client := s.setupLoopbackRequest()
220+ headers, _, client := s.setupLoopbackRequest()
221 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
222 err := client.BinaryRequest("POST", s.Server.URL, "token", req, nil)
223 c.Assert(err, IsNil)
224@@ -95,7 +139,7 @@
225 }
226
227 func (s *HTTPClientTestSuite) TestJSONRequestSetsToken(c *C) {
228- headers, client := s.setupLoopbackRequest()
229+ headers, _, client := s.setupLoopbackRequest()
230 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
231 err := client.JsonRequest("POST", s.Server.URL, "token", req, nil)
232 c.Assert(err, IsNil)
233
234=== modified file 'identity/identity.go'
235--- identity/identity.go 2013-02-12 01:47:38 +0000
236+++ identity/identity.go 2013-07-01 07:24:26 +0000
237@@ -15,10 +15,13 @@
238 const (
239 AuthLegacy = AuthMode(iota) // Legacy authentication
240 AuthUserPass // Username + password authentication
241+ AuthKeyPair // Access/secret key pair authentication
242 )
243
244 func (a AuthMode) String() string {
245 switch a {
246+ case AuthKeyPair:
247+ return "Access/Secret Key Authentication"
248 case AuthLegacy:
249 return "Legacy Authentication"
250 case AuthUserPass:
251@@ -69,9 +72,12 @@
252 // environment variables.
253 func CredentialsFromEnv() *Credentials {
254 return &Credentials{
255- URL: getConfig("OS_AUTH_URL"),
256- User: getConfig("OS_USERNAME", "NOVA_USERNAME"),
257- Secrets: getConfig("OS_PASSWORD", "NOVA_PASSWORD"),
258+ URL: getConfig("OS_AUTH_URL"),
259+ User: getConfig("OS_USERNAME", "NOVA_USERNAME",
260+ "OS_ACCESS_KEY", "NOVA_API_KEY"),
261+ Secrets: getConfig("OS_PASSWORD", "NOVA_PASSWORD",
262+ "OS_SECRET_KEY", "EC2_SECRET_KEYS",
263+ "AWS_SECRET_ACCESS_KEY"),
264 Region: getConfig("OS_REGION_NAME", "NOVA_REGION"),
265 TenantName: getConfig("OS_TENANT_NAME", "NOVA_PROJECT_ID"),
266 }
267
268=== modified file 'identity/identity_test.go'
269--- identity/identity_test.go 2013-02-11 05:01:34 +0000
270+++ identity/identity_test.go 2013-07-01 07:24:26 +0000
271@@ -27,6 +27,8 @@
272 env: map[string]string{
273 "NOVA_USERNAME": "test-user",
274 "NOVA_PASSWORD": "test-pass",
275+ "NOVA_API_KEY": "test-access-key",
276+ "EC2_SECRET_KEYS": "test-secret-key",
277 "NOVA_PROJECT_ID": "tenant-name",
278 "NOVA_REGION": "region",
279 },
280@@ -39,6 +41,8 @@
281 env: map[string]string{
282 "OS_USERNAME": "test-user",
283 "OS_PASSWORD": "test-pass",
284+ "OS_ACCESS_KEY": "test-access-key",
285+ "OS_SECRET_KEY": "test-secret-key",
286 "OS_TENANT_NAME": "tenant-name",
287 "OS_REGION_NAME": "region",
288 },
289@@ -66,6 +70,8 @@
290 "OS_AUTH_URL": "http://auth",
291 "OS_USERNAME": "test-user",
292 "OS_PASSWORD": "test-pass",
293+ "OS_ACCESS_KEY": "test-access-key",
294+ "OS_SECRET_KEY": "test-secret-key",
295 "OS_TENANT_NAME": "tenant-name",
296 "OS_REGION_NAME": "region",
297 }
298@@ -86,6 +92,7 @@
299 env := map[string]string{
300 "OS_AUTH_URL": "http://auth",
301 "OS_USERNAME": "test-user",
302+ "OS_ACCESS_KEY": "test-access-key",
303 "OS_TENANT_NAME": "tenant-name",
304 "OS_REGION_NAME": "region",
305 }
306@@ -96,3 +103,47 @@
307 c.Assert(err, Not(IsNil))
308 c.Assert(err.Error(), Matches, "required environment variable not set.*: Secrets")
309 }
310+
311+func (s *CredentialsTestSuite) TestCompleteCredentialsFromEnvKeypair(c *C) {
312+ env := map[string]string{
313+ "OS_AUTH_URL": "http://auth",
314+ "OS_USERNAME": "",
315+ "OS_PASSWORD": "",
316+ "OS_ACCESS_KEY": "test-access-key",
317+ "OS_SECRET_KEY": "test-secret-key",
318+ "OS_TENANT_NAME": "tenant-name",
319+ "OS_REGION_NAME": "region",
320+ }
321+ for key, value := range env {
322+ os.Setenv(key, value)
323+ }
324+ creds, err := CompleteCredentialsFromEnv()
325+ c.Assert(err, IsNil)
326+ c.Check(creds.URL, Equals, "http://auth")
327+ c.Check(creds.User, Equals, "test-access-key")
328+ c.Check(creds.Secrets, Equals, "test-secret-key")
329+ c.Check(creds.Region, Equals, "region")
330+ c.Check(creds.TenantName, Equals, "tenant-name")
331+}
332+
333+func (s *CredentialsTestSuite) TestCompleteCredentialsFromEnvKeypairCompatibleEnvVars(c *C) {
334+ env := map[string]string{
335+ "OS_AUTH_URL": "http://auth",
336+ "OS_USERNAME": "",
337+ "OS_PASSWORD": "",
338+ "NOVA_API_KEY": "test-access-key",
339+ "EC2_SECRET_KEYS": "test-secret-key",
340+ "OS_TENANT_NAME": "tenant-name",
341+ "OS_REGION_NAME": "region",
342+ }
343+ for key, value := range env {
344+ os.Setenv(key, value)
345+ }
346+ creds, err := CompleteCredentialsFromEnv()
347+ c.Assert(err, IsNil)
348+ c.Check(creds.URL, Equals, "http://auth")
349+ c.Check(creds.User, Equals, "test-access-key")
350+ c.Check(creds.Secrets, Equals, "test-secret-key")
351+ c.Check(creds.Region, Equals, "region")
352+ c.Check(creds.TenantName, Equals, "tenant-name")
353+}
354
355=== added file 'identity/keypair.go'
356--- identity/keypair.go 1970-01-01 00:00:00 +0000
357+++ identity/keypair.go 2013-07-01 07:24:26 +0000
358@@ -0,0 +1,41 @@
359+package identity
360+
361+import (
362+ goosehttp "launchpad.net/goose/http"
363+)
364+
365+// KeyPair allows OpenStack cloud authentication using an access and
366+// secret key.
367+//
368+// It implements Authenticator interface by providing the Auth method.
369+type KeyPair struct {
370+ client *goosehttp.Client
371+}
372+
373+type keypairCredentials struct {
374+ AccessKey string `json:"accessKey"`
375+ SecretKey string `json:"secretKey"`
376+}
377+
378+type authKeypairRequest struct {
379+ KeypairCredentials keypairCredentials `json:"apiAccessKeyCredentials"`
380+ TenantName string `json:"tenantName"`
381+}
382+
383+type authKeypairWrapper struct {
384+ Auth authKeypairRequest `json:"auth"`
385+}
386+
387+func (u *KeyPair) Auth(creds *Credentials) (*AuthDetails, error) {
388+ if u.client == nil {
389+ u.client = goosehttp.New()
390+ }
391+ auth := authKeypairWrapper{Auth: authKeypairRequest{
392+ KeypairCredentials: keypairCredentials{
393+ AccessKey: creds.User,
394+ SecretKey: creds.Secrets,
395+ },
396+ TenantName: creds.TenantName}}
397+
398+ return keystoneAuth(u.client, auth, creds.URL)
399+}
400
401=== added file 'identity/keystone.go'
402--- identity/keystone.go 1970-01-01 00:00:00 +0000
403+++ identity/keystone.go 2013-07-01 07:24:26 +0000
404@@ -0,0 +1,89 @@
405+package identity
406+
407+import (
408+ "fmt"
409+ goosehttp "launchpad.net/goose/http"
410+)
411+
412+type endpoint struct {
413+ AdminURL string `json:"adminURL"`
414+ InternalURL string `json:"internalURL"`
415+ PublicURL string `json:"publicURL"`
416+ Region string `json:"region"`
417+}
418+
419+type serviceResponse struct {
420+ Name string `json:"name"`
421+ Type string `json:"type"`
422+ Endpoints []endpoint
423+}
424+
425+type tokenResponse struct {
426+ Expires string `json:"expires"`
427+ Id string `json:"id"` // Actual token string
428+ Tenant struct {
429+ Id string `json:"id"`
430+ Name string `json:"name"`
431+ // Description is a pointer since it may be null and this breaks Go < 1.1
432+ Description *string `json:"description"`
433+ Enabled bool `json:"enabled"`
434+ } `json:"tenant"`
435+}
436+
437+type roleResponse struct {
438+ Id string `json:"id"`
439+ Name string `json:"name"`
440+ TenantId string `json:"tenantId"`
441+}
442+
443+type userResponse struct {
444+ Id string `json:"id"`
445+ Name string `json:"name"`
446+ Roles []roleResponse `json:"roles"`
447+}
448+
449+type accessWrapper struct {
450+ Access accessResponse `json:"access"`
451+}
452+
453+type accessResponse struct {
454+ ServiceCatalog []serviceResponse `json:"serviceCatalog"`
455+ Token tokenResponse `json:"token"`
456+ User userResponse `json:"user"`
457+}
458+
459+// keystoneAuth authenticates to OpenStack cloud using keystone v2 authentication.
460+//
461+// Uses `client` to submit HTTP requests to `URL`
462+// and posts `auth_data` as JSON.
463+func keystoneAuth(client *goosehttp.Client, auth_data interface{}, URL string) (*AuthDetails, error) {
464+
465+ var accessWrapper accessWrapper
466+ requestData := goosehttp.RequestData{ReqValue: auth_data, RespValue: &accessWrapper}
467+ err := client.JsonRequest("POST", URL, "", &requestData, nil)
468+ if err != nil {
469+ return nil, err
470+ }
471+
472+ details := &AuthDetails{}
473+ access := accessWrapper.Access
474+ respToken := access.Token
475+ if respToken.Id == "" {
476+ return nil, fmt.Errorf("authentication failed")
477+ }
478+ details.Token = respToken.Id
479+ details.TenantId = respToken.Tenant.Id
480+ details.UserId = access.User.Id
481+ details.RegionServiceURLs = make(map[string]ServiceURLs, len(access.ServiceCatalog))
482+ for _, service := range access.ServiceCatalog {
483+ for i, e := range service.Endpoints {
484+ endpointURLs, ok := details.RegionServiceURLs[e.Region]
485+ if !ok {
486+ endpointURLs = make(ServiceURLs)
487+ details.RegionServiceURLs[e.Region] = endpointURLs
488+ }
489+ endpointURLs[service.Type] = service.Endpoints[i].PublicURL
490+ }
491+ }
492+ return details, nil
493+}
494
495=== modified file 'identity/local_test.go'
496--- identity/local_test.go 2013-02-12 01:47:38 +0000
497+++ identity/local_test.go 2013-07-01 07:24:26 +0000
498@@ -6,6 +6,8 @@
499 "launchpad.net/goose/testservices/openstackservice"
500 "net/http"
501 "net/http/httptest"
502+ "net/url"
503+ "strings"
504 )
505
506 func registerLocalTests() {
507@@ -39,7 +41,7 @@
508 Region: "zone1.some region",
509 TenantName: "tenant",
510 }
511- openstack := openstackservice.New(s.cred)
512+ openstack := openstackservice.New(s.cred, identity.AuthUserPass)
513 openstack.SetupHTTP(s.Mux)
514
515 s.LiveTests.SetUpSuite(c)
516@@ -61,3 +63,22 @@
517 }
518
519 // Additional tests to be run against the service double only go here.
520+
521+func (s *localLiveSuite) TestProductStreamsEndpoint(c *C) {
522+ err := s.client.Authenticate()
523+ c.Assert(err, IsNil)
524+ serviceURL, err := s.client.MakeServiceURL("product-streams", nil)
525+ c.Assert(err, IsNil)
526+ _, err = url.Parse(serviceURL)
527+ c.Assert(err, IsNil)
528+ c.Assert(strings.HasSuffix(serviceURL, "/imagemetadata"), Equals, true)
529+}
530+
531+func (s *localLiveSuite) TestJujuToolsEndpoint(c *C) {
532+ err := s.client.Authenticate()
533+ c.Assert(err, IsNil)
534+ serviceURL, err := s.client.MakeServiceURL("juju-tools", nil)
535+ c.Assert(err, IsNil)
536+ _, err = url.Parse(serviceURL)
537+ c.Assert(err, IsNil)
538+}
539
540=== modified file 'identity/userpass.go'
541--- identity/userpass.go 2013-02-20 02:30:14 +0000
542+++ identity/userpass.go 2013-07-01 07:24:26 +0000
543@@ -1,7 +1,6 @@
544 package identity
545
546 import (
547- "fmt"
548 goosehttp "launchpad.net/goose/http"
549 )
550
551@@ -19,52 +18,6 @@
552 Auth authRequest `json:"auth"`
553 }
554
555-type endpoint struct {
556- AdminURL string `json:"adminURL"`
557- InternalURL string `json:"internalURL"`
558- PublicURL string `json:"publicURL"`
559- Region string `json:"region"`
560-}
561-
562-type serviceResponse struct {
563- Name string `json:"name"`
564- Type string `json:"type"`
565- Endpoints []endpoint
566-}
567-
568-type tokenResponse struct {
569- Expires string `json:"expires"` // should this be a date object?
570- Id string `json:"id"` // Actual token string
571- Tenant struct {
572- Id string `json:"id"`
573- Name string `json:"name"`
574- Description string `json:"description"`
575- Enabled bool `json:"enabled"`
576- } `json:"tenant"`
577-}
578-
579-type roleResponse struct {
580- Id string `json:"id"`
581- Name string `json:"name"`
582- TenantId string `json:"tenantId"`
583-}
584-
585-type userResponse struct {
586- Id string `json:"id"`
587- Name string `json:"name"`
588- Roles []roleResponse `json:"roles"`
589-}
590-
591-type accessWrapper struct {
592- Access accessResponse `json:"access"`
593-}
594-
595-type accessResponse struct {
596- ServiceCatalog []serviceResponse `json:"serviceCatalog"`
597- Token tokenResponse `json:"token"`
598- User userResponse `json:"user"`
599-}
600-
601 type UserPass struct {
602 client *goosehttp.Client
603 }
604@@ -80,32 +33,5 @@
605 },
606 TenantName: creds.TenantName}}
607
608- var accessWrapper accessWrapper
609- requestData := goosehttp.RequestData{ReqValue: auth, RespValue: &accessWrapper}
610- err := u.client.JsonRequest("POST", creds.URL, "", &requestData, nil)
611- if err != nil {
612- return nil, err
613- }
614-
615- details := &AuthDetails{}
616- access := accessWrapper.Access
617- respToken := access.Token
618- if respToken.Id == "" {
619- return nil, fmt.Errorf("Did not get valid Token from auth request")
620- }
621- details.Token = respToken.Id
622- details.TenantId = respToken.Tenant.Id
623- details.UserId = access.User.Id
624- details.RegionServiceURLs = make(map[string]ServiceURLs, len(access.ServiceCatalog))
625- for _, service := range access.ServiceCatalog {
626- for i, e := range service.Endpoints {
627- endpointURLs, ok := details.RegionServiceURLs[e.Region]
628- if !ok {
629- endpointURLs = make(ServiceURLs)
630- details.RegionServiceURLs[e.Region] = endpointURLs
631- }
632- endpointURLs[service.Type] = service.Endpoints[i].PublicURL
633- }
634- }
635- return details, nil
636+ return keystoneAuth(u.client, auth, creds.URL)
637 }
638
639=== modified file 'nova/json.go'
640--- nova/json.go 2013-03-21 04:52:22 +0000
641+++ nova/json.go 2013-07-01 07:24:26 +0000
642@@ -14,19 +14,12 @@
643 "strconv"
644 )
645
646-type genericId struct {
647- Id interface{} `json:"id"`
648-}
649-
650-func (id genericId) String() string {
651- if id.Id == nil {
652- return ""
653- }
654- if fid, ok := id.Id.(float64); ok {
655- return fmt.Sprint(int(fid))
656- }
657- return fmt.Sprint(id.Id)
658-}
659+const (
660+ idTag = "id"
661+ instanceIdTag = "instance_id"
662+ groupIdTag = "group_id"
663+ parentGroupIdTag = "parent_group_id"
664+)
665
666 var useNumericIds bool = false
667
668@@ -43,6 +36,25 @@
669 return result
670 }
671
672+// getIdAsString extracts the field with the specified tag from the json data
673+// and returns it converted to a string.
674+func getIdAsString(b []byte, tag string) (string, error) {
675+ var out map[string]interface{}
676+ if err := json.Unmarshal(b, &out); err != nil {
677+ return "", err
678+ }
679+ if val, ok := out[tag]; !ok {
680+ return "", nil
681+ } else {
682+ if floatVal, ok := val.(float64); ok {
683+ return fmt.Sprint(int(floatVal)), nil
684+ } else {
685+ return fmt.Sprint(val), nil
686+ }
687+ }
688+ panic("unreachable")
689+}
690+
691 // appendJSON marshals the given attribute value and appends it as an encoded value to the given json data.
692 // The newly encode (attr, value) is inserted just before the closing "}" in the json data.
693 func appendJSON(data []byte, attr string, value interface{}) ([]byte, error) {
694@@ -59,14 +71,13 @@
695
696 func (entity *Entity) UnmarshalJSON(b []byte) error {
697 var je jsonEntity = jsonEntity(*entity)
698- if err := json.Unmarshal(b, &je); err != nil {
699- return err
700- }
701- var id genericId
702- if err := json.Unmarshal(b, &id); err != nil {
703- return err
704- }
705- je.Id = id.String()
706+ var err error
707+ if err = json.Unmarshal(b, &je); err != nil {
708+ return err
709+ }
710+ if je.Id, err = getIdAsString(b, idTag); err != nil {
711+ return err
712+ }
713 *entity = Entity(je)
714 return nil
715 }
716@@ -78,21 +89,20 @@
717 return nil, err
718 }
719 id := convertId(entity.Id)
720- return appendJSON(data, "Id", id)
721+ return appendJSON(data, idTag, id)
722 }
723
724 type jsonFlavorDetail FlavorDetail
725
726 func (flavorDetail *FlavorDetail) UnmarshalJSON(b []byte) error {
727 var jfd jsonFlavorDetail = jsonFlavorDetail(*flavorDetail)
728- if err := json.Unmarshal(b, &jfd); err != nil {
729- return err
730- }
731- var id genericId
732- if err := json.Unmarshal(b, &id); err != nil {
733- return err
734- }
735- jfd.Id = id.String()
736+ var err error
737+ if err = json.Unmarshal(b, &jfd); err != nil {
738+ return err
739+ }
740+ if jfd.Id, err = getIdAsString(b, idTag); err != nil {
741+ return err
742+ }
743 *flavorDetail = FlavorDetail(jfd)
744 return nil
745 }
746@@ -104,21 +114,20 @@
747 return nil, err
748 }
749 id := convertId(flavorDetail.Id)
750- return appendJSON(data, "Id", id)
751+ return appendJSON(data, idTag, id)
752 }
753
754 type jsonServerDetail ServerDetail
755
756 func (serverDetail *ServerDetail) UnmarshalJSON(b []byte) error {
757 var jsd jsonServerDetail = jsonServerDetail(*serverDetail)
758- if err := json.Unmarshal(b, &jsd); err != nil {
759- return err
760- }
761- var id genericId
762- if err := json.Unmarshal(b, &id); err != nil {
763- return err
764- }
765- jsd.Id = id.String()
766+ var err error
767+ if err = json.Unmarshal(b, &jsd); err != nil {
768+ return err
769+ }
770+ if jsd.Id, err = getIdAsString(b, idTag); err != nil {
771+ return err
772+ }
773 *serverDetail = ServerDetail(jsd)
774 return nil
775 }
776@@ -130,39 +139,26 @@
777 return nil, err
778 }
779 id := convertId(serverDetail.Id)
780- return appendJSON(data, "Id", id)
781-}
782-
783-type genericInstanceId struct {
784- InstanceId interface{} `json:"instance_id"`
785-}
786-
787-func (id genericInstanceId) String() string {
788- if id.InstanceId == nil {
789- return ""
790- }
791- if fid, ok := id.InstanceId.(float64); ok {
792- return fmt.Sprint(int(fid))
793- }
794- return fmt.Sprint(id.InstanceId)
795+ return appendJSON(data, idTag, id)
796 }
797
798 type jsonFloatingIP FloatingIP
799
800 func (floatingIP *FloatingIP) UnmarshalJSON(b []byte) error {
801 var jfip jsonFloatingIP = jsonFloatingIP(*floatingIP)
802- if err := json.Unmarshal(b, &jfip); err != nil {
803- return err
804- }
805- var id genericInstanceId
806- if err := json.Unmarshal(b, &id); err != nil {
807- return err
808- }
809- instId := id.String()
810- if instId != "" {
811- strId := instId
812+ var err error
813+ if err = json.Unmarshal(b, &jfip); err != nil {
814+ return err
815+ }
816+ if instIdStr, err := getIdAsString(b, instanceIdTag); err != nil {
817+ return err
818+ } else if instIdStr != "" {
819+ strId := instIdStr
820 jfip.InstanceId = &strId
821 }
822+ if jfip.Id, err = getIdAsString(b, idTag); err != nil {
823+ return err
824+ }
825 *floatingIP = FloatingIP(jfip)
826 return nil
827 }
828@@ -173,9 +169,114 @@
829 if err != nil {
830 return nil, err
831 }
832+ id := convertId(floatingIP.Id)
833+ data, err = appendJSON(data, idTag, id)
834+ if err != nil {
835+ return nil, err
836+ }
837 if floatingIP.InstanceId == nil {
838 return data, nil
839 }
840- id := convertId(*floatingIP.InstanceId)
841- return appendJSON(data, "instance_id", id)
842+ instId := convertId(*floatingIP.InstanceId)
843+ return appendJSON(data, instanceIdTag, instId)
844+}
845+
846+type jsonSecurityGroup SecurityGroup
847+
848+func (securityGroup *SecurityGroup) UnmarshalJSON(b []byte) error {
849+ var jsg jsonSecurityGroup = jsonSecurityGroup(*securityGroup)
850+ var err error
851+ if err = json.Unmarshal(b, &jsg); err != nil {
852+ return err
853+ }
854+ if jsg.Id, err = getIdAsString(b, idTag); err != nil {
855+ return err
856+ }
857+ *securityGroup = SecurityGroup(jsg)
858+ return nil
859+}
860+
861+func (securityGroup SecurityGroup) MarshalJSON() ([]byte, error) {
862+ var jsg jsonSecurityGroup = jsonSecurityGroup(securityGroup)
863+ data, err := json.Marshal(&jsg)
864+ if err != nil {
865+ return nil, err
866+ }
867+ id := convertId(securityGroup.Id)
868+ return appendJSON(data, idTag, id)
869+}
870+
871+type jsonSecurityGroupRule SecurityGroupRule
872+
873+func (securityGroupRule *SecurityGroupRule) UnmarshalJSON(b []byte) error {
874+ var jsgr jsonSecurityGroupRule = jsonSecurityGroupRule(*securityGroupRule)
875+ var err error
876+ if err = json.Unmarshal(b, &jsgr); err != nil {
877+ return err
878+ }
879+ if jsgr.Id, err = getIdAsString(b, idTag); err != nil {
880+ return err
881+ }
882+ if jsgr.ParentGroupId, err = getIdAsString(b, parentGroupIdTag); err != nil {
883+ return err
884+ }
885+ *securityGroupRule = SecurityGroupRule(jsgr)
886+ return nil
887+}
888+
889+func (securityGroupRule SecurityGroupRule) MarshalJSON() ([]byte, error) {
890+ var jsgr jsonSecurityGroupRule = jsonSecurityGroupRule(securityGroupRule)
891+ data, err := json.Marshal(&jsgr)
892+ if err != nil {
893+ return nil, err
894+ }
895+ id := convertId(securityGroupRule.Id)
896+ data, err = appendJSON(data, idTag, id)
897+ if err != nil {
898+ return nil, err
899+ }
900+ if securityGroupRule.ParentGroupId == "" {
901+ return data, nil
902+ }
903+ id = convertId(securityGroupRule.ParentGroupId)
904+ return appendJSON(data, parentGroupIdTag, id)
905+}
906+
907+type jsonRuleInfo RuleInfo
908+
909+func (ruleInfo *RuleInfo) UnmarshalJSON(b []byte) error {
910+ var jri jsonRuleInfo = jsonRuleInfo(*ruleInfo)
911+ var err error
912+ if err = json.Unmarshal(b, &jri); err != nil {
913+ return err
914+ }
915+ if jri.ParentGroupId, err = getIdAsString(b, parentGroupIdTag); err != nil {
916+ return err
917+ }
918+ if groupId, err := getIdAsString(b, groupIdTag); err != nil {
919+ return err
920+ } else if groupId != "" {
921+ strId := groupId
922+ jri.GroupId = &strId
923+ }
924+ *ruleInfo = RuleInfo(jri)
925+ return nil
926+}
927+
928+func (ruleInfo RuleInfo) MarshalJSON() ([]byte, error) {
929+ var jri jsonRuleInfo = jsonRuleInfo(ruleInfo)
930+ data, err := json.Marshal(&jri)
931+ if err != nil {
932+ return nil, err
933+ }
934+ id := convertId(ruleInfo.ParentGroupId)
935+ data, err = appendJSON(data, parentGroupIdTag, id)
936+ if err != nil {
937+ return nil, err
938+ }
939+ if ruleInfo.GroupId == nil {
940+ return data, nil
941+ }
942+ id = convertId(*ruleInfo.GroupId)
943+ return appendJSON(data, groupIdTag, id)
944 }
945
946=== modified file 'nova/json_test.go'
947--- nova/json_test.go 2013-03-21 11:43:56 +0000
948+++ nova/json_test.go 2013-07-01 07:24:26 +0000
949@@ -52,7 +52,7 @@
950
951 func (s *JsonSuite) TestMarshallFloatingIPLargeIntId(c *C) {
952 id := "3000000"
953- fip := nova.FloatingIP{Id: 2000000, InstanceId: &id}
954+ fip := nova.FloatingIP{Id: "2000000", InstanceId: &id}
955 var unmarshalled nova.FloatingIP
956 s.assertMarshallRoundtrip(c, &fip, &unmarshalled)
957 }
958
959=== modified file 'nova/local_test.go'
960--- nova/local_test.go 2013-03-28 09:06:20 +0000
961+++ nova/local_test.go 2013-07-01 07:24:26 +0000
962@@ -71,7 +71,7 @@
963 Region: "some region",
964 TenantName: "tenant",
965 }
966- s.openstack = openstackservice.New(s.cred)
967+ s.openstack = openstackservice.New(s.cred, identity.AuthUserPass)
968 s.openstack.SetupHTTP(s.Mux)
969
970 s.testFlavor = "m1.small"
971@@ -172,8 +172,8 @@
972 fips, err := novaClient.ListFloatingIPs()
973 c.Assert(err, IsNil)
974 c.Assert(fips, HasLen, 0)
975- s.openstack.Nova.RegisterControlPoint("addFloatingIP", s.addFloatingIPHook(s.openstack.Nova))
976- defer s.openstack.Nova.RegisterControlPoint("addFloatingIP", nil)
977+ cleanup := s.openstack.Nova.RegisterControlPoint("addFloatingIP", s.addFloatingIPHook(s.openstack.Nova))
978+ defer cleanup()
979 s.noMoreIPs = true
980 fip, err := novaClient.AllocateFloatingIP()
981 c.Assert(err, ErrorMatches, "(.|\n)*Zero floating ips available.*")
982@@ -203,7 +203,8 @@
983 func (s *localLiveSuite) TestReauthenticate(c *C) {
984 novaClient := s.setupClient(c, nil)
985 up := s.openstack.Identity.(*identityservice.UserPass)
986- defer up.RegisterControlPoint("authorisation", s.authHook(up))
987+ cleanup := up.RegisterControlPoint("authorisation", s.authHook(up))
988+ defer cleanup()
989
990 // An invalid token is returned after the first authentication step, resulting in the ListServers call
991 // returning a 401. Subsequent authentication calls return the correct token so the auth retry does it's job.
992@@ -215,7 +216,8 @@
993 func (s *localLiveSuite) TestReauthenticateFailure(c *C) {
994 novaClient := s.setupClient(c, nil)
995 up := s.openstack.Identity.(*identityservice.UserPass)
996- defer up.RegisterControlPoint("authorisation", s.authHook(up))
997+ cleanup := up.RegisterControlPoint("authorisation", s.authHook(up))
998+ defer cleanup()
999
1000 // If the re-authentication fails, ensure an Unauthorised error is returned.
1001 s.badTokens = 2
1002
1003=== modified file 'nova/nova.go'
1004--- nova/nova.go 2013-04-23 00:19:57 +0000
1005+++ nova/nova.go 2013-07-01 07:24:26 +0000
1006@@ -11,7 +11,6 @@
1007 "net/http"
1008 "net/url"
1009 "reflect"
1010- "strconv"
1011 )
1012
1013 // API URL parts.
1014@@ -327,9 +326,9 @@
1015 FromPort *int `json:"from_port"` // Can be nil
1016 IPProtocol *string `json:"ip_protocol"` // Can be nil
1017 ToPort *int `json:"to_port"` // Can be nil
1018- ParentGroupId int `json:"parent_group_id"`
1019+ ParentGroupId string `json:"-"`
1020 IPRange map[string]string `json:"ip_range"` // Can be empty
1021- Id int
1022+ Id string `json:"-"`
1023 Group SecurityGroupRef
1024 }
1025
1026@@ -337,7 +336,7 @@
1027 type SecurityGroup struct {
1028 Rules []SecurityGroupRule
1029 TenantId string `json:"tenant_id"`
1030- Id int
1031+ Id string `json:"-"`
1032 Name string
1033 Description string
1034 }
1035@@ -389,12 +388,8 @@
1036 if err == nil {
1037 result := make([]SecurityGroup, len(serverDetails.Groups))
1038 for i, e := range serverDetails.Groups {
1039- id, err := strconv.Atoi(e.Id)
1040- if err != nil {
1041- return nil, errors.Newf(err, "failed to parse security group id %s", e.Id)
1042- }
1043 result[i] = SecurityGroup{
1044- Id: id,
1045+ Id: e.Id,
1046 Name: e.Name,
1047 }
1048 }
1049@@ -429,8 +424,8 @@
1050 }
1051
1052 // DeleteSecurityGroup deletes the specified security group.
1053-func (c *Client) DeleteSecurityGroup(groupId int) error {
1054- url := fmt.Sprintf("%s/%d", apiSecurityGroups, groupId)
1055+func (c *Client) DeleteSecurityGroup(groupId string) error {
1056+ url := fmt.Sprintf("%s/%s", apiSecurityGroups, groupId)
1057 requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusAccepted}}
1058 err := c.client.SendRequest(client.DELETE, "compute", url, &requestData)
1059 if err != nil {
1060@@ -473,14 +468,14 @@
1061 // Cidr cannot be specified with GroupId. Ingress rules need a valid
1062 // subnet mast in CIDR format here, while if GroupID is specifed, it
1063 // means you're adding a group rule, specifying source group ID, which
1064- // must exists already and can be equal to ParentGroupId).
1065+ // must exist already and can be equal to ParentGroupId).
1066 // need Cidr, while
1067- Cidr string `json:"cidr"`
1068- GroupId *int `json:"group_id"`
1069+ Cidr string `json:"cidr"`
1070+ GroupId *string `json:"-"`
1071
1072 // ParentGroupId is always required and specifies the group to which
1073 // the rule is added.
1074- ParentGroupId int `json:"parent_group_id"`
1075+ ParentGroupId string `json:"-"`
1076 }
1077
1078 // CreateSecurityGroupRule creates a security group rule.
1079@@ -505,8 +500,8 @@
1080 }
1081
1082 // DeleteSecurityGroupRule deletes the specified security group rule.
1083-func (c *Client) DeleteSecurityGroupRule(ruleId int) error {
1084- url := fmt.Sprintf("%s/%d", apiSecurityGroupRules, ruleId)
1085+func (c *Client) DeleteSecurityGroupRule(ruleId string) error {
1086+ url := fmt.Sprintf("%s/%s", apiSecurityGroupRules, ruleId)
1087 requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusAccepted}}
1088 err := c.client.SendRequest(client.DELETE, "compute", url, &requestData)
1089 if err != nil {
1090@@ -556,7 +551,7 @@
1091 type FloatingIP struct {
1092 // FixedIP holds the private IP address of the machine (when assigned)
1093 FixedIP *string `json:"fixed_ip"`
1094- Id int `json:"id"`
1095+ Id string `json:"-"`
1096 // InstanceId holds the instance id of the machine, if this FIP is assigned to one
1097 InstanceId *string `json:"-"`
1098 IP string `json:"ip"`
1099@@ -578,16 +573,16 @@
1100 }
1101
1102 // GetFloatingIP lists details of the floating IP address associated with specified id.
1103-func (c *Client) GetFloatingIP(ipId int) (*FloatingIP, error) {
1104+func (c *Client) GetFloatingIP(ipId string) (*FloatingIP, error) {
1105 var resp struct {
1106 FloatingIP FloatingIP `json:"floating_ip"`
1107 }
1108
1109- url := fmt.Sprintf("%s/%d", apiFloatingIPs, ipId)
1110+ url := fmt.Sprintf("%s/%s", apiFloatingIPs, ipId)
1111 requestData := goosehttp.RequestData{RespValue: &resp}
1112 err := c.client.SendRequest(client.GET, "compute", url, &requestData)
1113 if err != nil {
1114- return nil, errors.Newf(err, "failed to get floating ip %d details", ipId)
1115+ return nil, errors.Newf(err, "failed to get floating ip %s details", ipId)
1116 }
1117 return &resp.FloatingIP, nil
1118 }
1119@@ -607,12 +602,12 @@
1120 }
1121
1122 // DeleteFloatingIP deallocates the floating IP address associated with the specified id.
1123-func (c *Client) DeleteFloatingIP(ipId int) error {
1124- url := fmt.Sprintf("%s/%d", apiFloatingIPs, ipId)
1125+func (c *Client) DeleteFloatingIP(ipId string) error {
1126+ url := fmt.Sprintf("%s/%s", apiFloatingIPs, ipId)
1127 requestData := goosehttp.RequestData{ExpectedStatus: []int{http.StatusAccepted}}
1128 err := c.client.SendRequest(client.DELETE, "compute", url, &requestData)
1129 if err != nil {
1130- err = errors.Newf(err, "failed to delete floating ip %d details", ipId)
1131+ err = errors.Newf(err, "failed to delete floating ip %s details", ipId)
1132 }
1133 return err
1134 }
1135
1136=== modified file 'nova/nova_test.go'
1137--- nova/nova_test.go 2013-02-06 06:15:09 +0000
1138+++ nova/nova_test.go 2013-07-01 07:24:26 +0000
1139@@ -18,9 +18,9 @@
1140 // Out-of-the-box, we support live testing using Canonistack or HP Cloud.
1141 var testConstraints = map[string]imageDetails{
1142 "canonistack": imageDetails{
1143- flavor: "m1.tiny", imageId: "c876e5fe-abb0-41f0-8f29-f0b47481f523"},
1144+ flavor: "m1.tiny", imageId: "f2ca48ce-30d5-4f1f-9075-12e64510368d"},
1145 "hpcloud": imageDetails{
1146- flavor: "standard.xsmall", imageId: "75845"},
1147+ flavor: "standard.xsmall", imageId: "81078"},
1148 }
1149
1150 var live = flag.Bool("live", false, "Include live OpenStack tests")
1151
1152=== modified file 'swift/local_test.go'
1153--- swift/local_test.go 2013-01-29 00:45:31 +0000
1154+++ swift/local_test.go 2013-07-01 07:24:26 +0000
1155@@ -33,7 +33,8 @@
1156 TenantName: "tenant",
1157 }
1158 s.LiveTestsPublicContainer.cred = s.LiveTests.cred
1159- s.openstack = openstackservice.New(s.LiveTests.cred)
1160+ s.openstack = openstackservice.New(s.LiveTests.cred,
1161+ identity.AuthUserPass)
1162
1163 s.LiveTests.SetUpSuite(c)
1164 s.LiveTestsPublicContainer.SetUpSuite(c)
1165
1166=== modified file 'testservices/identityservice/identityservice.go'
1167--- testservices/identityservice/identityservice.go 2013-01-24 03:15:19 +0000
1168+++ testservices/identityservice/identityservice.go 2013-07-01 07:24:26 +0000
1169@@ -7,6 +7,7 @@
1170 AddUser(user, secret, tenant string) *UserInfo
1171 FindUser(token string) (*UserInfo, error)
1172 RegisterServiceProvider(name, serviceType string, serviceProvider ServiceProvider)
1173+ AddService(service Service)
1174 SetupHTTP(mux *http.ServeMux)
1175 }
1176
1177
1178=== added file 'testservices/identityservice/keypair.go'
1179--- testservices/identityservice/keypair.go 1970-01-01 00:00:00 +0000
1180+++ testservices/identityservice/keypair.go 2013-07-01 07:24:26 +0000
1181@@ -0,0 +1,123 @@
1182+package identityservice
1183+
1184+import (
1185+ "encoding/json"
1186+ "fmt"
1187+ "io/ioutil"
1188+ "launchpad.net/goose/testservices/hook"
1189+ "net/http"
1190+)
1191+
1192+// Implement the v2 Key Pair form of identity based on Keystone
1193+
1194+type KeyPairRequest struct {
1195+ Auth struct {
1196+ ApiAccessKeyCredentials struct {
1197+ AccessKey string `json:"accessKey"`
1198+ SecretKey string `json:"secretKey"`
1199+ } `json:"apiAccessKeyCredentials"`
1200+ TenantName string `json:"tenantName"`
1201+ } `json:"auth"`
1202+}
1203+
1204+type KeyPair struct {
1205+ hook.TestService
1206+ Users
1207+ services []Service
1208+}
1209+
1210+func NewKeyPair() *KeyPair {
1211+ return &KeyPair{
1212+ Users: Users{
1213+ users: make(map[string]UserInfo),
1214+ tenants: make(map[string]string),
1215+ },
1216+ }
1217+}
1218+
1219+func (u *KeyPair) RegisterServiceProvider(name, serviceType string, serviceProvider ServiceProvider) {
1220+ service := Service{name, serviceType, serviceProvider.Endpoints()}
1221+ u.AddService(service)
1222+}
1223+
1224+func (u *KeyPair) AddService(service Service) {
1225+ u.services = append(u.services, service)
1226+}
1227+
1228+func (u *KeyPair) ReturnFailure(w http.ResponseWriter, status int, message string) {
1229+ e := ErrorWrapper{
1230+ Error: ErrorResponse{
1231+ Message: message,
1232+ Code: status,
1233+ Title: http.StatusText(status),
1234+ },
1235+ }
1236+ if content, err := json.Marshal(e); err != nil {
1237+ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(internalError)))
1238+ w.WriteHeader(http.StatusInternalServerError)
1239+ w.Write(internalError)
1240+ } else {
1241+ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(content)))
1242+ w.WriteHeader(status)
1243+ w.Write(content)
1244+ }
1245+}
1246+
1247+func (u *KeyPair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
1248+ var req KeyPairRequest
1249+ // Testing against Canonistack, all responses are application/json, even failures
1250+ w.Header().Set("Content-Type", "application/json")
1251+ if r.Header.Get("Content-Type") != "application/json" {
1252+ u.ReturnFailure(w, http.StatusBadRequest, notJSON)
1253+ return
1254+ }
1255+ if content, err := ioutil.ReadAll(r.Body); err != nil {
1256+ w.WriteHeader(http.StatusBadRequest)
1257+ return
1258+ } else {
1259+ if err := json.Unmarshal(content, &req); err != nil {
1260+ u.ReturnFailure(w, http.StatusBadRequest, notJSON)
1261+ return
1262+ }
1263+ }
1264+ userInfo, errmsg := u.authenticate(req.Auth.ApiAccessKeyCredentials.AccessKey, req.Auth.ApiAccessKeyCredentials.SecretKey)
1265+ if errmsg != "" {
1266+ u.ReturnFailure(w, http.StatusUnauthorized, errmsg)
1267+ return
1268+ }
1269+ res, err := u.generateAccessResponse(userInfo)
1270+ if err != nil {
1271+ u.ReturnFailure(w, http.StatusInternalServerError, err.Error())
1272+ return
1273+ }
1274+ if content, err := json.Marshal(res); err != nil {
1275+ u.ReturnFailure(w, http.StatusInternalServerError, err.Error())
1276+ return
1277+ } else {
1278+ w.WriteHeader(http.StatusOK)
1279+ w.Write(content)
1280+ return
1281+ }
1282+ panic("unreachable")
1283+}
1284+
1285+func (u *KeyPair) generateAccessResponse(userInfo *UserInfo) (*AccessResponse, error) {
1286+ res := AccessResponse{}
1287+ // We pre-populate the response with genuine entries so that it looks sane.
1288+ if err := json.Unmarshal([]byte(exampleResponse), &res); err != nil {
1289+ return nil, err
1290+ }
1291+ res.Access.ServiceCatalog = u.services
1292+ res.Access.Token.Id = userInfo.Token
1293+ res.Access.Token.Tenant.Id = userInfo.TenantId
1294+ res.Access.User.Id = userInfo.Id
1295+ if err := u.ProcessControlHook("authorisation", u, &res, userInfo); err != nil {
1296+ return nil, err
1297+ }
1298+ return &res, nil
1299+}
1300+
1301+// setupHTTP attaches all the needed handlers to provide the HTTP API.
1302+func (u *KeyPair) SetupHTTP(mux *http.ServeMux) {
1303+ mux.Handle("/tokens", u)
1304+}
1305
1306=== added file 'testservices/identityservice/keypair_test.go'
1307--- testservices/identityservice/keypair_test.go 1970-01-01 00:00:00 +0000
1308+++ testservices/identityservice/keypair_test.go 2013-07-01 07:24:26 +0000
1309@@ -0,0 +1,130 @@
1310+package identityservice
1311+
1312+import (
1313+ "encoding/json"
1314+ "fmt"
1315+ "io/ioutil"
1316+ . "launchpad.net/gocheck"
1317+ "launchpad.net/goose/testing/httpsuite"
1318+ "net/http"
1319+ "strings"
1320+)
1321+
1322+type KeyPairSuite struct {
1323+ httpsuite.HTTPSuite
1324+}
1325+
1326+var _ = Suite(&KeyPairSuite{})
1327+
1328+func makeKeyPair(user, secret string) (identity *KeyPair) {
1329+ identity = NewKeyPair()
1330+ // Ensure that it conforms to the interface
1331+ var _ IdentityService = identity
1332+ if user != "" {
1333+ identity.AddUser(user, secret, "tenant")
1334+ }
1335+ return
1336+}
1337+
1338+func (s *KeyPairSuite) setupKeyPair(user, secret string) {
1339+ var identity *KeyPair
1340+ identity = makeKeyPair(user, secret)
1341+ identity.SetupHTTP(s.Mux)
1342+ return
1343+}
1344+
1345+func (s *KeyPairSuite) setupKeyPairWithServices(user, secret string, services []Service) {
1346+ var identity *KeyPair
1347+ identity = makeKeyPair(user, secret)
1348+ for _, service := range services {
1349+ identity.AddService(service)
1350+ }
1351+ identity.SetupHTTP(s.Mux)
1352+ return
1353+}
1354+
1355+const authKeyPairTemplate = `{
1356+ "auth": {
1357+ "tenantName": "tenant-something",
1358+ "apiAccessKeyCredentials": {
1359+ "accessKey": "%s",
1360+ "secretKey": "%s"
1361+ }
1362+ }
1363+}`
1364+
1365+func keyPairAuthRequest(URL, access, secret string) (*http.Response, error) {
1366+ client := &http.DefaultClient
1367+ body := strings.NewReader(fmt.Sprintf(authKeyPairTemplate, access, secret))
1368+ request, err := http.NewRequest("POST", URL+"/tokens", body)
1369+ request.Header.Set("Content-Type", "application/json")
1370+ if err != nil {
1371+ return nil, err
1372+ }
1373+ return client.Do(request)
1374+}
1375+
1376+func (s *KeyPairSuite) TestNotJSON(c *C) {
1377+ // We do everything in keyPairAuthRequest, except set the Content-Type
1378+ s.setupKeyPair("user", "secret")
1379+ client := &http.DefaultClient
1380+ body := strings.NewReader(fmt.Sprintf(authTemplate, "user", "secret"))
1381+ request, err := http.NewRequest("POST", s.Server.URL+"/tokens", body)
1382+ c.Assert(err, IsNil)
1383+ res, err := client.Do(request)
1384+ defer res.Body.Close()
1385+ c.Assert(err, IsNil)
1386+ CheckErrorResponse(c, res, http.StatusBadRequest, notJSON)
1387+}
1388+
1389+func (s *KeyPairSuite) TestBadJSON(c *C) {
1390+ // We do everything in keyPairAuthRequest, except set the Content-Type
1391+ s.setupKeyPair("user", "secret")
1392+ res, err := keyPairAuthRequest(s.Server.URL, `garbage"in`, "secret")
1393+ defer res.Body.Close()
1394+ c.Assert(err, IsNil)
1395+ CheckErrorResponse(c, res, http.StatusBadRequest, notJSON)
1396+}
1397+
1398+func (s *KeyPairSuite) TestNoSuchUser(c *C) {
1399+ s.setupKeyPair("user", "secret")
1400+ res, err := keyPairAuthRequest(s.Server.URL, "not-user", "secret")
1401+ defer res.Body.Close()
1402+ c.Assert(err, IsNil)
1403+ CheckErrorResponse(c, res, http.StatusUnauthorized, notAuthorized)
1404+}
1405+
1406+func (s *KeyPairSuite) TestBadPassword(c *C) {
1407+ s.setupKeyPair("user", "secret")
1408+ res, err := keyPairAuthRequest(s.Server.URL, "user", "not-secret")
1409+ defer res.Body.Close()
1410+ c.Assert(err, IsNil)
1411+ CheckErrorResponse(c, res, http.StatusUnauthorized, invalidUser)
1412+}
1413+
1414+func (s *KeyPairSuite) TestValidAuthorization(c *C) {
1415+ compute_url := "http://testing.invalid/compute"
1416+ s.setupKeyPairWithServices("user", "secret", []Service{
1417+ {"nova", "compute", []Endpoint{
1418+ {PublicURL: compute_url},
1419+ }}})
1420+ res, err := keyPairAuthRequest(s.Server.URL, "user", "secret")
1421+ defer res.Body.Close()
1422+ c.Assert(err, IsNil)
1423+ c.Check(res.StatusCode, Equals, http.StatusOK)
1424+ c.Check(res.Header.Get("Content-Type"), Equals, "application/json")
1425+ content, err := ioutil.ReadAll(res.Body)
1426+ c.Assert(err, IsNil)
1427+ var response AccessResponse
1428+ err = json.Unmarshal(content, &response)
1429+ c.Assert(err, IsNil)
1430+ c.Check(response.Access.Token.Id, NotNil)
1431+ novaURL := ""
1432+ for _, service := range response.Access.ServiceCatalog {
1433+ if service.Type == "compute" {
1434+ novaURL = service.Endpoints[0].PublicURL
1435+ break
1436+ }
1437+ }
1438+ c.Assert(novaURL, Equals, compute_url)
1439+}
1440
1441=== modified file 'testservices/identityservice/legacy.go'
1442--- testservices/identityservice/legacy.go 2013-01-24 01:01:35 +0000
1443+++ testservices/identityservice/legacy.go 2013-07-01 07:24:26 +0000
1444@@ -20,6 +20,10 @@
1445 // NOOP for legacy identity service.
1446 }
1447
1448+func (lis *Legacy) AddService(service Service) {
1449+ // NOOP for legacy identity service.
1450+}
1451+
1452 func (lis *Legacy) SetManagementURL(URL string) {
1453 lis.managementURL = URL
1454 }
1455
1456=== modified file 'testservices/identityservice/userpass.go'
1457--- testservices/identityservice/userpass.go 2013-02-20 06:00:49 +0000
1458+++ testservices/identityservice/userpass.go 2013-07-01 07:24:26 +0000
1459@@ -47,8 +47,9 @@
1460 Expires string `json:"expires"` // should this be a date object?
1461 Id string `json:"id"` // Actual token string
1462 Tenant struct {
1463- Id string `json:"id"`
1464- Name string `json:"name"`
1465+ Id string `json:"id"`
1466+ Name string `json:"name"`
1467+ Description *string `json:"description"`
1468 } `json:"tenant"`
1469 }
1470
1471@@ -118,7 +119,8 @@
1472 "id": "5df9d45d-d198-4222-9b4c-7a280aa35666",
1473 "tenant": {
1474 "id": "1",
1475- "name": "admin"
1476+ "name": "admin",
1477+ "description": null
1478 }
1479 },
1480 "user": {
1481
1482=== modified file 'testservices/novaservice/service.go'
1483--- testservices/novaservice/service.go 2013-04-22 23:20:03 +0000
1484+++ testservices/novaservice/service.go 2013-07-01 07:24:26 +0000
1485@@ -21,11 +21,11 @@
1486 testservices.ServiceInstance
1487 flavors map[string]nova.FlavorDetail
1488 servers map[string]nova.ServerDetail
1489- groups map[int]nova.SecurityGroup
1490- rules map[int]nova.SecurityGroupRule
1491- floatingIPs map[int]nova.FloatingIP
1492- serverGroups map[string][]int
1493- serverIPs map[string][]int
1494+ groups map[string]nova.SecurityGroup
1495+ rules map[string]nova.SecurityGroupRule
1496+ floatingIPs map[string]nova.FloatingIP
1497+ serverGroups map[string][]string
1498+ serverIPs map[string][]string
1499 nextServerId int
1500 nextGroupId int
1501 nextRuleId int
1502@@ -74,16 +74,16 @@
1503 }
1504 // Real openstack instances have a default security group "out of the box". So we add it here.
1505 defaultSecurityGroups := []nova.SecurityGroup{
1506- {Id: 999, Name: "default", Description: "default group"},
1507+ {Id: "999", Name: "default", Description: "default group"},
1508 }
1509 novaService := &Nova{
1510 flavors: make(map[string]nova.FlavorDetail),
1511 servers: make(map[string]nova.ServerDetail),
1512- groups: make(map[int]nova.SecurityGroup),
1513- rules: make(map[int]nova.SecurityGroupRule),
1514- floatingIPs: make(map[int]nova.FloatingIP),
1515- serverGroups: make(map[string][]int),
1516- serverIPs: make(map[string][]int),
1517+ groups: make(map[string]nova.SecurityGroup),
1518+ rules: make(map[string]nova.SecurityGroupRule),
1519+ floatingIPs: make(map[string]nova.FloatingIP),
1520+ serverGroups: make(map[string][]string),
1521+ serverIPs: make(map[string][]string),
1522 ServiceInstance: testservices.ServiceInstance{
1523 IdentityService: identityService,
1524 Hostname: hostname,
1525@@ -368,7 +368,7 @@
1526 return err
1527 }
1528 if _, err := n.securityGroup(group.Id); err == nil {
1529- return fmt.Errorf("a security group with id %d already exists", group.Id)
1530+ return fmt.Errorf("a security group with id %s already exists", group.Id)
1531 }
1532 group.TenantId = n.TenantId
1533 if group.Rules == nil {
1534@@ -379,13 +379,13 @@
1535 }
1536
1537 // securityGroup retrieves an existing group by ID.
1538-func (n *Nova) securityGroup(groupId int) (*nova.SecurityGroup, error) {
1539+func (n *Nova) securityGroup(groupId string) (*nova.SecurityGroup, error) {
1540 if err := n.ProcessFunctionHook(n, groupId); err != nil {
1541 return nil, err
1542 }
1543 group, ok := n.groups[groupId]
1544 if !ok {
1545- return nil, fmt.Errorf("no such security group %d", groupId)
1546+ return nil, fmt.Errorf("no such security group %s", groupId)
1547 }
1548 return &group, nil
1549 }
1550@@ -413,7 +413,7 @@
1551 }
1552
1553 // removeSecurityGroup deletes an existing group.
1554-func (n *Nova) removeSecurityGroup(groupId int) error {
1555+func (n *Nova) removeSecurityGroup(groupId string) error {
1556 if err := n.ProcessFunctionHook(n, groupId); err != nil {
1557 return err
1558 }
1559@@ -427,12 +427,12 @@
1560 // addSecurityGroupRule creates a new rule in an existing group.
1561 // This can be either an ingress or a group rule (see the notes
1562 // about nova.RuleInfo).
1563-func (n *Nova) addSecurityGroupRule(ruleId int, rule nova.RuleInfo) error {
1564+func (n *Nova) addSecurityGroupRule(ruleId string, rule nova.RuleInfo) error {
1565 if err := n.ProcessFunctionHook(n, ruleId, rule); err != nil {
1566 return err
1567 }
1568 if _, err := n.securityGroupRule(ruleId); err == nil {
1569- return fmt.Errorf("a security group rule with id %d already exists", ruleId)
1570+ return fmt.Errorf("a security group rule with id %s already exists", ruleId)
1571 }
1572 group, err := n.securityGroup(rule.ParentGroupId)
1573 if err != nil {
1574@@ -440,7 +440,7 @@
1575 }
1576 for _, ru := range group.Rules {
1577 if ru.Id == ruleId {
1578- return fmt.Errorf("cannot add twice rule %d to security group %d", ru.Id, group.Id)
1579+ return fmt.Errorf("cannot add twice rule %s to security group %s", ru.Id, group.Id)
1580 }
1581 }
1582 var zeroSecurityGroupRef nova.SecurityGroupRef
1583@@ -452,7 +452,7 @@
1584 if rule.GroupId != nil {
1585 sourceGroup, err := n.securityGroup(*rule.GroupId)
1586 if err != nil {
1587- return fmt.Errorf("unknown source security group %d", *rule.GroupId)
1588+ return fmt.Errorf("unknown source security group %s", *rule.GroupId)
1589 }
1590 newrule.Group = nova.SecurityGroupRef{
1591 TenantId: sourceGroup.TenantId,
1592@@ -480,27 +480,27 @@
1593 }
1594
1595 // hasSecurityGroupRule returns whether the given group contains the given rule,
1596-// or (when groupId=-1) whether the given rule exists.
1597-func (n *Nova) hasSecurityGroupRule(groupId, ruleId int) bool {
1598+// or (when groupId="-1") whether the given rule exists.
1599+func (n *Nova) hasSecurityGroupRule(groupId, ruleId string) bool {
1600 rule, ok := n.rules[ruleId]
1601 _, err := n.securityGroup(groupId)
1602- return ok && (groupId == -1 || (err == nil && rule.ParentGroupId == groupId))
1603+ return ok && (groupId == "-1" || (err == nil && rule.ParentGroupId == groupId))
1604 }
1605
1606 // securityGroupRule retrieves an existing rule by ID.
1607-func (n *Nova) securityGroupRule(ruleId int) (*nova.SecurityGroupRule, error) {
1608+func (n *Nova) securityGroupRule(ruleId string) (*nova.SecurityGroupRule, error) {
1609 if err := n.ProcessFunctionHook(n, ruleId); err != nil {
1610 return nil, err
1611 }
1612 rule, ok := n.rules[ruleId]
1613 if !ok {
1614- return nil, fmt.Errorf("no such security group rule %d", ruleId)
1615+ return nil, fmt.Errorf("no such security group rule %s", ruleId)
1616 }
1617 return &rule, nil
1618 }
1619
1620 // removeSecurityGroupRule deletes an existing rule from its group.
1621-func (n *Nova) removeSecurityGroupRule(ruleId int) error {
1622+func (n *Nova) removeSecurityGroupRule(ruleId string) error {
1623 if err := n.ProcessFunctionHook(n, ruleId); err != nil {
1624 return err
1625 }
1626@@ -528,7 +528,7 @@
1627 }
1628
1629 // addServerSecurityGroup attaches an existing server to a group.
1630-func (n *Nova) addServerSecurityGroup(serverId string, groupId int) error {
1631+func (n *Nova) addServerSecurityGroup(serverId string, groupId string) error {
1632 if err := n.ProcessFunctionHook(n, serverId, groupId); err != nil {
1633 return err
1634 }
1635@@ -542,7 +542,7 @@
1636 if ok {
1637 for _, gid := range groups {
1638 if gid == groupId {
1639- return fmt.Errorf("server %q already belongs to group %d", serverId, groupId)
1640+ return fmt.Errorf("server %q already belongs to group %s", serverId, groupId)
1641 }
1642 }
1643 }
1644@@ -552,7 +552,7 @@
1645 }
1646
1647 // hasServerSecurityGroup returns whether the given server belongs to the group.
1648-func (n *Nova) hasServerSecurityGroup(serverId string, groupId int) bool {
1649+func (n *Nova) hasServerSecurityGroup(serverId string, groupId string) bool {
1650 if _, err := n.server(serverId); err != nil {
1651 return false
1652 }
1653@@ -586,7 +586,7 @@
1654 }
1655
1656 // removeServerSecurityGroup detaches an existing server from a group.
1657-func (n *Nova) removeServerSecurityGroup(serverId string, groupId int) error {
1658+func (n *Nova) removeServerSecurityGroup(serverId string, groupId string) error {
1659 if err := n.ProcessFunctionHook(n, serverId, groupId); err != nil {
1660 return err
1661 }
1662@@ -608,7 +608,7 @@
1663 }
1664 }
1665 if idx == -1 {
1666- return fmt.Errorf("server %q does not belong to group %d", serverId, groupId)
1667+ return fmt.Errorf("server %q does not belong to group %s", serverId, groupId)
1668 }
1669 groups = append(groups[:idx], groups[idx+1:]...)
1670 n.serverGroups[serverId] = groups
1671@@ -621,7 +621,7 @@
1672 return err
1673 }
1674 if _, err := n.floatingIP(ip.Id); err == nil {
1675- return fmt.Errorf("a floating IP with id %d already exists", ip.Id)
1676+ return fmt.Errorf("a floating IP with id %s already exists", ip.Id)
1677 }
1678 n.floatingIPs[ip.Id] = ip
1679 return nil
1680@@ -641,13 +641,13 @@
1681 }
1682
1683 // floatingIP retrieves the floating IP by ID.
1684-func (n *Nova) floatingIP(ipId int) (*nova.FloatingIP, error) {
1685+func (n *Nova) floatingIP(ipId string) (*nova.FloatingIP, error) {
1686 if err := n.ProcessFunctionHook(n, ipId); err != nil {
1687 return nil, err
1688 }
1689 ip, ok := n.floatingIPs[ipId]
1690 if !ok {
1691- return nil, fmt.Errorf("no such floating IP %d", ipId)
1692+ return nil, fmt.Errorf("no such floating IP %s", ipId)
1693 }
1694 return &ip, nil
1695 }
1696@@ -675,7 +675,7 @@
1697 }
1698
1699 // removeFloatingIP deletes an existing floating IP by ID.
1700-func (n *Nova) removeFloatingIP(ipId int) error {
1701+func (n *Nova) removeFloatingIP(ipId string) error {
1702 if err := n.ProcessFunctionHook(n, ipId); err != nil {
1703 return err
1704 }
1705@@ -687,7 +687,7 @@
1706 }
1707
1708 // addServerFloatingIP attaches an existing floating IP to a server.
1709-func (n *Nova) addServerFloatingIP(serverId string, ipId int) error {
1710+func (n *Nova) addServerFloatingIP(serverId string, ipId string) error {
1711 if err := n.ProcessFunctionHook(n, serverId, ipId); err != nil {
1712 return err
1713 }
1714@@ -706,7 +706,7 @@
1715 if ok {
1716 for _, fipId := range fips {
1717 if fipId == ipId {
1718- return fmt.Errorf("server %q already has floating IP %d", serverId, ipId)
1719+ return fmt.Errorf("server %q already has floating IP %s", serverId, ipId)
1720 }
1721 }
1722 }
1723@@ -734,7 +734,7 @@
1724 }
1725
1726 // removeServerFloatingIP deletes an attached floating IP from a server.
1727-func (n *Nova) removeServerFloatingIP(serverId string, ipId int) error {
1728+func (n *Nova) removeServerFloatingIP(serverId string, ipId string) error {
1729 if err := n.ProcessFunctionHook(n, serverId); err != nil {
1730 return err
1731 }
1732@@ -760,7 +760,7 @@
1733 }
1734 }
1735 if idx == -1 {
1736- return fmt.Errorf("server %q does not have floating IP %d", serverId, ipId)
1737+ return fmt.Errorf("server %q does not have floating IP %s", serverId, ipId)
1738 }
1739 fips = append(fips[:idx], fips[idx+1:]...)
1740 n.serverIPs[serverId] = fips
1741
1742=== modified file 'testservices/novaservice/service_http.go'
1743--- testservices/novaservice/service_http.go 2013-02-25 07:16:32 +0000
1744+++ testservices/novaservice/service_http.go 2013-07-01 07:24:26 +0000
1745@@ -114,14 +114,6 @@
1746 nil,
1747 nil,
1748 }
1749- errBadRequestSG = &errorResponse{
1750- http.StatusBadRequest,
1751- `{"badRequest": {"message": "Security group id should be integer", "code": 400}}`,
1752- "application/json; charset=UTF-8",
1753- "bad security group id type",
1754- nil,
1755- nil,
1756- }
1757 errNotFound = &errorResponse{
1758 http.StatusNotFound,
1759 `404 Not Found
1760@@ -567,7 +559,7 @@
1761 if err != nil {
1762 return err
1763 }
1764- var groups []int
1765+ var groups []string
1766 if len(req.Server.SecurityGroups) > 0 {
1767 for _, group := range req.Server.SecurityGroups {
1768 groupName := group["name"]
1769@@ -772,11 +764,7 @@
1770 // If there was no group id specified in the path, it returns errNoGroupId
1771 func (n *Nova) processGroupId(w http.ResponseWriter, r *http.Request) (*nova.SecurityGroup, error) {
1772 if groupId := path.Base(r.URL.Path); groupId != "os-security-groups" {
1773- id, err := strconv.Atoi(groupId)
1774- if err != nil {
1775- return nil, errBadRequestSG
1776- }
1777- group, err := n.securityGroup(id)
1778+ group, err := n.securityGroup(groupId)
1779 if err != nil {
1780 return nil, errNotFoundJSONSG
1781 }
1782@@ -829,7 +817,7 @@
1783 return errBadRequestDuplicateValue
1784 }
1785 n.nextGroupId++
1786- nextId := n.nextGroupId
1787+ nextId := strconv.Itoa(n.nextGroupId)
1788 err = n.addSecurityGroup(nova.SecurityGroup{
1789 Id: nextId,
1790 Name: req.Group.Name,
1791@@ -912,7 +900,7 @@
1792 }
1793 }
1794 n.nextRuleId++
1795- nextId := n.nextRuleId
1796+ nextId := strconv.Itoa(n.nextRuleId)
1797 err = n.addSecurityGroupRule(nextId, req.Rule)
1798 if err != nil {
1799 return err
1800@@ -933,15 +921,10 @@
1801 return errNotFound
1802 case "DELETE":
1803 if ruleId := path.Base(r.URL.Path); ruleId != "os-security-group-rules" {
1804- id, err := strconv.Atoi(ruleId)
1805- if err != nil {
1806- // weird, but this is how nova responds
1807- return errBadRequestSG
1808- }
1809- if _, err = n.securityGroupRule(id); err != nil {
1810+ if _, err := n.securityGroupRule(ruleId); err != nil {
1811 return errNotFoundJSONSGR
1812 }
1813- if err = n.removeSecurityGroupRule(id); err != nil {
1814+ if err := n.removeSecurityGroupRule(ruleId); err != nil {
1815 return err
1816 }
1817 writeResponse(w, http.StatusAccepted, nil)
1818@@ -957,11 +940,7 @@
1819 switch r.Method {
1820 case "GET":
1821 if ipId := path.Base(r.URL.Path); ipId != "os-floating-ips" {
1822- nId, err := strconv.Atoi(ipId)
1823- if err != nil {
1824- return errNotFoundJSON
1825- }
1826- fip, err := n.floatingIP(nId)
1827+ fip, err := n.floatingIP(ipId)
1828 if err != nil {
1829 return errNotFoundJSON
1830 }
1831@@ -983,8 +962,8 @@
1832 return errNotFound
1833 }
1834 n.nextIPId++
1835- nextId := n.nextIPId
1836- addr := fmt.Sprintf("10.0.0.%d", nextId)
1837+ addr := fmt.Sprintf("10.0.0.%d", n.nextIPId)
1838+ nextId := strconv.Itoa(n.nextIPId)
1839 fip := nova.FloatingIP{Id: nextId, IP: addr, Pool: "nova"}
1840 err := n.addFloatingIP(fip)
1841 if err != nil {
1842@@ -1001,11 +980,9 @@
1843 return errNotFound
1844 case "DELETE":
1845 if ipId := path.Base(r.URL.Path); ipId != "os-floating-ips" {
1846- if nId, err := strconv.Atoi(ipId); err == nil {
1847- if err := n.removeFloatingIP(nId); err == nil {
1848- writeResponse(w, http.StatusAccepted, nil)
1849- return nil
1850- }
1851+ if err := n.removeFloatingIP(ipId); err == nil {
1852+ writeResponse(w, http.StatusAccepted, nil)
1853+ return nil
1854 }
1855 return errNotFoundJSON
1856 }
1857
1858=== modified file 'testservices/novaservice/service_http_test.go'
1859--- testservices/novaservice/service_http_test.go 2013-04-23 00:19:57 +0000
1860+++ testservices/novaservice/service_http_test.go 2013-07-01 07:24:26 +0000
1861@@ -322,11 +322,6 @@
1862 },
1863 {
1864 method: "GET",
1865- url: "/os-security-groups/invalid",
1866- expect: errBadRequestSG,
1867- },
1868- {
1869- method: "GET",
1870 url: "/os-security-groups/42",
1871 expect: errNotFoundJSONSG,
1872 },
1873@@ -357,11 +352,6 @@
1874 },
1875 {
1876 method: "DELETE",
1877- url: "/os-security-groups/invalid",
1878- expect: errBadRequestSG,
1879- },
1880- {
1881- method: "DELETE",
1882 url: "/os-security-groups/42",
1883 expect: errNotFoundJSONSG,
1884 },
1885@@ -404,11 +394,6 @@
1886 method: "DELETE",
1887 url: "/os-security-group-rules",
1888 expect: errNotFound,
1889- },
1890- {
1891- method: "DELETE",
1892- url: "/os-security-group-rules/invalid",
1893- expect: errBadRequestSG, // sic; should've been rule-specific
1894 },
1895 {
1896 method: "DELETE",
1897@@ -676,12 +661,12 @@
1898 {"name": "group1"},
1899 {"name": "group2"},
1900 }
1901- err = s.service.addSecurityGroup(nova.SecurityGroup{Id: 1, Name: "group1"})
1902- c.Assert(err, IsNil)
1903- defer s.service.removeSecurityGroup(1)
1904- err = s.service.addSecurityGroup(nova.SecurityGroup{Id: 2, Name: "group2"})
1905- c.Assert(err, IsNil)
1906- defer s.service.removeSecurityGroup(2)
1907+ err = s.service.addSecurityGroup(nova.SecurityGroup{Id: "1", Name: "group1"})
1908+ c.Assert(err, IsNil)
1909+ defer s.service.removeSecurityGroup("1")
1910+ err = s.service.addSecurityGroup(nova.SecurityGroup{Id: "2", Name: "group2"})
1911+ c.Assert(err, IsNil)
1912+ defer s.service.removeSecurityGroup("2")
1913 resp, err = s.jsonRequest("POST", "/servers", req, nil)
1914 c.Assert(err, IsNil)
1915 c.Assert(resp.StatusCode, Equals, http.StatusAccepted)
1916@@ -689,12 +674,12 @@
1917 c.Assert(expected.Server.SecurityGroups, DeepEquals, req.Server.SecurityGroups)
1918 srv, err = s.service.server(expected.Server.Id)
1919 c.Assert(err, IsNil)
1920- ok := s.service.hasServerSecurityGroup(srv.Id, 1)
1921- c.Assert(ok, Equals, true)
1922- ok = s.service.hasServerSecurityGroup(srv.Id, 2)
1923- c.Assert(ok, Equals, true)
1924- s.service.removeServerSecurityGroup(srv.Id, 1)
1925- s.service.removeServerSecurityGroup(srv.Id, 2)
1926+ ok := s.service.hasServerSecurityGroup(srv.Id, "1")
1927+ c.Assert(ok, Equals, true)
1928+ ok = s.service.hasServerSecurityGroup(srv.Id, "2")
1929+ c.Assert(ok, Equals, true)
1930+ s.service.removeServerSecurityGroup(srv.Id, "1")
1931+ s.service.removeServerSecurityGroup(srv.Id, "2")
1932 s.service.removeServer(srv.Id)
1933 }
1934
1935@@ -794,13 +779,13 @@
1936 c.Assert(expected.Groups, HasLen, 1)
1937 groups = []nova.SecurityGroup{
1938 {
1939- Id: 1,
1940+ Id: "1",
1941 Name: "group 1",
1942 TenantId: s.service.TenantId,
1943 Rules: []nova.SecurityGroupRule{},
1944 },
1945 {
1946- Id: 2,
1947+ Id: "2",
1948 Name: "group 2",
1949 TenantId: s.service.TenantId,
1950 Rules: []nova.SecurityGroupRule{},
1951@@ -829,7 +814,7 @@
1952
1953 func (s *NovaHTTPSuite) TestAddSecurityGroup(c *C) {
1954 group := nova.SecurityGroup{
1955- Id: 1,
1956+ Id: "1",
1957 Name: "group 1",
1958 Description: "desc",
1959 TenantId: s.service.TenantId,
1960@@ -858,7 +843,7 @@
1961 }
1962
1963 func (s *NovaHTTPSuite) TestDeleteSecurityGroup(c *C) {
1964- group := nova.SecurityGroup{Id: 1, Name: "group 1"}
1965+ group := nova.SecurityGroup{Id: "1", Name: "group 1"}
1966 _, err := s.service.securityGroup(group.Id)
1967 c.Assert(err, NotNil)
1968 err = s.service.addSecurityGroup(group)
1969@@ -872,8 +857,8 @@
1970 }
1971
1972 func (s *NovaHTTPSuite) TestAddSecurityGroupRule(c *C) {
1973- group1 := nova.SecurityGroup{Id: 1, Name: "src"}
1974- group2 := nova.SecurityGroup{Id: 2, Name: "tgt"}
1975+ group1 := nova.SecurityGroup{Id: "1", Name: "src"}
1976+ group2 := nova.SecurityGroup{Id: "2", Name: "tgt"}
1977 err := s.service.addSecurityGroup(group1)
1978 c.Assert(err, IsNil)
1979 defer s.service.removeSecurityGroup(group1.Id)
1980@@ -881,7 +866,7 @@
1981 c.Assert(err, IsNil)
1982 defer s.service.removeSecurityGroup(group2.Id)
1983 riIngress := nova.RuleInfo{
1984- ParentGroupId: 1,
1985+ ParentGroupId: "1",
1986 FromPort: 1234,
1987 ToPort: 4321,
1988 IPProtocol: "tcp",
1989@@ -894,7 +879,7 @@
1990 iprange := make(map[string]string)
1991 iprange["cidr"] = riIngress.Cidr
1992 rule1 := nova.SecurityGroupRule{
1993- Id: 1,
1994+ Id: "1",
1995 ParentGroupId: group1.Id,
1996 FromPort: &riIngress.FromPort,
1997 ToPort: &riIngress.ToPort,
1998@@ -902,7 +887,7 @@
1999 IPRange: iprange,
2000 }
2001 rule2 := nova.SecurityGroupRule{
2002- Id: 2,
2003+ Id: "2",
2004 ParentGroupId: group2.Id,
2005 Group: nova.SecurityGroupRef{
2006 Name: group1.Name,
2007@@ -945,8 +930,8 @@
2008 }
2009
2010 func (s *NovaHTTPSuite) TestDeleteSecurityGroupRule(c *C) {
2011- group1 := nova.SecurityGroup{Id: 1, Name: "src"}
2012- group2 := nova.SecurityGroup{Id: 2, Name: "tgt"}
2013+ group1 := nova.SecurityGroup{Id: "1", Name: "src"}
2014+ group2 := nova.SecurityGroup{Id: "2", Name: "tgt"}
2015 err := s.service.addSecurityGroup(group1)
2016 c.Assert(err, IsNil)
2017 defer s.service.removeSecurityGroup(group1.Id)
2018@@ -958,7 +943,7 @@
2019 GroupId: &group1.Id,
2020 }
2021 rule := nova.SecurityGroupRule{
2022- Id: 1,
2023+ Id: "1",
2024 ParentGroupId: group2.Id,
2025 Group: nova.SecurityGroupRef{
2026 Name: group1.Name,
2027@@ -975,7 +960,7 @@
2028 }
2029
2030 func (s *NovaHTTPSuite) TestAddServerSecurityGroup(c *C) {
2031- group := nova.SecurityGroup{Id: 1, Name: "group"}
2032+ group := nova.SecurityGroup{Id: "1", Name: "group"}
2033 err := s.service.addSecurityGroup(group)
2034 c.Assert(err, IsNil)
2035 defer s.service.removeSecurityGroup(group.Id)
2036@@ -1004,13 +989,13 @@
2037 server := nova.ServerDetail{Id: "sr1"}
2038 groups := []nova.SecurityGroup{
2039 {
2040- Id: 1,
2041+ Id: "1",
2042 Name: "group1",
2043 TenantId: s.service.TenantId,
2044 Rules: []nova.SecurityGroupRule{},
2045 },
2046 {
2047- Id: 2,
2048+ Id: "2",
2049 Name: "group2",
2050 TenantId: s.service.TenantId,
2051 Rules: []nova.SecurityGroupRule{},
2052@@ -1040,7 +1025,7 @@
2053 }
2054
2055 func (s *NovaHTTPSuite) TestDeleteServerSecurityGroup(c *C) {
2056- group := nova.SecurityGroup{Id: 1, Name: "group"}
2057+ group := nova.SecurityGroup{Id: "1", Name: "group"}
2058 err := s.service.addSecurityGroup(group)
2059 c.Assert(err, IsNil)
2060 defer s.service.removeSecurityGroup(group.Id)
2061@@ -1066,7 +1051,7 @@
2062 }
2063
2064 func (s *NovaHTTPSuite) TestPostFloatingIP(c *C) {
2065- fip := nova.FloatingIP{Id: 1, IP: "10.0.0.1", Pool: "nova"}
2066+ fip := nova.FloatingIP{Id: "1", IP: "10.0.0.1", Pool: "nova"}
2067 c.Assert(s.service.allFloatingIPs(), HasLen, 0)
2068 var expected struct {
2069 IP nova.FloatingIP `json:"floating_ip"`
2070@@ -1091,8 +1076,8 @@
2071 assertJSON(c, resp, &expected)
2072 c.Assert(expected.IPs, HasLen, 0)
2073 fips := []nova.FloatingIP{
2074- {Id: 1, IP: "1.2.3.4", Pool: "nova"},
2075- {Id: 2, IP: "4.3.2.1", Pool: "nova"},
2076+ {Id: "1", IP: "1.2.3.4", Pool: "nova"},
2077+ {Id: "2", IP: "4.3.2.1", Pool: "nova"},
2078 }
2079 for _, fip := range fips {
2080 err := s.service.addFloatingIP(fip)
2081@@ -1118,7 +1103,7 @@
2082 }
2083
2084 func (s *NovaHTTPSuite) TestDeleteFloatingIP(c *C) {
2085- fip := nova.FloatingIP{Id: 1, IP: "10.0.0.1", Pool: "nova"}
2086+ fip := nova.FloatingIP{Id: "1", IP: "10.0.0.1", Pool: "nova"}
2087 err := s.service.addFloatingIP(fip)
2088 c.Assert(err, IsNil)
2089 defer s.service.removeFloatingIP(fip.Id)
2090@@ -1130,7 +1115,7 @@
2091 }
2092
2093 func (s *NovaHTTPSuite) TestAddServerFloatingIP(c *C) {
2094- fip := nova.FloatingIP{Id: 1, IP: "1.2.3.4"}
2095+ fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
2096 server := nova.ServerDetail{Id: "sr1"}
2097 err := s.service.addFloatingIP(fip)
2098 c.Assert(err, IsNil)
2099@@ -1154,7 +1139,7 @@
2100 }
2101
2102 func (s *NovaHTTPSuite) TestRemoveServerFloatingIP(c *C) {
2103- fip := nova.FloatingIP{Id: 1, IP: "1.2.3.4"}
2104+ fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
2105 server := nova.ServerDetail{Id: "sr1"}
2106 err := s.service.addFloatingIP(fip)
2107 c.Assert(err, IsNil)
2108
2109=== modified file 'testservices/novaservice/service_test.go'
2110--- testservices/novaservice/service_test.go 2013-04-23 00:19:57 +0000
2111+++ testservices/novaservice/service_test.go 2013-07-01 07:24:26 +0000
2112@@ -36,17 +36,17 @@
2113
2114 func (s *NovaSuite) ensureNoGroup(c *C, group nova.SecurityGroup) {
2115 _, err := s.service.securityGroup(group.Id)
2116- c.Assert(err, ErrorMatches, fmt.Sprintf("no such security group %d", group.Id))
2117+ c.Assert(err, ErrorMatches, fmt.Sprintf("no such security group %s", group.Id))
2118 }
2119
2120 func (s *NovaSuite) ensureNoRule(c *C, rule nova.SecurityGroupRule) {
2121 _, err := s.service.securityGroupRule(rule.Id)
2122- c.Assert(err, ErrorMatches, fmt.Sprintf("no such security group rule %d", rule.Id))
2123+ c.Assert(err, ErrorMatches, fmt.Sprintf("no such security group rule %s", rule.Id))
2124 }
2125
2126 func (s *NovaSuite) ensureNoIP(c *C, ip nova.FloatingIP) {
2127 _, err := s.service.floatingIP(ip.Id)
2128- c.Assert(err, ErrorMatches, fmt.Sprintf("no such floating IP %d", ip.Id))
2129+ c.Assert(err, ErrorMatches, fmt.Sprintf("no such floating IP %s", ip.Id))
2130 }
2131
2132 func (s *NovaSuite) createFlavor(c *C, flavor nova.FlavorDetail) {
2133@@ -520,19 +520,19 @@
2134 }
2135
2136 func (s *NovaSuite) TestAddRemoveSecurityGroup(c *C) {
2137- group := nova.SecurityGroup{Id: 1}
2138+ group := nova.SecurityGroup{Id: "1"}
2139 s.createGroup(c, group)
2140 s.deleteGroup(c, group)
2141 }
2142
2143 func (s *NovaSuite) TestAddSecurityGroupWithRules(c *C) {
2144 group := nova.SecurityGroup{
2145- Id: 1,
2146+ Id: "1",
2147 Name: "test",
2148 TenantId: s.service.TenantId,
2149 Rules: []nova.SecurityGroupRule{
2150- {Id: 10, ParentGroupId: 1},
2151- {Id: 20, ParentGroupId: 1},
2152+ {Id: "10", ParentGroupId: "1"},
2153+ {Id: "20", ParentGroupId: "1"},
2154 },
2155 }
2156 s.createGroup(c, group)
2157@@ -542,7 +542,7 @@
2158 }
2159
2160 func (s *NovaSuite) TestAddSecurityGroupTwiceFails(c *C) {
2161- group := nova.SecurityGroup{Id: 1, Name: "test"}
2162+ group := nova.SecurityGroup{Id: "1", Name: "test"}
2163 s.createGroup(c, group)
2164 defer s.deleteGroup(c, group)
2165 err := s.service.addSecurityGroup(group)
2166@@ -550,7 +550,7 @@
2167 }
2168
2169 func (s *NovaSuite) TestRemoveSecurityGroupTwiceFails(c *C) {
2170- group := nova.SecurityGroup{Id: 1, Name: "test"}
2171+ group := nova.SecurityGroup{Id: "1", Name: "test"}
2172 s.createGroup(c, group)
2173 s.deleteGroup(c, group)
2174 err := s.service.removeSecurityGroup(group.Id)
2175@@ -563,13 +563,13 @@
2176 c.Assert(groups, HasLen, 1)
2177 groups = []nova.SecurityGroup{
2178 {
2179- Id: 1,
2180+ Id: "1",
2181 Name: "one",
2182 TenantId: s.service.TenantId,
2183 Rules: []nova.SecurityGroupRule{},
2184 },
2185 {
2186- Id: 2,
2187+ Id: "2",
2188 Name: "two",
2189 TenantId: s.service.TenantId,
2190 Rules: []nova.SecurityGroupRule{},
2191@@ -586,7 +586,7 @@
2192
2193 func (s *NovaSuite) TestGetSecurityGroup(c *C) {
2194 group := nova.SecurityGroup{
2195- Id: 42,
2196+ Id: "42",
2197 TenantId: s.service.TenantId,
2198 Name: "group",
2199 Description: "desc",
2200@@ -600,7 +600,7 @@
2201
2202 func (s *NovaSuite) TestGetSecurityGroupByName(c *C) {
2203 group := nova.SecurityGroup{
2204- Id: 1,
2205+ Id: "1",
2206 Name: "test",
2207 TenantId: s.service.TenantId,
2208 Rules: []nova.SecurityGroupRule{},
2209@@ -616,9 +616,9 @@
2210 }
2211
2212 func (s *NovaSuite) TestAddHasRemoveSecurityGroupRule(c *C) {
2213- group := nova.SecurityGroup{Id: 1}
2214+ group := nova.SecurityGroup{Id: "1"}
2215 ri := nova.RuleInfo{ParentGroupId: group.Id}
2216- rule := nova.SecurityGroupRule{Id: 10, ParentGroupId: group.Id}
2217+ rule := nova.SecurityGroupRule{Id: "10", ParentGroupId: group.Id}
2218 s.ensureNoGroup(c, group)
2219 s.ensureNoRule(c, rule)
2220 ok := s.service.hasSecurityGroupRule(group.Id, rule.Id)
2221@@ -629,17 +629,17 @@
2222 ok = s.service.hasSecurityGroupRule(group.Id, rule.Id)
2223 c.Assert(ok, Equals, true)
2224 s.deleteGroup(c, group)
2225- ok = s.service.hasSecurityGroupRule(-1, rule.Id)
2226+ ok = s.service.hasSecurityGroupRule("-1", rule.Id)
2227 c.Assert(ok, Equals, true)
2228 ok = s.service.hasSecurityGroupRule(group.Id, rule.Id)
2229 c.Assert(ok, Equals, false)
2230 s.deleteRule(c, rule)
2231- ok = s.service.hasSecurityGroupRule(-1, rule.Id)
2232+ ok = s.service.hasSecurityGroupRule("-1", rule.Id)
2233 c.Assert(ok, Equals, false)
2234 }
2235
2236 func (s *NovaSuite) TestAddGetIngressSecurityGroupRule(c *C) {
2237- group := nova.SecurityGroup{Id: 1}
2238+ group := nova.SecurityGroup{Id: "1"}
2239 s.createGroup(c, group)
2240 defer s.deleteGroup(c, group)
2241 ri := nova.RuleInfo{
2242@@ -650,7 +650,7 @@
2243 ParentGroupId: group.Id,
2244 }
2245 rule := nova.SecurityGroupRule{
2246- Id: 10,
2247+ Id: "10",
2248 ParentGroupId: group.Id,
2249 FromPort: &ri.FromPort,
2250 ToPort: &ri.ToPort,
2251@@ -673,8 +673,8 @@
2252 }
2253
2254 func (s *NovaSuite) TestAddGetGroupSecurityGroupRule(c *C) {
2255- srcGroup := nova.SecurityGroup{Id: 1, Name: "source", TenantId: s.service.TenantId}
2256- tgtGroup := nova.SecurityGroup{Id: 2, Name: "target"}
2257+ srcGroup := nova.SecurityGroup{Id: "1", Name: "source", TenantId: s.service.TenantId}
2258+ tgtGroup := nova.SecurityGroup{Id: "2", Name: "target"}
2259 s.createGroup(c, srcGroup)
2260 defer s.deleteGroup(c, srcGroup)
2261 s.createGroup(c, tgtGroup)
2262@@ -687,7 +687,7 @@
2263 ParentGroupId: tgtGroup.Id,
2264 }
2265 rule := nova.SecurityGroupRule{
2266- Id: 10,
2267+ Id: "10",
2268 ParentGroupId: tgtGroup.Id,
2269 FromPort: &ri.FromPort,
2270 ToPort: &ri.ToPort,
2271@@ -712,11 +712,11 @@
2272 }
2273
2274 func (s *NovaSuite) TestAddSecurityGroupRuleTwiceFails(c *C) {
2275- group := nova.SecurityGroup{Id: 1}
2276+ group := nova.SecurityGroup{Id: "1"}
2277 s.createGroup(c, group)
2278 defer s.deleteGroup(c, group)
2279 ri := nova.RuleInfo{ParentGroupId: group.Id}
2280- rule := nova.SecurityGroupRule{Id: 10}
2281+ rule := nova.SecurityGroupRule{Id: "10"}
2282 s.ensureNoRule(c, rule)
2283 err := s.service.addSecurityGroupRule(rule.Id, ri)
2284 c.Assert(err, IsNil)
2285@@ -727,39 +727,39 @@
2286
2287 func (s *NovaSuite) TestAddSecurityGroupRuleToParentTwiceFails(c *C) {
2288 group := nova.SecurityGroup{
2289- Id: 1,
2290+ Id: "1",
2291 Rules: []nova.SecurityGroupRule{
2292- {Id: 10},
2293+ {Id: "10"},
2294 },
2295 }
2296 s.createGroup(c, group)
2297 defer s.deleteGroup(c, group)
2298 ri := nova.RuleInfo{ParentGroupId: group.Id}
2299- rule := nova.SecurityGroupRule{Id: 10}
2300+ rule := nova.SecurityGroupRule{Id: "10"}
2301 err := s.service.addSecurityGroupRule(rule.Id, ri)
2302 c.Assert(err, ErrorMatches, "cannot add twice rule 10 to security group 1")
2303 }
2304
2305 func (s *NovaSuite) TestAddSecurityGroupRuleWithInvalidParentFails(c *C) {
2306- invalidGroup := nova.SecurityGroup{Id: 1}
2307+ invalidGroup := nova.SecurityGroup{Id: "1"}
2308 s.ensureNoGroup(c, invalidGroup)
2309 ri := nova.RuleInfo{ParentGroupId: invalidGroup.Id}
2310- rule := nova.SecurityGroupRule{Id: 10}
2311+ rule := nova.SecurityGroupRule{Id: "10"}
2312 s.ensureNoRule(c, rule)
2313 err := s.service.addSecurityGroupRule(rule.Id, ri)
2314 c.Assert(err, ErrorMatches, "no such security group 1")
2315 }
2316
2317 func (s *NovaSuite) TestAddGroupSecurityGroupRuleWithInvalidSourceFails(c *C) {
2318- group := nova.SecurityGroup{Id: 1}
2319+ group := nova.SecurityGroup{Id: "1"}
2320 s.createGroup(c, group)
2321 defer s.deleteGroup(c, group)
2322- invalidGroupId := 42
2323+ invalidGroupId := "42"
2324 ri := nova.RuleInfo{
2325 ParentGroupId: group.Id,
2326 GroupId: &invalidGroupId,
2327 }
2328- rule := nova.SecurityGroupRule{Id: 10}
2329+ rule := nova.SecurityGroupRule{Id: "10"}
2330 s.ensureNoRule(c, rule)
2331 err := s.service.addSecurityGroupRule(rule.Id, ri)
2332 c.Assert(err, ErrorMatches, "unknown source security group 42")
2333@@ -767,7 +767,7 @@
2334
2335 func (s *NovaSuite) TestAddSecurityGroupRuleUpdatesParent(c *C) {
2336 group := nova.SecurityGroup{
2337- Id: 1,
2338+ Id: "1",
2339 Name: "test",
2340 TenantId: s.service.TenantId,
2341 }
2342@@ -775,7 +775,7 @@
2343 defer s.deleteGroup(c, group)
2344 ri := nova.RuleInfo{ParentGroupId: group.Id}
2345 rule := nova.SecurityGroupRule{
2346- Id: 10,
2347+ Id: "10",
2348 ParentGroupId: group.Id,
2349 Group: nova.SecurityGroupRef{},
2350 }
2351@@ -791,7 +791,7 @@
2352
2353 func (s *NovaSuite) TestAddSecurityGroupRuleKeepsNegativePort(c *C) {
2354 group := nova.SecurityGroup{
2355- Id: 1,
2356+ Id: "1",
2357 Name: "test",
2358 TenantId: s.service.TenantId,
2359 }
2360@@ -805,7 +805,7 @@
2361 ParentGroupId: group.Id,
2362 }
2363 rule := nova.SecurityGroupRule{
2364- Id: 10,
2365+ Id: "10",
2366 ParentGroupId: group.Id,
2367 FromPort: &ri.FromPort,
2368 ToPort: &ri.ToPort,
2369@@ -822,11 +822,11 @@
2370 }
2371
2372 func (s *NovaSuite) TestRemoveSecurityGroupRuleTwiceFails(c *C) {
2373- group := nova.SecurityGroup{Id: 1}
2374+ group := nova.SecurityGroup{Id: "1"}
2375 s.createGroup(c, group)
2376 defer s.deleteGroup(c, group)
2377 ri := nova.RuleInfo{ParentGroupId: group.Id}
2378- rule := nova.SecurityGroupRule{Id: 10}
2379+ rule := nova.SecurityGroupRule{Id: "10"}
2380 s.ensureNoRule(c, rule)
2381 err := s.service.addSecurityGroupRule(rule.Id, ri)
2382 c.Assert(err, IsNil)
2383@@ -837,7 +837,7 @@
2384
2385 func (s *NovaSuite) TestAddHasRemoveServerSecurityGroup(c *C) {
2386 server := nova.ServerDetail{Id: "sr1"}
2387- group := nova.SecurityGroup{Id: 1}
2388+ group := nova.SecurityGroup{Id: "1"}
2389 s.ensureNoServer(c, server)
2390 s.ensureNoGroup(c, group)
2391 ok := s.service.hasServerSecurityGroup(server.Id, group.Id)
2392@@ -862,7 +862,7 @@
2393
2394 func (s *NovaSuite) TestAddServerSecurityGroupWithInvalidServerFails(c *C) {
2395 server := nova.ServerDetail{Id: "sr1"}
2396- group := nova.SecurityGroup{Id: 1}
2397+ group := nova.SecurityGroup{Id: "1"}
2398 s.ensureNoServer(c, server)
2399 s.createGroup(c, group)
2400 defer s.deleteGroup(c, group)
2401@@ -871,7 +871,7 @@
2402 }
2403
2404 func (s *NovaSuite) TestAddServerSecurityGroupWithInvalidGroupFails(c *C) {
2405- group := nova.SecurityGroup{Id: 1}
2406+ group := nova.SecurityGroup{Id: "1"}
2407 server := nova.ServerDetail{Id: "sr1"}
2408 s.ensureNoGroup(c, group)
2409 s.createServer(c, server)
2410@@ -882,7 +882,7 @@
2411
2412 func (s *NovaSuite) TestAddServerSecurityGroupTwiceFails(c *C) {
2413 server := nova.ServerDetail{Id: "sr1"}
2414- group := nova.SecurityGroup{Id: 1}
2415+ group := nova.SecurityGroup{Id: "1"}
2416 s.createServer(c, server)
2417 defer s.deleteServer(c, server)
2418 s.createGroup(c, group)
2419@@ -903,13 +903,13 @@
2420 defer s.deleteServer(c, server)
2421 groups := []nova.SecurityGroup{
2422 {
2423- Id: 1,
2424+ Id: "1",
2425 Name: "gr1",
2426 TenantId: s.service.TenantId,
2427 Rules: []nova.SecurityGroupRule{},
2428 },
2429 {
2430- Id: 2,
2431+ Id: "2",
2432 Name: "gr2",
2433 TenantId: s.service.TenantId,
2434 Rules: []nova.SecurityGroupRule{},
2435@@ -932,7 +932,7 @@
2436
2437 func (s *NovaSuite) TestRemoveServerSecurityGroupWithInvalidServerFails(c *C) {
2438 server := nova.ServerDetail{Id: "sr1"}
2439- group := nova.SecurityGroup{Id: 1}
2440+ group := nova.SecurityGroup{Id: "1"}
2441 s.createServer(c, server)
2442 s.createGroup(c, group)
2443 defer s.deleteGroup(c, group)
2444@@ -948,7 +948,7 @@
2445 }
2446
2447 func (s *NovaSuite) TestRemoveServerSecurityGroupWithInvalidGroupFails(c *C) {
2448- group := nova.SecurityGroup{Id: 1}
2449+ group := nova.SecurityGroup{Id: "1"}
2450 server := nova.ServerDetail{Id: "sr1"}
2451 s.createGroup(c, group)
2452 s.createServer(c, server)
2453@@ -966,7 +966,7 @@
2454
2455 func (s *NovaSuite) TestRemoveServerSecurityGroupTwiceFails(c *C) {
2456 server := nova.ServerDetail{Id: "sr1"}
2457- group := nova.SecurityGroup{Id: 1}
2458+ group := nova.SecurityGroup{Id: "1"}
2459 s.createServer(c, server)
2460 defer s.deleteServer(c, server)
2461 s.createGroup(c, group)
2462@@ -980,7 +980,7 @@
2463 }
2464
2465 func (s *NovaSuite) TestAddHasRemoveFloatingIP(c *C) {
2466- ip := nova.FloatingIP{Id: 1, IP: "1.2.3.4"}
2467+ ip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
2468 s.ensureNoIP(c, ip)
2469 ok := s.service.hasFloatingIP(ip.IP)
2470 c.Assert(ok, Equals, false)
2471@@ -995,7 +995,7 @@
2472 }
2473
2474 func (s *NovaSuite) TestAddFloatingIPTwiceFails(c *C) {
2475- ip := nova.FloatingIP{Id: 1}
2476+ ip := nova.FloatingIP{Id: "1"}
2477 s.createIP(c, ip)
2478 defer s.deleteIP(c, ip)
2479 err := s.service.addFloatingIP(ip)
2480@@ -1003,7 +1003,7 @@
2481 }
2482
2483 func (s *NovaSuite) TestRemoveFloatingIPTwiceFails(c *C) {
2484- ip := nova.FloatingIP{Id: 1}
2485+ ip := nova.FloatingIP{Id: "1"}
2486 s.createIP(c, ip)
2487 s.deleteIP(c, ip)
2488 err := s.service.removeFloatingIP(ip.Id)
2489@@ -1014,8 +1014,8 @@
2490 fips := s.service.allFloatingIPs()
2491 c.Assert(fips, HasLen, 0)
2492 fips = []nova.FloatingIP{
2493- {Id: 1},
2494- {Id: 2},
2495+ {Id: "1"},
2496+ {Id: "2"},
2497 }
2498 s.createIP(c, fips[0])
2499 defer s.deleteIP(c, fips[0])
2500@@ -1033,7 +1033,7 @@
2501 inst := "sr1"
2502 fixedIP := "4.3.2.1"
2503 fip := nova.FloatingIP{
2504- Id: 1,
2505+ Id: "1",
2506 IP: "1.2.3.4",
2507 Pool: "pool",
2508 InstanceId: &inst,
2509@@ -1046,7 +1046,7 @@
2510 }
2511
2512 func (s *NovaSuite) TestGetFloatingIPByAddr(c *C) {
2513- fip := nova.FloatingIP{Id: 1, IP: "1.2.3.4"}
2514+ fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
2515 s.ensureNoIP(c, fip)
2516 ip, err := s.service.floatingIPByAddr(fip.IP)
2517 c.Assert(err, NotNil)
2518@@ -1061,7 +1061,7 @@
2519
2520 func (s *NovaSuite) TestAddHasRemoveServerFloatingIP(c *C) {
2521 server := nova.ServerDetail{Id: "sr1"}
2522- fip := nova.FloatingIP{Id: 1, IP: "1.2.3.4"}
2523+ fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
2524 s.ensureNoServer(c, server)
2525 s.ensureNoIP(c, fip)
2526 ok := s.service.hasServerFloatingIP(server.Id, fip.IP)
2527@@ -1086,7 +1086,7 @@
2528
2529 func (s *NovaSuite) TestAddServerFloatingIPWithInvalidServerFails(c *C) {
2530 server := nova.ServerDetail{Id: "sr1"}
2531- fip := nova.FloatingIP{Id: 1}
2532+ fip := nova.FloatingIP{Id: "1"}
2533 s.ensureNoServer(c, server)
2534 s.createIP(c, fip)
2535 defer s.deleteIP(c, fip)
2536@@ -1095,7 +1095,7 @@
2537 }
2538
2539 func (s *NovaSuite) TestAddServerFloatingIPWithInvalidIPFails(c *C) {
2540- fip := nova.FloatingIP{Id: 1}
2541+ fip := nova.FloatingIP{Id: "1"}
2542 server := nova.ServerDetail{Id: "sr1"}
2543 s.ensureNoIP(c, fip)
2544 s.createServer(c, server)
2545@@ -1106,7 +1106,7 @@
2546
2547 func (s *NovaSuite) TestAddServerFloatingIPTwiceFails(c *C) {
2548 server := nova.ServerDetail{Id: "sr1"}
2549- fip := nova.FloatingIP{Id: 1}
2550+ fip := nova.FloatingIP{Id: "1"}
2551 s.createServer(c, server)
2552 defer s.deleteServer(c, server)
2553 s.createIP(c, fip)
2554@@ -1121,7 +1121,7 @@
2555
2556 func (s *NovaSuite) TestRemoveServerFloatingIPWithInvalidServerFails(c *C) {
2557 server := nova.ServerDetail{Id: "sr1"}
2558- fip := nova.FloatingIP{Id: 1}
2559+ fip := nova.FloatingIP{Id: "1"}
2560 s.createServer(c, server)
2561 s.createIP(c, fip)
2562 defer s.deleteIP(c, fip)
2563@@ -1137,7 +1137,7 @@
2564 }
2565
2566 func (s *NovaSuite) TestRemoveServerFloatingIPWithInvalidIPFails(c *C) {
2567- fip := nova.FloatingIP{Id: 1}
2568+ fip := nova.FloatingIP{Id: "1"}
2569 server := nova.ServerDetail{Id: "sr1"}
2570 s.createIP(c, fip)
2571 s.createServer(c, server)
2572@@ -1155,7 +1155,7 @@
2573
2574 func (s *NovaSuite) TestRemoveServerFloatingIPTwiceFails(c *C) {
2575 server := nova.ServerDetail{Id: "sr1"}
2576- fip := nova.FloatingIP{Id: 1}
2577+ fip := nova.FloatingIP{Id: "1"}
2578 s.createServer(c, server)
2579 defer s.deleteServer(c, server)
2580 s.createIP(c, fip)
2581
2582=== modified file 'testservices/openstackservice/openstack.go'
2583--- testservices/openstackservice/openstack.go 2013-02-08 02:23:27 +0000
2584+++ testservices/openstackservice/openstack.go 2013-07-01 07:24:26 +0000
2585@@ -1,6 +1,7 @@
2586 package openstackservice
2587
2588 import (
2589+ "fmt"
2590 "launchpad.net/goose/identity"
2591 "launchpad.net/goose/testservices/identityservice"
2592 "launchpad.net/goose/testservices/novaservice"
2593@@ -18,9 +19,16 @@
2594
2595 // New creates an instance of a full Openstack service double.
2596 // An initial user with the specified credentials is registered with the identity service.
2597-func New(cred *identity.Credentials) *Openstack {
2598- openstack := Openstack{
2599- Identity: identityservice.NewUserPass(),
2600+func New(cred *identity.Credentials, authMode identity.AuthMode) *Openstack {
2601+ var openstack Openstack
2602+ if authMode == identity.AuthKeyPair {
2603+ openstack = Openstack{
2604+ Identity: identityservice.NewKeyPair(),
2605+ }
2606+ } else {
2607+ openstack = Openstack{
2608+ Identity: identityservice.NewUserPass(),
2609+ }
2610 }
2611 userInfo := openstack.Identity.AddUser(cred.User, cred.Secrets, cred.TenantName)
2612 if cred.TenantName == "" {
2613@@ -31,6 +39,22 @@
2614 regionParts := strings.Split(cred.Region, ".")
2615 baseRegion := regionParts[len(regionParts)-1]
2616 openstack.Swift = swiftservice.New(cred.URL, "v1", userInfo.TenantId, baseRegion, openstack.Identity)
2617+ // Create container and add image metadata endpoint so that product-streams URLs are included
2618+ // in the keystone catalog.
2619+ err := openstack.Swift.AddContainer("imagemetadata")
2620+ if err != nil {
2621+ panic(fmt.Errorf("setting up image metadata container: %v", err))
2622+ }
2623+ url := openstack.Swift.Endpoints()[0].PublicURL
2624+ serviceDef := identityservice.Service{"simplestreams", "product-streams", []identityservice.Endpoint{
2625+ identityservice.Endpoint{PublicURL: url + "/imagemetadata", Region: cred.Region},
2626+ }}
2627+ openstack.Identity.AddService(serviceDef)
2628+ // Add public bucket endpoint so that juju-tools URLs are included in the keystone catalog.
2629+ serviceDef = identityservice.Service{"juju", "juju-tools", []identityservice.Endpoint{
2630+ identityservice.Endpoint{PublicURL: url, Region: cred.Region},
2631+ }}
2632+ openstack.Identity.AddService(serviceDef)
2633 return &openstack
2634 }
2635
2636
2637=== modified file 'tools/secgroup-delete-all/main_test.go'
2638--- tools/secgroup-delete-all/main_test.go 2013-02-20 06:00:49 +0000
2639+++ tools/secgroup-delete-all/main_test.go 2013-07-01 07:24:26 +0000
2640@@ -46,7 +46,7 @@
2641 Region: region,
2642 TenantName: tenant,
2643 }
2644- openstack := openstackservice.New(creds)
2645+ openstack := openstackservice.New(creds, identity.AuthUserPass)
2646 openstack.SetupHTTP(s.Mux)
2647 return openstack, createNovaClient(creds)
2648 }
2649@@ -74,7 +74,7 @@
2650
2651 // deleteGroupError hook raises an error if a group with id 2 is deleted.
2652 func deleteGroupError(s hook.ServiceControl, args ...interface{}) error {
2653- groupId := args[0].(int)
2654+ groupId := args[0].(string)
2655 if groupId == doNotDelete.Id {
2656 return fmt.Errorf("cannot delete group %d", groupId)
2657 }
2658
2659=== modified file 'version.go'
2660--- version.go 2013-02-05 13:22:51 +0000
2661+++ version.go 2013-07-01 07:24:26 +0000
2662@@ -1,3 +1,6 @@
2663+// Copyright 2013 Canonical Ltd.
2664+// Licensed under the LGPLv3, see COPYING and COPYING.LESSER file for details.
2665+
2666 package goose
2667
2668 import (
2669
2670=== modified file 'version_test.go'
2671--- version_test.go 2013-02-05 13:37:45 +0000
2672+++ version_test.go 2013-07-01 07:24:26 +0000
2673@@ -1,3 +1,6 @@
2674+// Copyright 2013 Canonical Ltd.
2675+// Licensed under the LGPLv3, see COPYING and COPYING.LESSER file for details.
2676+
2677 package goose
2678
2679 import (

Subscribers

People subscribed via source and target branches