Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Stub provider for OpenStack, using goose will be implemented here | 1 // Stub provider for OpenStack, using goose will be implemented here |
2 | 2 |
3 package openstack | 3 package openstack |
4 | 4 |
5 import ( | 5 import ( |
6 "fmt" | |
7 "io/ioutil" | |
6 "launchpad.net/juju-core/environs" | 8 "launchpad.net/juju-core/environs" |
7 "launchpad.net/juju-core/environs/config" | 9 "launchpad.net/juju-core/environs/config" |
8 "launchpad.net/juju-core/log" | 10 "launchpad.net/juju-core/log" |
9 "launchpad.net/juju-core/state" | 11 "launchpad.net/juju-core/state" |
12 "launchpad.net/juju-core/trivial" | |
13 "net/http" | |
14 "strings" | |
10 "sync" | 15 "sync" |
16 "time" | |
11 ) | 17 ) |
12 | 18 |
13 type environProvider struct{} | 19 type environProvider struct{} |
14 | 20 |
15 var _ environs.EnvironProvider = (*environProvider)(nil) | 21 var _ environs.EnvironProvider = (*environProvider)(nil) |
16 | 22 |
17 var providerInstance environProvider | 23 var providerInstance environProvider |
18 | 24 |
25 // A request may fail to due "eventual consistency" semantics, which | |
26 // should resolve fairly quickly. A request may also fail due to a slow | |
27 // state transition (for instance an instance taking a while to release | |
28 // a security group after termination). The former failure mode is | |
29 // dealt with by shortAttempt, the latter by longAttempt. | |
30 var shortAttempt = trivial.AttemptStrategy{ | |
rog
2012/11/22 15:11:48
does openstack have the same eventual-consistency
| |
31 Total: 5 * time.Second, | |
32 Delay: 200 * time.Millisecond, | |
33 } | |
34 | |
35 var longAttempt = trivial.AttemptStrategy{ | |
36 Total: 3 * time.Minute, | |
37 Delay: 1 * time.Second, | |
38 } | |
39 | |
19 func init() { | 40 func init() { |
20 environs.RegisterProvider("openstack", environProvider{}) | 41 environs.RegisterProvider("openstack", environProvider{}) |
21 } | 42 } |
22 | 43 |
23 func (p environProvider) Open(cfg *config.Config) (environs.Environ, error) { | 44 func (p environProvider) Open(cfg *config.Config) (environs.Environ, error) { |
24 log.Printf("environs/openstack: opening environment %q", cfg.Name()) | 45 log.Printf("environs/openstack: opening environment %q", cfg.Name()) |
25 e := new(environ) | 46 e := new(environ) |
26 err := e.SetConfig(cfg) | 47 err := e.SetConfig(cfg) |
27 if err != nil { | 48 if err != nil { |
28 return nil, err | 49 return nil, err |
29 } | 50 } |
30 return e, nil | 51 return e, nil |
31 } | 52 } |
32 | 53 |
33 func (p environProvider) SecretAttrs(cfg *config.Config) (map[string]interface{} , error) { | 54 func (p environProvider) SecretAttrs(cfg *config.Config) (map[string]interface{} , error) { |
34 m := make(map[string]interface{}) | 55 m := make(map[string]interface{}) |
35 ecfg, err := providerInstance.newConfig(cfg) | 56 ecfg, err := providerInstance.newConfig(cfg) |
36 if err != nil { | 57 if err != nil { |
37 return nil, err | 58 return nil, err |
38 } | 59 } |
39 m["username"] = ecfg.username() | 60 m["username"] = ecfg.username() |
40 m["password"] = ecfg.password() | 61 m["password"] = ecfg.password() |
41 m["tenant-name"] = ecfg.tenantName() | 62 m["tenant-name"] = ecfg.tenantName() |
42 return m, nil | 63 return m, nil |
43 } | 64 } |
44 | 65 |
45 func (p environProvider) PublicAddress() (string, error) { | 66 func (p environProvider) PublicAddress() (string, error) { |
46 » panic("not implemented") | 67 » return fetchMetadata("public-hostname") |
47 } | 68 } |
48 | 69 |
49 func (p environProvider) PrivateAddress() (string, error) { | 70 func (p environProvider) PrivateAddress() (string, error) { |
50 » panic("not implemented") | 71 » return fetchMetadata("local-hostname") |
51 } | 72 } |
52 | 73 |
53 type environ struct { | 74 type environ struct { |
54 name string | 75 name string |
55 | 76 |
56 ecfgMutex sync.Mutex | 77 ecfgMutex sync.Mutex |
57 ecfgUnlocked *environConfig | 78 ecfgUnlocked *environConfig |
58 } | 79 } |
59 | 80 |
60 var _ environs.Environ = (*environ)(nil) | 81 var _ environs.Environ = (*environ)(nil) |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 panic("not implemented") | 157 panic("not implemented") |
137 } | 158 } |
138 | 159 |
139 func (e *environ) Ports() ([]state.Port, error) { | 160 func (e *environ) Ports() ([]state.Port, error) { |
140 panic("not implemented") | 161 panic("not implemented") |
141 } | 162 } |
142 | 163 |
143 func (e *environ) Provider() environs.EnvironProvider { | 164 func (e *environ) Provider() environs.EnvironProvider { |
144 return &providerInstance | 165 return &providerInstance |
145 } | 166 } |
167 | |
168 // metadataHost holds the address of the instance metadata service. | |
169 // It is a variable so that tests can change it to refer to a local | |
170 // server when needed. | |
171 var metadataHost = "http://169.254.169.254" | |
172 | |
173 // fetchMetadata fetches a single atom of data from the openstack instance metad ata service. | |
174 // http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/AESDG-chapter-insta ncedata.html | |
TheMue
2012/11/22 14:31:57
Here again a reference to EC2. But maybe only I do
| |
175 func fetchMetadata(name string) (value string, err error) { | |
176 uri := fmt.Sprintf("%s/2011-01-01/meta-data/%s", metadataHost, name) | |
177 defer trivial.ErrorContextf(&err, "cannot get %q", uri) | |
178 for a := shortAttempt.Start(); a.Next(); { | |
179 var resp *http.Response | |
180 resp, err = http.Get(uri) | |
181 if err != nil { | |
182 continue | |
183 } | |
184 defer resp.Body.Close() | |
185 if resp.StatusCode != http.StatusOK { | |
186 err = fmt.Errorf("bad http response %v", resp.Status) | |
187 continue | |
188 } | |
189 var data []byte | |
190 data, err = ioutil.ReadAll(resp.Body) | |
191 if err != nil { | |
192 continue | |
193 } | |
194 return strings.TrimSpace(string(data)), nil | |
195 } | |
196 return | |
197 } | |
OLD | NEW |