Merge lp:~thumper/juju-core/provisioner-reget-state-info into lp:~juju/juju-core/trunk
- provisioner-reget-state-info
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~thumper/juju-core/provisioner-reget-state-info |
Merge into: | lp:~juju/juju-core/trunk |
Diff against target: |
2421 lines (+589/-351) 33 files modified
.lbox.check (+1/-1) cmd/juju/plugin_test.go (+3/-2) cmd/juju/status.go (+88/-45) cmd/juju/status_test.go (+97/-0) environs/azure/environ.go (+6/-5) environs/azure/instance.go (+2/-2) environs/dummy/environs.go (+20/-19) environs/ec2/ec2.go (+29/-28) environs/ec2/export_test.go (+6/-5) environs/ec2/live_test.go (+7/-6) environs/interface.go (+6/-35) environs/jujutest/livetests.go (+9/-8) environs/jujutest/tests.go (+2/-1) environs/maas/environ.go (+12/-11) environs/maas/environ_test.go (+5/-4) environs/maas/instance.go (+2/-2) environs/openstack/local_test.go (+3/-2) environs/openstack/provider.go (+29/-28) environs/openstack/provider_test.go (+4/-4) instance/instance.go (+41/-0) juju/testing/conn.go (+2/-1) state/container.go (+15/-3) state/export_test.go (+4/-0) state/machine.go (+13/-2) state/machine_test.go (+9/-0) state/state.go (+43/-4) state/state_test.go (+64/-0) worker/firewaller/firewaller_test.go (+3/-3) worker/provisioner/broker.go (+4/-4) worker/provisioner/export_test.go (+2/-2) worker/provisioner/provisioner.go (+11/-15) worker/provisioner/provisioner_task.go (+43/-32) worker/provisioner/provisioner_test.go (+4/-77) |
To merge this branch: | bzr merge lp:~thumper/juju-core/provisioner-reget-state-info |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+168562@code.launchpad.net |
This proposal has been superseded by a proposal from 2013-06-17.
Commit message
Description of the change
Provisioner gets addresses for each new machine.
The addresses are retrieved each time we attempt to start a machine. This
allows the provisioner to take advantage of any new api or state servers that
are started as part of a block of machines being provisioned at one time.
There is some saving of addresses at this stage to make the existing tests
pass, even though this goes a little against what William has mentioned
before. If we have invalid config, the tests assume that we continue with old
info, whereas William has suggested that we pause provisioning while the
config is broken.
One behavioural tweak in this branch. If we do fail to setup authentication,
we no longer kill the task, but instead log and continue. We will attempt to
start it again next time through the loop.
Tim Penhey (thumper) wrote : | # |
William Reade (fwereade) wrote : | # |
Strongly -1 on the clever bits here. Just barf on failure and I'll be
happy :).
https:/
File worker/
https:/
worker/
error, just try again next time.
This is problematic, because the watcher won't report that machine again
until it changes -- which it won't. For this to work, we need the
provisioner to be restarted regularly... but I'm hoping for a
provisioner that can run for weeks without breaking sweat.
https:/
worker/
invalid.
Honestly, I think this is sufficient justification to nuke the whole
provisioner; it'll be restarted in a few seconds, and for now I'd rather
not even try to provision a machine (which can be expected to cost our
users actual money) unless I'm as sure as I can be that I'll be able to
start a functioning machine agent...
William Reade (fwereade) wrote : | # |
Re what we do without a valid environment... hmm. Thinking aloud:
* we certainly start off with an invalid environ config, and only get a
valid one once whoever started the environment has connected for the
first time.
* today, on first startup, there will be one machine present; but it'll
be marked as provisioned already, so it won't cause env access directly;
and if we're tolerant of list-instances failures, we'll be able to
complete the first processMachines without difficulty. But I don't think
we can necessarily depend on that forever...
* in theory, it is impossible to set an invalid environ config in state,
except via the special mechanism at bootstrap time.
* in practice, an environ config can most certainly become invalid --
you can (1) replace the config with *any* valid config, which might ofc
be invalid in this context (changed environ type, for example, will
screw us most comprehensively) and (2) config update is racy anyway,
such that two users making valid changes concurrently can end up with an
environment config that reflects neither of their desires... and I bet
there's a way for that to cause invalidity. (oh, and, on inspection,
(3): it looks like values can't be dependably unset anyway. we probably
need that too. grar.)
* BUT the consequences of an invalid environ affect many more things
than just the provisioner.
* AND SO it would be folly to spend time and effort hardening the
provisioner against catastrophic environ failure when we could be fixing
the root cause.
* AND THUS you should (1) wait for a valid config at startup before
processing machines and (2) proceed otherwise as though the environment
configuration were always guaranteed consistent and valid from a juju
perspective and (3) use the time thereby saved to fix SetEnvironConfig.
* BUT ALSO remember that a valid *environ config* does not necessarily
contain valid *provider credentials*. So issues can always arise at
runtime anyway, and should I think be dealt with as follows:
* StartInstance: record on machine via SetInstanceError.
* AllInstances: log and ignore -- I don't think there are negative
consequences (out-of-date
instance list is always possible anyway).
* StopInstances: log and ignore, they'll be tried again next time we
processMachines. (We should
add a periodic processMachines call so that we do at least handle
them in something resembling
a timely fashion. Not too hard, I think?)
Tim Penhey (thumper) wrote : | # |
Please take a look.
https:/
File worker/
https:/
worker/
error, just try again next time.
On 2013/06/11 09:08:21, fwereade wrote:
> This is problematic, because the watcher won't report that machine
again until
> it changes -- which it won't. For this to work, we need the
provisioner to be
> restarted regularly... but I'm hoping for a provisioner that can run
for weeks
> without breaking sweat.
OK, reverted.
https:/
worker/
invalid.
On 2013/06/11 09:08:21, fwereade wrote:
> Honestly, I think this is sufficient justification to nuke the whole
> provisioner; it'll be restarted in a few seconds, and for now I'd
rather not
> even try to provision a machine (which can be expected to cost our
users actual
> money) unless I'm as sure as I can be that I'll be able to start a
functioning
> machine agent...
OK, nuking in progress.
William Reade (fwereade) wrote : | # |
Ian Booth (wallyworld) wrote : | # |
Preview Diff
1 | === modified file '.lbox.check' |
2 | --- .lbox.check 2013-04-08 13:46:30 +0000 |
3 | +++ .lbox.check 2013-06-17 04:13:30 +0000 |
4 | @@ -2,7 +2,7 @@ |
5 | |
6 | set -e |
7 | |
8 | -BADFMT=`find * -name '*.go' | xargs gofmt -l` |
9 | +BADFMT=`find * -name '*.go' -not -name '.#*' | xargs gofmt -l` |
10 | if [ -n "$BADFMT" ]; then |
11 | BADFMT=`echo "$BADFMT" | sed "s/^/ /"` |
12 | echo -e "gofmt is sad:\n\n$BADFMT" |
13 | |
14 | === modified file 'cmd/juju/plugin_test.go' |
15 | --- cmd/juju/plugin_test.go 2013-06-13 10:56:08 +0000 |
16 | +++ cmd/juju/plugin_test.go 2013-06-17 04:13:30 +0000 |
17 | @@ -17,6 +17,7 @@ |
18 | ) |
19 | |
20 | type PluginSuite struct { |
21 | + testing.LoggingSuite |
22 | oldPath string |
23 | home *testing.FakeHome |
24 | } |
25 | @@ -24,6 +25,7 @@ |
26 | var _ = Suite(&PluginSuite{}) |
27 | |
28 | func (suite *PluginSuite) SetUpTest(c *C) { |
29 | + suite.LoggingSuite.SetUpTest(c) |
30 | suite.oldPath = os.Getenv("PATH") |
31 | suite.home = testing.MakeSampleHome(c) |
32 | os.Setenv("PATH", "/bin:"+testing.HomePath()) |
33 | @@ -32,6 +34,7 @@ |
34 | func (suite *PluginSuite) TearDownTest(c *C) { |
35 | suite.home.Restore() |
36 | os.Setenv("PATH", suite.oldPath) |
37 | + suite.LoggingSuite.TearDownTest(c) |
38 | } |
39 | |
40 | func (*PluginSuite) TestFindPlugins(c *C) { |
41 | @@ -195,8 +198,6 @@ |
42 | fi |
43 | echo "{{.Name}} description" |
44 | exit {{.ExitStatus}} |
45 | -else |
46 | - echo "No --description" >2 |
47 | fi |
48 | |
49 | if [ "$1" = "--help" ]; then |
50 | |
51 | === modified file 'cmd/juju/status.go' |
52 | --- cmd/juju/status.go 2013-06-04 11:50:12 +0000 |
53 | +++ cmd/juju/status.go 2013-06-17 04:13:30 +0000 |
54 | @@ -10,6 +10,7 @@ |
55 | "launchpad.net/juju-core/charm" |
56 | "launchpad.net/juju-core/cmd" |
57 | "launchpad.net/juju-core/environs" |
58 | + "launchpad.net/juju-core/instance" |
59 | "launchpad.net/juju-core/juju" |
60 | "launchpad.net/juju-core/state" |
61 | "launchpad.net/juju-core/state/api/params" |
62 | @@ -42,8 +43,8 @@ |
63 | } |
64 | |
65 | type statusContext struct { |
66 | - instances map[state.InstanceId]environs.Instance |
67 | - machines map[string]*state.Machine |
68 | + instances map[state.InstanceId]instance.Instance |
69 | + machines map[string][]*state.Machine |
70 | services map[string]*state.Service |
71 | units map[string]map[string]*state.Unit |
72 | } |
73 | @@ -55,14 +56,14 @@ |
74 | } |
75 | defer conn.Close() |
76 | |
77 | - var ctxt statusContext |
78 | - if ctxt.machines, err = fetchAllMachines(conn.State); err != nil { |
79 | - return err |
80 | - } |
81 | - if ctxt.services, ctxt.units, err = fetchAllServicesAndUnits(conn.State); err != nil { |
82 | - return err |
83 | - } |
84 | - ctxt.instances, err = fetchAllInstances(conn.Environ) |
85 | + var context statusContext |
86 | + if context.machines, err = fetchAllMachines(conn.State); err != nil { |
87 | + return err |
88 | + } |
89 | + if context.services, context.units, err = fetchAllServicesAndUnits(conn.State); err != nil { |
90 | + return err |
91 | + } |
92 | + context.instances, err = fetchAllInstances(conn.Environ) |
93 | if err != nil { |
94 | // We cannot see instances from the environment, but |
95 | // there's still lots of potentially useful info to print. |
96 | @@ -72,15 +73,15 @@ |
97 | Machines map[string]machineStatus `json:"machines"` |
98 | Services map[string]serviceStatus `json:"services"` |
99 | }{ |
100 | - Machines: ctxt.processMachines(), |
101 | - Services: ctxt.processServices(), |
102 | + Machines: context.processMachines(), |
103 | + Services: context.processServices(), |
104 | } |
105 | return c.out.Write(ctx, result) |
106 | } |
107 | |
108 | // fetchAllInstances returns a map from instance id to instance. |
109 | -func fetchAllInstances(env environs.Environ) (map[state.InstanceId]environs.Instance, error) { |
110 | - m := make(map[state.InstanceId]environs.Instance) |
111 | +func fetchAllInstances(env environs.Environ) (map[state.InstanceId]instance.Instance, error) { |
112 | + m := make(map[state.InstanceId]instance.Instance) |
113 | insts, err := env.AllInstances() |
114 | if err != nil { |
115 | return nil, err |
116 | @@ -91,15 +92,29 @@ |
117 | return m, nil |
118 | } |
119 | |
120 | -// fetchAllMachines returns a map from machine id to machine. |
121 | -func fetchAllMachines(st *state.State) (map[string]*state.Machine, error) { |
122 | - v := make(map[string]*state.Machine) |
123 | +// fetchAllMachines returns a map from top level machine id to machines, where machines[0] is the host |
124 | +// machine and machines[1..n] are any containers (including nested ones). |
125 | +func fetchAllMachines(st *state.State) (map[string][]*state.Machine, error) { |
126 | + v := make(map[string][]*state.Machine) |
127 | machines, err := st.AllMachines() |
128 | if err != nil { |
129 | return nil, err |
130 | } |
131 | + // AllMachines gives us machines sorted by id. |
132 | for _, m := range machines { |
133 | - v[m.Id()] = m |
134 | + parentId, ok := m.ParentId() |
135 | + if !ok { |
136 | + // Only top level host machines go directly into the machine map. |
137 | + v[m.Id()] = []*state.Machine{m} |
138 | + } else { |
139 | + topParentId := state.TopParentId(m.Id()) |
140 | + machines, ok := v[topParentId] |
141 | + if !ok { |
142 | + panic(fmt.Errorf("unexpected machine id %q", parentId)) |
143 | + } |
144 | + machines = append(machines, m) |
145 | + v[topParentId] = machines |
146 | + } |
147 | } |
148 | return v, nil |
149 | } |
150 | @@ -128,15 +143,40 @@ |
151 | return svcMap, unitMap, nil |
152 | } |
153 | |
154 | -func (ctxt *statusContext) processMachines() map[string]machineStatus { |
155 | +func (context *statusContext) processMachines() map[string]machineStatus { |
156 | machinesMap := make(map[string]machineStatus) |
157 | - for _, m := range ctxt.machines { |
158 | - machinesMap[m.Id()] = ctxt.processMachine(m) |
159 | + for id, machines := range context.machines { |
160 | + hostStatus := context.makeMachineStatus(machines[0]) |
161 | + context.processMachine(machines, &hostStatus, 0) |
162 | + machinesMap[id] = hostStatus |
163 | } |
164 | return machinesMap |
165 | } |
166 | |
167 | -func (ctxt *statusContext) processMachine(machine *state.Machine) (status machineStatus) { |
168 | +func (context *statusContext) processMachine(machines []*state.Machine, host *machineStatus, startIndex int) (nextIndex int) { |
169 | + nextIndex = startIndex + 1 |
170 | + currentHost := host |
171 | + var previousContainer *machineStatus |
172 | + for nextIndex < len(machines) { |
173 | + machine := machines[nextIndex] |
174 | + container := context.makeMachineStatus(machine) |
175 | + if currentHost.Id == state.ParentId(machine.Id()) { |
176 | + currentHost.Containers[machine.Id()] = container |
177 | + previousContainer = &container |
178 | + nextIndex++ |
179 | + } else { |
180 | + if state.NestingLevel(machine.Id()) > state.NestingLevel(previousContainer.Id) { |
181 | + nextIndex = context.processMachine(machines, previousContainer, nextIndex-1) |
182 | + } else { |
183 | + break |
184 | + } |
185 | + } |
186 | + } |
187 | + return |
188 | +} |
189 | + |
190 | +func (context *statusContext) makeMachineStatus(machine *state.Machine) (status machineStatus) { |
191 | + status.Id = machine.Id() |
192 | status.Life, |
193 | status.AgentVersion, |
194 | status.AgentState, |
195 | @@ -146,7 +186,7 @@ |
196 | instid, ok := machine.InstanceId() |
197 | if ok { |
198 | status.InstanceId = instid |
199 | - instance, ok := ctxt.instances[instid] |
200 | + instance, ok := context.instances[instid] |
201 | if ok { |
202 | status.DNSName, _ = instance.DNSName() |
203 | } else { |
204 | @@ -163,43 +203,44 @@ |
205 | // in the output. |
206 | status.AgentState = "" |
207 | } |
208 | + status.Containers = make(map[string]machineStatus) |
209 | return |
210 | } |
211 | |
212 | -func (ctxt *statusContext) processServices() map[string]serviceStatus { |
213 | +func (context *statusContext) processServices() map[string]serviceStatus { |
214 | servicesMap := make(map[string]serviceStatus) |
215 | - for _, s := range ctxt.services { |
216 | - servicesMap[s.Name()] = ctxt.processService(s) |
217 | + for _, s := range context.services { |
218 | + servicesMap[s.Name()] = context.processService(s) |
219 | } |
220 | return servicesMap |
221 | } |
222 | |
223 | -func (ctxt *statusContext) processService(service *state.Service) (status serviceStatus) { |
224 | +func (context *statusContext) processService(service *state.Service) (status serviceStatus) { |
225 | url, _ := service.CharmURL() |
226 | status.Charm = url.String() |
227 | status.Exposed = service.IsExposed() |
228 | status.Life = processLife(service) |
229 | var err error |
230 | - status.Relations, status.SubordinateTo, err = ctxt.processRelations(service) |
231 | + status.Relations, status.SubordinateTo, err = context.processRelations(service) |
232 | if err != nil { |
233 | status.Err = err |
234 | return |
235 | } |
236 | if service.IsPrincipal() { |
237 | - status.Units = ctxt.processUnits(ctxt.units[service.Name()]) |
238 | + status.Units = context.processUnits(context.units[service.Name()]) |
239 | } |
240 | return status |
241 | } |
242 | |
243 | -func (ctxt *statusContext) processUnits(units map[string]*state.Unit) map[string]unitStatus { |
244 | +func (context *statusContext) processUnits(units map[string]*state.Unit) map[string]unitStatus { |
245 | unitsMap := make(map[string]unitStatus) |
246 | for _, unit := range units { |
247 | - unitsMap[unit.Name()] = ctxt.processUnit(unit) |
248 | + unitsMap[unit.Name()] = context.processUnit(unit) |
249 | } |
250 | return unitsMap |
251 | } |
252 | |
253 | -func (ctxt *statusContext) processUnit(unit *state.Unit) (status unitStatus) { |
254 | +func (context *statusContext) processUnit(unit *state.Unit) (status unitStatus) { |
255 | status.PublicAddress, _ = unit.PublicAddress() |
256 | if unit.IsPrincipal() { |
257 | status.Machine, _ = unit.AssignedMachineId() |
258 | @@ -212,16 +253,16 @@ |
259 | if subUnits := unit.SubordinateNames(); len(subUnits) > 0 { |
260 | status.Subordinates = make(map[string]unitStatus) |
261 | for _, name := range subUnits { |
262 | - subUnit := ctxt.unitByName(name) |
263 | - status.Subordinates[name] = ctxt.processUnit(subUnit) |
264 | + subUnit := context.unitByName(name) |
265 | + status.Subordinates[name] = context.processUnit(subUnit) |
266 | } |
267 | } |
268 | return |
269 | } |
270 | |
271 | -func (ctxt *statusContext) unitByName(name string) *state.Unit { |
272 | +func (context *statusContext) unitByName(name string) *state.Unit { |
273 | serviceName := strings.Split(name, "/")[0] |
274 | - return ctxt.units[serviceName][name] |
275 | + return context.units[serviceName][name] |
276 | } |
277 | |
278 | func (*statusContext) processRelations(service *state.Service) (related map[string][]string, subord []string, err error) { |
279 | @@ -311,15 +352,17 @@ |
280 | } |
281 | |
282 | type machineStatus struct { |
283 | - Err error `json:"-" yaml:",omitempty"` |
284 | - AgentState params.Status `json:"agent-state,omitempty" yaml:"agent-state,omitempty"` |
285 | - AgentStateInfo string `json:"agent-state-info,omitempty" yaml:"agent-state-info,omitempty"` |
286 | - AgentVersion string `json:"agent-version,omitempty" yaml:"agent-version,omitempty"` |
287 | - DNSName string `json:"dns-name,omitempty" yaml:"dns-name,omitempty"` |
288 | - InstanceId state.InstanceId `json:"instance-id,omitempty" yaml:"instance-id,omitempty"` |
289 | - InstanceState string `json:"instance-state,omitempty" yaml:"instance-state,omitempty"` |
290 | - Life string `json:"life,omitempty" yaml:"life,omitempty"` |
291 | - Series string `json:"series,omitempty" yaml:"series,omitempty"` |
292 | + Err error `json:"-" yaml:",omitempty"` |
293 | + AgentState params.Status `json:"agent-state,omitempty" yaml:"agent-state,omitempty"` |
294 | + AgentStateInfo string `json:"agent-state-info,omitempty" yaml:"agent-state-info,omitempty"` |
295 | + AgentVersion string `json:"agent-version,omitempty" yaml:"agent-version,omitempty"` |
296 | + DNSName string `json:"dns-name,omitempty" yaml:"dns-name,omitempty"` |
297 | + InstanceId state.InstanceId `json:"instance-id,omitempty" yaml:"instance-id,omitempty"` |
298 | + InstanceState string `json:"instance-state,omitempty" yaml:"instance-state,omitempty"` |
299 | + Life string `json:"life,omitempty" yaml:"life,omitempty"` |
300 | + Series string `json:"series,omitempty" yaml:"series,omitempty"` |
301 | + Id string `json:"-" yaml:"-"` |
302 | + Containers map[string]machineStatus `json:"containers,omitempty" yaml:"containers,omitempty"` |
303 | } |
304 | |
305 | // A goyaml bug means we can't declare these types |
306 | |
307 | === modified file 'cmd/juju/status_test.go' |
308 | --- cmd/juju/status_test.go 2013-05-27 03:00:31 +0000 |
309 | +++ cmd/juju/status_test.go 2013-06-17 04:13:30 +0000 |
310 | @@ -117,6 +117,32 @@ |
311 | "instance-id": "dummyenv-4", |
312 | "series": "series", |
313 | } |
314 | + machine1WithContainers = M{ |
315 | + "agent-state": "started", |
316 | + "containers": M{ |
317 | + "1/lxc/0": M{ |
318 | + "agent-state": "started", |
319 | + "containers": M{ |
320 | + "1/lxc/0/lxc/0": M{ |
321 | + "agent-state": "started", |
322 | + "dns-name": "dummyenv-3.dns", |
323 | + "instance-id": "dummyenv-3", |
324 | + "series": "series", |
325 | + }, |
326 | + }, |
327 | + "dns-name": "dummyenv-2.dns", |
328 | + "instance-id": "dummyenv-2", |
329 | + "series": "series", |
330 | + }, |
331 | + "1/lxc/1": M{ |
332 | + "instance-id": "pending", |
333 | + "series": "series", |
334 | + }, |
335 | + }, |
336 | + "dns-name": "dummyenv-1.dns", |
337 | + "instance-id": "dummyenv-1", |
338 | + "series": "series", |
339 | + } |
340 | unexposedService = M{ |
341 | "charm": "local:series/dummy-1", |
342 | "exposed": false, |
343 | @@ -716,6 +742,59 @@ |
344 | }, |
345 | }, |
346 | }, |
347 | + ), test( |
348 | + "machines with containers", |
349 | + addMachine{"0", state.JobManageEnviron}, |
350 | + startAliveMachine{"0"}, |
351 | + setMachineStatus{"0", params.StatusStarted, ""}, |
352 | + addCharm{"mysql"}, |
353 | + addService{"mysql", "mysql"}, |
354 | + setServiceExposed{"mysql", true}, |
355 | + |
356 | + addMachine{"1", state.JobHostUnits}, |
357 | + startAliveMachine{"1"}, |
358 | + setMachineStatus{"1", params.StatusStarted, ""}, |
359 | + addAliveUnit{"mysql", "1"}, |
360 | + setUnitStatus{"mysql/0", params.StatusStarted, ""}, |
361 | + |
362 | + // A container on machine 1. |
363 | + addContainer{"1", "1/lxc/0", state.JobHostUnits}, |
364 | + startAliveMachine{"1/lxc/0"}, |
365 | + setMachineStatus{"1/lxc/0", params.StatusStarted, ""}, |
366 | + addAliveUnit{"mysql", "1/lxc/0"}, |
367 | + setUnitStatus{"mysql/1", params.StatusStarted, ""}, |
368 | + addContainer{"1", "1/lxc/1", state.JobHostUnits}, |
369 | + |
370 | + // A nested container. |
371 | + addContainer{"1/lxc/0", "1/lxc/0/lxc/0", state.JobHostUnits}, |
372 | + startAliveMachine{"1/lxc/0/lxc/0"}, |
373 | + setMachineStatus{"1/lxc/0/lxc/0", params.StatusStarted, ""}, |
374 | + |
375 | + expect{ |
376 | + "machines with nested containers", |
377 | + M{ |
378 | + "machines": M{ |
379 | + "0": machine0, |
380 | + "1": machine1WithContainers, |
381 | + }, |
382 | + "services": M{ |
383 | + "mysql": M{ |
384 | + "charm": "local:series/mysql-1", |
385 | + "exposed": true, |
386 | + "units": M{ |
387 | + "mysql/0": M{ |
388 | + "machine": "1", |
389 | + "agent-state": "started", |
390 | + }, |
391 | + "mysql/1": M{ |
392 | + "machine": "1/lxc/0", |
393 | + "agent-state": "started", |
394 | + }, |
395 | + }, |
396 | + }, |
397 | + }, |
398 | + }, |
399 | + }, |
400 | ), |
401 | } |
402 | |
403 | @@ -732,6 +811,24 @@ |
404 | c.Assert(m.Id(), Equals, am.machineId) |
405 | } |
406 | |
407 | +type addContainer struct { |
408 | + parentId string |
409 | + machineId string |
410 | + job state.MachineJob |
411 | +} |
412 | + |
413 | +func (ac addContainer) step(c *C, ctx *context) { |
414 | + params := &state.AddMachineParams{ |
415 | + ParentId: ac.parentId, |
416 | + ContainerType: state.LXC, |
417 | + Series: "series", |
418 | + Jobs: []state.MachineJob{ac.job}, |
419 | + } |
420 | + m, err := ctx.st.AddMachineWithConstraints(params) |
421 | + c.Assert(err, IsNil) |
422 | + c.Assert(m.Id(), Equals, ac.machineId) |
423 | +} |
424 | + |
425 | type startMachine struct { |
426 | machineId string |
427 | } |
428 | |
429 | === modified file 'environs/azure/environ.go' |
430 | --- environs/azure/environ.go 2013-06-11 12:41:10 +0000 |
431 | +++ environs/azure/environ.go 2013-06-17 04:13:30 +0000 |
432 | @@ -7,6 +7,7 @@ |
433 | "launchpad.net/juju-core/constraints" |
434 | "launchpad.net/juju-core/environs" |
435 | "launchpad.net/juju-core/environs/config" |
436 | + "launchpad.net/juju-core/instance" |
437 | "launchpad.net/juju-core/state" |
438 | "launchpad.net/juju-core/state/api" |
439 | "launchpad.net/juju-core/state/api/params" |
440 | @@ -43,22 +44,22 @@ |
441 | } |
442 | |
443 | // StartInstance is specified in the Environ interface. |
444 | -func (env *azureEnviron) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (environs.Instance, error) { |
445 | +func (env *azureEnviron) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (instance.Instance, error) { |
446 | panic("unimplemented") |
447 | } |
448 | |
449 | // StopInstances is specified in the Environ interface. |
450 | -func (env *azureEnviron) StopInstances([]environs.Instance) error { |
451 | +func (env *azureEnviron) StopInstances([]instance.Instance) error { |
452 | panic("unimplemented") |
453 | } |
454 | |
455 | // Instances is specified in the Environ interface. |
456 | -func (env *azureEnviron) Instances(ids []state.InstanceId) ([]environs.Instance, error) { |
457 | +func (env *azureEnviron) Instances(ids []state.InstanceId) ([]instance.Instance, error) { |
458 | panic("unimplemented") |
459 | } |
460 | |
461 | // AllInstances is specified in the Environ interface. |
462 | -func (env *azureEnviron) AllInstances() ([]environs.Instance, error) { |
463 | +func (env *azureEnviron) AllInstances() ([]instance.Instance, error) { |
464 | panic("unimplemented") |
465 | } |
466 | |
467 | @@ -73,7 +74,7 @@ |
468 | } |
469 | |
470 | // Destroy is specified in the Environ interface. |
471 | -func (env *azureEnviron) Destroy(insts []environs.Instance) error { |
472 | +func (env *azureEnviron) Destroy(insts []instance.Instance) error { |
473 | panic("unimplemented") |
474 | } |
475 | |
476 | |
477 | === modified file 'environs/azure/instance.go' |
478 | --- environs/azure/instance.go 2013-06-11 12:41:10 +0000 |
479 | +++ environs/azure/instance.go 2013-06-17 04:13:30 +0000 |
480 | @@ -4,7 +4,7 @@ |
481 | package azure |
482 | |
483 | import ( |
484 | - "launchpad.net/juju-core/environs" |
485 | + "launchpad.net/juju-core/instance" |
486 | "launchpad.net/juju-core/state" |
487 | "launchpad.net/juju-core/state/api/params" |
488 | ) |
489 | @@ -12,7 +12,7 @@ |
490 | type azureInstance struct{} |
491 | |
492 | // azureInstance implements Instance. |
493 | -var _ environs.Instance = (*azureInstance)(nil) |
494 | +var _ instance.Instance = (*azureInstance)(nil) |
495 | |
496 | // Id is specified in the Instance interface. |
497 | func (instance *azureInstance) Id() state.InstanceId { |
498 | |
499 | === modified file 'environs/dummy/environs.go' |
500 | --- environs/dummy/environs.go 2013-05-28 08:05:49 +0000 |
501 | +++ environs/dummy/environs.go 2013-06-17 04:13:30 +0000 |
502 | @@ -29,6 +29,7 @@ |
503 | "launchpad.net/juju-core/environs" |
504 | "launchpad.net/juju-core/environs/config" |
505 | envtesting "launchpad.net/juju-core/environs/testing" |
506 | + "launchpad.net/juju-core/instance" |
507 | "launchpad.net/juju-core/log" |
508 | "launchpad.net/juju-core/schema" |
509 | "launchpad.net/juju-core/state" |
510 | @@ -75,7 +76,7 @@ |
511 | Env string |
512 | MachineId string |
513 | MachineNonce string |
514 | - Instance environs.Instance |
515 | + Instance instance.Instance |
516 | Constraints constraints.Value |
517 | Info *state.Info |
518 | APIInfo *api.Info |
519 | @@ -84,7 +85,7 @@ |
520 | |
521 | type OpStopInstances struct { |
522 | Env string |
523 | - Instances []environs.Instance |
524 | + Instances []instance.Instance |
525 | } |
526 | |
527 | type OpOpenPorts struct { |
528 | @@ -122,7 +123,7 @@ |
529 | ops chan<- Operation |
530 | mu sync.Mutex |
531 | maxId int // maximum instance id allocated so far. |
532 | - insts map[state.InstanceId]*instance |
533 | + insts map[state.InstanceId]*dummyInstance |
534 | globalPorts map[params.Port]bool |
535 | firewallMode config.FirewallMode |
536 | bootstrapped bool |
537 | @@ -224,7 +225,7 @@ |
538 | s := &environState{ |
539 | name: name, |
540 | ops: ops, |
541 | - insts: make(map[state.InstanceId]*instance), |
542 | + insts: make(map[state.InstanceId]*dummyInstance), |
543 | globalPorts: make(map[params.Port]bool), |
544 | firewallMode: fwmode, |
545 | } |
546 | @@ -515,7 +516,7 @@ |
547 | return nil |
548 | } |
549 | |
550 | -func (e *environ) Destroy([]environs.Instance) error { |
551 | +func (e *environ) Destroy([]instance.Instance) error { |
552 | defer delay() |
553 | if err := e.checkBroken("Destroy"); err != nil { |
554 | return err |
555 | @@ -527,7 +528,7 @@ |
556 | return nil |
557 | } |
558 | |
559 | -func (e *environ) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (environs.Instance, error) { |
560 | +func (e *environ) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (instance.Instance, error) { |
561 | defer delay() |
562 | log.Infof("environs/dummy: dummy startinstance, machine %s", machineId) |
563 | if err := e.checkBroken("StartInstance"); err != nil { |
564 | @@ -552,7 +553,7 @@ |
565 | if apiInfo.Tag != state.MachineTag(machineId) { |
566 | return nil, fmt.Errorf("entity tag must match started machine") |
567 | } |
568 | - i := &instance{ |
569 | + i := &dummyInstance{ |
570 | state: e.state, |
571 | id: state.InstanceId(fmt.Sprintf("%s-%d", e.state.name, e.state.maxId)), |
572 | ports: make(map[params.Port]bool), |
573 | @@ -574,7 +575,7 @@ |
574 | return i, nil |
575 | } |
576 | |
577 | -func (e *environ) StopInstances(is []environs.Instance) error { |
578 | +func (e *environ) StopInstances(is []instance.Instance) error { |
579 | defer delay() |
580 | if err := e.checkBroken("StopInstance"); err != nil { |
581 | return err |
582 | @@ -582,7 +583,7 @@ |
583 | e.state.mu.Lock() |
584 | defer e.state.mu.Unlock() |
585 | for _, i := range is { |
586 | - delete(e.state.insts, i.(*instance).id) |
587 | + delete(e.state.insts, i.(*dummyInstance).id) |
588 | } |
589 | e.state.ops <- OpStopInstances{ |
590 | Env: e.state.name, |
591 | @@ -591,7 +592,7 @@ |
592 | return nil |
593 | } |
594 | |
595 | -func (e *environ) Instances(ids []state.InstanceId) (insts []environs.Instance, err error) { |
596 | +func (e *environ) Instances(ids []state.InstanceId) (insts []instance.Instance, err error) { |
597 | defer delay() |
598 | if err := e.checkBroken("Instances"); err != nil { |
599 | return nil, err |
600 | @@ -616,12 +617,12 @@ |
601 | return |
602 | } |
603 | |
604 | -func (e *environ) AllInstances() ([]environs.Instance, error) { |
605 | +func (e *environ) AllInstances() ([]instance.Instance, error) { |
606 | defer delay() |
607 | if err := e.checkBroken("AllInstances"); err != nil { |
608 | return nil, err |
609 | } |
610 | - var insts []environs.Instance |
611 | + var insts []instance.Instance |
612 | e.state.mu.Lock() |
613 | defer e.state.mu.Unlock() |
614 | for _, v := range e.state.insts { |
615 | @@ -674,7 +675,7 @@ |
616 | return &providerInstance |
617 | } |
618 | |
619 | -type instance struct { |
620 | +type dummyInstance struct { |
621 | state *environState |
622 | ports map[params.Port]bool |
623 | id state.InstanceId |
624 | @@ -682,20 +683,20 @@ |
625 | series string |
626 | } |
627 | |
628 | -func (inst *instance) Id() state.InstanceId { |
629 | +func (inst *dummyInstance) Id() state.InstanceId { |
630 | return inst.id |
631 | } |
632 | |
633 | -func (inst *instance) DNSName() (string, error) { |
634 | +func (inst *dummyInstance) DNSName() (string, error) { |
635 | defer delay() |
636 | return string(inst.id) + ".dns", nil |
637 | } |
638 | |
639 | -func (inst *instance) WaitDNSName() (string, error) { |
640 | +func (inst *dummyInstance) WaitDNSName() (string, error) { |
641 | return inst.DNSName() |
642 | } |
643 | |
644 | -func (inst *instance) OpenPorts(machineId string, ports []params.Port) error { |
645 | +func (inst *dummyInstance) OpenPorts(machineId string, ports []params.Port) error { |
646 | defer delay() |
647 | log.Infof("environs/dummy: openPorts %s, %#v", machineId, ports) |
648 | if inst.state.firewallMode != config.FwInstance { |
649 | @@ -719,7 +720,7 @@ |
650 | return nil |
651 | } |
652 | |
653 | -func (inst *instance) ClosePorts(machineId string, ports []params.Port) error { |
654 | +func (inst *dummyInstance) ClosePorts(machineId string, ports []params.Port) error { |
655 | defer delay() |
656 | if inst.state.firewallMode != config.FwInstance { |
657 | return fmt.Errorf("invalid firewall mode for closing ports on instance: %q", |
658 | @@ -742,7 +743,7 @@ |
659 | return nil |
660 | } |
661 | |
662 | -func (inst *instance) Ports(machineId string) (ports []params.Port, err error) { |
663 | +func (inst *dummyInstance) Ports(machineId string) (ports []params.Port, err error) { |
664 | defer delay() |
665 | if inst.state.firewallMode != config.FwInstance { |
666 | return nil, fmt.Errorf("invalid firewall mode for retrieving ports from instance: %q", |
667 | |
668 | === modified file 'environs/ec2/ec2.go' |
669 | --- environs/ec2/ec2.go 2013-06-10 10:30:13 +0000 |
670 | +++ environs/ec2/ec2.go 2013-06-17 04:13:30 +0000 |
671 | @@ -17,6 +17,7 @@ |
672 | "launchpad.net/juju-core/environs/instances" |
673 | "launchpad.net/juju-core/environs/tools" |
674 | "launchpad.net/juju-core/errors" |
675 | + "launchpad.net/juju-core/instance" |
676 | "launchpad.net/juju-core/log" |
677 | "launchpad.net/juju-core/state" |
678 | "launchpad.net/juju-core/state/api" |
679 | @@ -65,22 +66,22 @@ |
680 | |
681 | var _ environs.Environ = (*environ)(nil) |
682 | |
683 | -type instance struct { |
684 | +type ec2Instance struct { |
685 | e *environ |
686 | *ec2.Instance |
687 | } |
688 | |
689 | -func (inst *instance) String() string { |
690 | +func (inst *ec2Instance) String() string { |
691 | return inst.InstanceId |
692 | } |
693 | |
694 | -var _ environs.Instance = (*instance)(nil) |
695 | +var _ instance.Instance = (*ec2Instance)(nil) |
696 | |
697 | -func (inst *instance) Id() state.InstanceId { |
698 | +func (inst *ec2Instance) Id() state.InstanceId { |
699 | return state.InstanceId(inst.InstanceId) |
700 | } |
701 | |
702 | -func (inst *instance) DNSName() (string, error) { |
703 | +func (inst *ec2Instance) DNSName() (string, error) { |
704 | if inst.Instance.DNSName != "" { |
705 | return inst.Instance.DNSName, nil |
706 | } |
707 | @@ -90,18 +91,18 @@ |
708 | if err != nil { |
709 | return "", err |
710 | } |
711 | - freshInst := insts[0].(*instance).Instance |
712 | + freshInst := insts[0].(*ec2Instance).Instance |
713 | if freshInst.DNSName == "" { |
714 | - return "", environs.ErrNoDNSName |
715 | + return "", instance.ErrNoDNSName |
716 | } |
717 | inst.Instance.DNSName = freshInst.DNSName |
718 | return freshInst.DNSName, nil |
719 | } |
720 | |
721 | -func (inst *instance) WaitDNSName() (string, error) { |
722 | +func (inst *ec2Instance) WaitDNSName() (string, error) { |
723 | for a := longAttempt.Start(); a.Next(); { |
724 | name, err := inst.DNSName() |
725 | - if err == nil || err != environs.ErrNoDNSName { |
726 | + if err == nil || err != instance.ErrNoDNSName { |
727 | return name, err |
728 | } |
729 | } |
730 | @@ -278,7 +279,7 @@ |
731 | if err != nil { |
732 | // ignore error on StopInstance because the previous error is |
733 | // more important. |
734 | - e.StopInstances([]environs.Instance{inst}) |
735 | + e.StopInstances([]instance.Instance{inst}) |
736 | return fmt.Errorf("cannot save state: %v", err) |
737 | } |
738 | // TODO make safe in the case of racing Bootstraps |
739 | @@ -313,7 +314,7 @@ |
740 | if inst == nil { |
741 | continue |
742 | } |
743 | - name := inst.(*instance).Instance.DNSName |
744 | + name := inst.(*ec2Instance).Instance.DNSName |
745 | if name != "" { |
746 | statePortSuffix := fmt.Sprintf(":%d", config.StatePort()) |
747 | apiPortSuffix := fmt.Sprintf(":%d", config.APIPort()) |
748 | @@ -340,7 +341,7 @@ |
749 | return []string{imagemetadata.DefaultBaseURL}, nil |
750 | } |
751 | |
752 | -func (e *environ) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (environs.Instance, error) { |
753 | +func (e *environ) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (instance.Instance, error) { |
754 | possibleTools, err := environs.FindInstanceTools(e, series, cons) |
755 | if err != nil { |
756 | return nil, err |
757 | @@ -397,7 +398,7 @@ |
758 | |
759 | // startInstance is the internal version of StartInstance, used by Bootstrap |
760 | // as well as via StartInstance itself. |
761 | -func (e *environ) startInstance(scfg *startInstanceParams) (environs.Instance, error) { |
762 | +func (e *environ) startInstance(scfg *startInstanceParams) (instance.Instance, error) { |
763 | series := scfg.possibleTools.Series() |
764 | if len(series) != 1 { |
765 | return nil, fmt.Errorf("expected single series, got %v", series) |
766 | @@ -455,15 +456,15 @@ |
767 | if len(instances.Instances) != 1 { |
768 | return nil, fmt.Errorf("expected 1 started instance, got %d", len(instances.Instances)) |
769 | } |
770 | - inst := &instance{e, &instances.Instances[0]} |
771 | + inst := &ec2Instance{e, &instances.Instances[0]} |
772 | log.Infof("environs/ec2: started instance %q", inst.Id()) |
773 | return inst, nil |
774 | } |
775 | |
776 | -func (e *environ) StopInstances(insts []environs.Instance) error { |
777 | +func (e *environ) StopInstances(insts []instance.Instance) error { |
778 | ids := make([]state.InstanceId, len(insts)) |
779 | for i, inst := range insts { |
780 | - ids[i] = inst.(*instance).Id() |
781 | + ids[i] = inst.(*ec2Instance).Id() |
782 | } |
783 | return e.terminateInstances(ids) |
784 | } |
785 | @@ -472,7 +473,7 @@ |
786 | // id whose corresponding insts slot is nil. |
787 | // It returns environs.ErrPartialInstances if the insts |
788 | // slice has not been completely filled. |
789 | -func (e *environ) gatherInstances(ids []state.InstanceId, insts []environs.Instance) error { |
790 | +func (e *environ) gatherInstances(ids []state.InstanceId, insts []instance.Instance) error { |
791 | var need []string |
792 | for i, inst := range insts { |
793 | if inst == nil { |
794 | @@ -502,7 +503,7 @@ |
795 | for k := range r.Instances { |
796 | if r.Instances[k].InstanceId == string(id) { |
797 | inst := r.Instances[k] |
798 | - insts[i] = &instance{e, &inst} |
799 | + insts[i] = &ec2Instance{e, &inst} |
800 | n++ |
801 | } |
802 | } |
803 | @@ -514,11 +515,11 @@ |
804 | return nil |
805 | } |
806 | |
807 | -func (e *environ) Instances(ids []state.InstanceId) ([]environs.Instance, error) { |
808 | +func (e *environ) Instances(ids []state.InstanceId) ([]instance.Instance, error) { |
809 | if len(ids) == 0 { |
810 | return nil, nil |
811 | } |
812 | - insts := make([]environs.Instance, len(ids)) |
813 | + insts := make([]instance.Instance, len(ids)) |
814 | // Make a series of requests to cope with eventual consistency. |
815 | // Each request will attempt to add more instances to the requested |
816 | // set. |
817 | @@ -543,7 +544,7 @@ |
818 | return insts, nil |
819 | } |
820 | |
821 | -func (e *environ) AllInstances() ([]environs.Instance, error) { |
822 | +func (e *environ) AllInstances() ([]instance.Instance, error) { |
823 | filter := ec2.NewFilter() |
824 | filter.Add("instance-state-name", "pending", "running") |
825 | filter.Add("group-name", e.jujuGroupName()) |
826 | @@ -551,17 +552,17 @@ |
827 | if err != nil { |
828 | return nil, err |
829 | } |
830 | - var insts []environs.Instance |
831 | + var insts []instance.Instance |
832 | for _, r := range resp.Reservations { |
833 | for i := range r.Instances { |
834 | inst := r.Instances[i] |
835 | - insts = append(insts, &instance{e, &inst}) |
836 | + insts = append(insts, &ec2Instance{e, &inst}) |
837 | } |
838 | } |
839 | return insts, nil |
840 | } |
841 | |
842 | -func (e *environ) Destroy(ensureInsts []environs.Instance) error { |
843 | +func (e *environ) Destroy(ensureInsts []instance.Instance) error { |
844 | log.Infof("environs/ec2: destroying environment %q", e.name) |
845 | insts, err := e.AllInstances() |
846 | if err != nil { |
847 | @@ -577,7 +578,7 @@ |
848 | // Add any instances we've been told about but haven't yet shown |
849 | // up in the instance list. |
850 | for _, inst := range ensureInsts { |
851 | - id := state.InstanceId(inst.(*instance).InstanceId) |
852 | + id := state.InstanceId(inst.(*ec2Instance).InstanceId) |
853 | if !found[id] { |
854 | ids = append(ids, id) |
855 | found[id] = true |
856 | @@ -761,7 +762,7 @@ |
857 | return "juju-" + e.name |
858 | } |
859 | |
860 | -func (inst *instance) OpenPorts(machineId string, ports []params.Port) error { |
861 | +func (inst *ec2Instance) OpenPorts(machineId string, ports []params.Port) error { |
862 | if inst.e.Config().FirewallMode() != config.FwInstance { |
863 | return fmt.Errorf("invalid firewall mode for opening ports on instance: %q", |
864 | inst.e.Config().FirewallMode()) |
865 | @@ -774,7 +775,7 @@ |
866 | return nil |
867 | } |
868 | |
869 | -func (inst *instance) ClosePorts(machineId string, ports []params.Port) error { |
870 | +func (inst *ec2Instance) ClosePorts(machineId string, ports []params.Port) error { |
871 | if inst.e.Config().FirewallMode() != config.FwInstance { |
872 | return fmt.Errorf("invalid firewall mode for closing ports on instance: %q", |
873 | inst.e.Config().FirewallMode()) |
874 | @@ -787,7 +788,7 @@ |
875 | return nil |
876 | } |
877 | |
878 | -func (inst *instance) Ports(machineId string) ([]params.Port, error) { |
879 | +func (inst *ec2Instance) Ports(machineId string) ([]params.Port, error) { |
880 | if inst.e.Config().FirewallMode() != config.FwInstance { |
881 | return nil, fmt.Errorf("invalid firewall mode for retrieving ports from instance: %q", |
882 | inst.e.Config().FirewallMode()) |
883 | |
884 | === modified file 'environs/ec2/export_test.go' |
885 | --- environs/ec2/export_test.go 2013-05-30 05:39:33 +0000 |
886 | +++ environs/ec2/export_test.go 2013-06-17 04:13:30 +0000 |
887 | @@ -11,6 +11,7 @@ |
888 | "launchpad.net/juju-core/environs" |
889 | "launchpad.net/juju-core/environs/imagemetadata" |
890 | "launchpad.net/juju-core/environs/jujutest" |
891 | + "launchpad.net/juju-core/instance" |
892 | "launchpad.net/juju-core/state" |
893 | "launchpad.net/juju-core/utils" |
894 | "net/http" |
895 | @@ -48,8 +49,8 @@ |
896 | return s.(*storage).deleteAll() |
897 | } |
898 | |
899 | -func InstanceEC2(inst environs.Instance) *ec2.Instance { |
900 | - return inst.(*instance).Instance |
901 | +func InstanceEC2(inst instance.Instance) *ec2.Instance { |
902 | + return inst.(*ec2Instance).Instance |
903 | } |
904 | |
905 | // BucketStorage returns a storage instance addressing |
906 | @@ -147,9 +148,9 @@ |
907 | |
908 | // FabricateInstance creates a new fictitious instance |
909 | // given an existing instance and a new id. |
910 | -func FabricateInstance(inst environs.Instance, newId string) environs.Instance { |
911 | - oldi := inst.(*instance) |
912 | - newi := &instance{oldi.e, &ec2.Instance{}} |
913 | +func FabricateInstance(inst instance.Instance, newId string) instance.Instance { |
914 | + oldi := inst.(*ec2Instance) |
915 | + newi := &ec2Instance{oldi.e, &ec2.Instance{}} |
916 | *newi.Instance = *oldi.Instance |
917 | newi.InstanceId = newId |
918 | return newi |
919 | |
920 | === modified file 'environs/ec2/live_test.go' |
921 | --- environs/ec2/live_test.go 2013-05-30 00:47:30 +0000 |
922 | +++ environs/ec2/live_test.go 2013-06-17 04:13:30 +0000 |
923 | @@ -17,6 +17,7 @@ |
924 | "launchpad.net/juju-core/environs/jujutest" |
925 | envtesting "launchpad.net/juju-core/environs/testing" |
926 | "launchpad.net/juju-core/errors" |
927 | + "launchpad.net/juju-core/instance" |
928 | "launchpad.net/juju-core/juju/testing" |
929 | "launchpad.net/juju-core/state" |
930 | coretesting "launchpad.net/juju-core/testing" |
931 | @@ -113,7 +114,7 @@ |
932 | |
933 | func (t *LiveTests) TestInstanceAttributes(c *C) { |
934 | inst := testing.StartInstance(c, t.Env, "30") |
935 | - defer t.Env.StopInstances([]environs.Instance{inst}) |
936 | + defer t.Env.StopInstances([]instance.Instance{inst}) |
937 | dns, err := inst.WaitDNSName() |
938 | // TODO(niemeyer): This assert sometimes fails with "no instances found" |
939 | c.Assert(err, IsNil) |
940 | @@ -132,7 +133,7 @@ |
941 | cons := constraints.MustParse("mem=2G") |
942 | inst, err := t.Env.StartInstance("31", "fake_nonce", config.DefaultSeries, cons, testing.InvalidStateInfo("31"), testing.InvalidAPIInfo("31")) |
943 | c.Assert(err, IsNil) |
944 | - defer t.Env.StopInstances([]environs.Instance{inst}) |
945 | + defer t.Env.StopInstances([]instance.Instance{inst}) |
946 | ec2inst := ec2.InstanceEC2(inst) |
947 | c.Assert(ec2inst.InstanceType, Equals, "m1.medium") |
948 | } |
949 | @@ -173,14 +174,14 @@ |
950 | c.Assert(err, IsNil) |
951 | |
952 | inst0 := testing.StartInstance(c, t.Env, "98") |
953 | - defer t.Env.StopInstances([]environs.Instance{inst0}) |
954 | + defer t.Env.StopInstances([]instance.Instance{inst0}) |
955 | |
956 | // Create a same-named group for the second instance |
957 | // before starting it, to check that it's reused correctly. |
958 | oldMachineGroup := createGroup(c, ec2conn, groups[2].Name, "old machine group") |
959 | |
960 | inst1 := testing.StartInstance(c, t.Env, "99") |
961 | - defer t.Env.StopInstances([]environs.Instance{inst1}) |
962 | + defer t.Env.StopInstances([]instance.Instance{inst1}) |
963 | |
964 | groupsResp, err := ec2conn.SecurityGroups(groups, nil) |
965 | c.Assert(err, IsNil) |
966 | @@ -314,10 +315,10 @@ |
967 | inst1 := ec2.FabricateInstance(inst0, "i-aaaaaaaa") |
968 | inst2 := testing.StartInstance(c, t.Env, "41") |
969 | |
970 | - err := t.Env.StopInstances([]environs.Instance{inst0, inst1, inst2}) |
971 | + err := t.Env.StopInstances([]instance.Instance{inst0, inst1, inst2}) |
972 | c.Check(err, IsNil) |
973 | |
974 | - var insts []environs.Instance |
975 | + var insts []instance.Instance |
976 | |
977 | // We need the retry logic here because we are waiting |
978 | // for Instances to return an error, and it will not retry |
979 | |
980 | === modified file 'environs/interface.go' |
981 | --- environs/interface.go 2013-06-10 10:30:13 +0000 |
982 | +++ environs/interface.go 2013-06-17 04:13:30 +0000 |
983 | @@ -8,6 +8,7 @@ |
984 | "io" |
985 | "launchpad.net/juju-core/constraints" |
986 | "launchpad.net/juju-core/environs/config" |
987 | + "launchpad.net/juju-core/instance" |
988 | "launchpad.net/juju-core/state" |
989 | "launchpad.net/juju-core/state/api" |
990 | "launchpad.net/juju-core/state/api/params" |
991 | @@ -49,36 +50,6 @@ |
992 | InstanceId() (state.InstanceId, error) |
993 | } |
994 | |
995 | -var ErrNoDNSName = errors.New("DNS name not allocated") |
996 | - |
997 | -// Instance represents the provider-specific notion of a machine. |
998 | -type Instance interface { |
999 | - // Id returns a provider-generated identifier for the Instance. |
1000 | - Id() state.InstanceId |
1001 | - |
1002 | - // DNSName returns the DNS name for the instance. |
1003 | - // If the name is not yet allocated, it will return |
1004 | - // an ErrNoDNSName error. |
1005 | - DNSName() (string, error) |
1006 | - |
1007 | - // WaitDNSName returns the DNS name for the instance, |
1008 | - // waiting until it is allocated if necessary. |
1009 | - WaitDNSName() (string, error) |
1010 | - |
1011 | - // OpenPorts opens the given ports on the instance, which |
1012 | - // should have been started with the given machine id. |
1013 | - OpenPorts(machineId string, ports []params.Port) error |
1014 | - |
1015 | - // ClosePorts closes the given ports on the instance, which |
1016 | - // should have been started with the given machine id. |
1017 | - ClosePorts(machineId string, ports []params.Port) error |
1018 | - |
1019 | - // Ports returns the set of ports open on the instance, which |
1020 | - // should have been started with the given machine id. |
1021 | - // The ports are returned as sorted by state.SortPorts. |
1022 | - Ports(machineId string) ([]params.Port, error) |
1023 | -} |
1024 | - |
1025 | var ErrNoInstances = errors.New("no instances found") |
1026 | var ErrPartialInstances = errors.New("only some instances were found") |
1027 | |
1028 | @@ -164,10 +135,10 @@ |
1029 | // which must be unique within an environment, is used by juju to |
1030 | // protect against the consequences of multiple instances being |
1031 | // started with the same machine id. |
1032 | - StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (Instance, error) |
1033 | + StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (instance.Instance, error) |
1034 | |
1035 | // StopInstances shuts down the given instances. |
1036 | - StopInstances([]Instance) error |
1037 | + StopInstances([]instance.Instance) error |
1038 | |
1039 | // Instances returns a slice of instances corresponding to the |
1040 | // given instance ids. If no instances were found, but there |
1041 | @@ -175,11 +146,11 @@ |
1042 | // some but not all the instances were found, the returned slice |
1043 | // will have some nil slots, and an ErrPartialInstances error |
1044 | // will be returned. |
1045 | - Instances(ids []state.InstanceId) ([]Instance, error) |
1046 | + Instances(ids []state.InstanceId) ([]instance.Instance, error) |
1047 | |
1048 | // AllInstances returns all instances currently known to the |
1049 | // environment. |
1050 | - AllInstances() ([]Instance, error) |
1051 | + AllInstances() ([]instance.Instance, error) |
1052 | |
1053 | // Storage returns storage specific to the environment. |
1054 | Storage() Storage |
1055 | @@ -196,7 +167,7 @@ |
1056 | // |
1057 | // When Destroy has been called, any Environ referring to the |
1058 | // same remote environment may become invalid |
1059 | - Destroy(insts []Instance) error |
1060 | + Destroy(insts []instance.Instance) error |
1061 | |
1062 | // OpenPorts opens the given ports for the whole environment. |
1063 | // Must only be used if the environment was setup with the |
1064 | |
1065 | === modified file 'environs/jujutest/livetests.go' |
1066 | --- environs/jujutest/livetests.go 2013-05-30 00:47:30 +0000 |
1067 | +++ environs/jujutest/livetests.go 2013-06-17 04:13:30 +0000 |
1068 | @@ -14,6 +14,7 @@ |
1069 | "launchpad.net/juju-core/environs/config" |
1070 | "launchpad.net/juju-core/environs/tools" |
1071 | "launchpad.net/juju-core/errors" |
1072 | + "launchpad.net/juju-core/instance" |
1073 | "launchpad.net/juju-core/juju" |
1074 | "launchpad.net/juju-core/juju/testing" |
1075 | "launchpad.net/juju-core/state" |
1076 | @@ -142,7 +143,7 @@ |
1077 | c.Check(insts[0].Id(), Equals, id0) |
1078 | c.Check(insts[1], IsNil) |
1079 | |
1080 | - err = t.Env.StopInstances([]environs.Instance{inst}) |
1081 | + err = t.Env.StopInstances([]instance.Instance{inst}) |
1082 | c.Assert(err, IsNil) |
1083 | |
1084 | // The machine may not be marked as shutting down |
1085 | @@ -160,7 +161,7 @@ |
1086 | func (t *LiveTests) TestPorts(c *C) { |
1087 | inst1 := testing.StartInstance(c, t.Env, "1") |
1088 | c.Assert(inst1, NotNil) |
1089 | - defer t.Env.StopInstances([]environs.Instance{inst1}) |
1090 | + defer t.Env.StopInstances([]instance.Instance{inst1}) |
1091 | ports, err := inst1.Ports("1") |
1092 | c.Assert(err, IsNil) |
1093 | c.Assert(ports, HasLen, 0) |
1094 | @@ -170,7 +171,7 @@ |
1095 | ports, err = inst2.Ports("2") |
1096 | c.Assert(err, IsNil) |
1097 | c.Assert(ports, HasLen, 0) |
1098 | - defer t.Env.StopInstances([]environs.Instance{inst2}) |
1099 | + defer t.Env.StopInstances([]instance.Instance{inst2}) |
1100 | |
1101 | // Open some ports and check they're there. |
1102 | err = inst1.OpenPorts("1", []params.Port{{"udp", 67}, {"tcp", 45}}) |
1103 | @@ -260,7 +261,7 @@ |
1104 | |
1105 | // Create instances and check open ports on both instances. |
1106 | inst1 := testing.StartInstance(c, t.Env, "1") |
1107 | - defer t.Env.StopInstances([]environs.Instance{inst1}) |
1108 | + defer t.Env.StopInstances([]instance.Instance{inst1}) |
1109 | ports, err := t.Env.Ports() |
1110 | c.Assert(err, IsNil) |
1111 | c.Assert(ports, HasLen, 0) |
1112 | @@ -269,7 +270,7 @@ |
1113 | ports, err = t.Env.Ports() |
1114 | c.Assert(err, IsNil) |
1115 | c.Assert(ports, HasLen, 0) |
1116 | - defer t.Env.StopInstances([]environs.Instance{inst2}) |
1117 | + defer t.Env.StopInstances([]instance.Instance{inst2}) |
1118 | |
1119 | err = t.Env.OpenPorts([]params.Port{{"udp", 67}, {"tcp", 45}, {"tcp", 89}, {"tcp", 99}}) |
1120 | c.Assert(err, IsNil) |
1121 | @@ -630,7 +631,7 @@ |
1122 | // assertInstanceId asserts that the machine has an instance id |
1123 | // that matches that of the given instance. If the instance is nil, |
1124 | // It asserts that the instance id is unset. |
1125 | -func assertInstanceId(c *C, m *state.Machine, inst environs.Instance) { |
1126 | +func assertInstanceId(c *C, m *state.Machine, inst instance.Instance) { |
1127 | var wantId, gotId state.InstanceId |
1128 | var err error |
1129 | if inst != nil { |
1130 | @@ -700,7 +701,7 @@ |
1131 | func (t *LiveTests) TestStartInstanceOnUnknownPlatform(c *C) { |
1132 | inst, err := t.Env.StartInstance("4", "fake_nonce", "unknownseries", constraints.Value{}, testing.InvalidStateInfo("4"), testing.InvalidAPIInfo("4")) |
1133 | if inst != nil { |
1134 | - err := t.Env.StopInstances([]environs.Instance{inst}) |
1135 | + err := t.Env.StopInstances([]instance.Instance{inst}) |
1136 | c.Check(err, IsNil) |
1137 | } |
1138 | c.Assert(inst, IsNil) |
1139 | @@ -713,7 +714,7 @@ |
1140 | func (t *LiveTests) TestStartInstanceWithEmptyNonceFails(c *C) { |
1141 | inst, err := t.Env.StartInstance("4", "", config.DefaultSeries, constraints.Value{}, testing.InvalidStateInfo("4"), testing.InvalidAPIInfo("4")) |
1142 | if inst != nil { |
1143 | - err := t.Env.StopInstances([]environs.Instance{inst}) |
1144 | + err := t.Env.StopInstances([]instance.Instance{inst}) |
1145 | c.Check(err, IsNil) |
1146 | } |
1147 | c.Assert(inst, IsNil) |
1148 | |
1149 | === modified file 'environs/jujutest/tests.go' |
1150 | --- environs/jujutest/tests.go 2013-05-30 00:47:30 +0000 |
1151 | +++ environs/jujutest/tests.go 2013-06-17 04:13:30 +0000 |
1152 | @@ -12,6 +12,7 @@ |
1153 | "launchpad.net/juju-core/environs" |
1154 | envtesting "launchpad.net/juju-core/environs/testing" |
1155 | "launchpad.net/juju-core/errors" |
1156 | + "launchpad.net/juju-core/instance" |
1157 | "launchpad.net/juju-core/juju/testing" |
1158 | "launchpad.net/juju-core/state" |
1159 | coretesting "launchpad.net/juju-core/testing" |
1160 | @@ -107,7 +108,7 @@ |
1161 | c.Assert(insts, HasLen, 2) |
1162 | c.Assert(insts[0].Id(), Not(Equals), insts[1].Id()) |
1163 | |
1164 | - err = e.StopInstances([]environs.Instance{inst0}) |
1165 | + err = e.StopInstances([]instance.Instance{inst0}) |
1166 | c.Assert(err, IsNil) |
1167 | |
1168 | insts, err = e.Instances([]state.InstanceId{id0, id1}) |
1169 | |
1170 | === modified file 'environs/maas/environ.go' |
1171 | --- environs/maas/environ.go 2013-06-10 10:30:13 +0000 |
1172 | +++ environs/maas/environ.go 2013-06-17 04:13:30 +0000 |
1173 | @@ -13,6 +13,7 @@ |
1174 | "launchpad.net/juju-core/environs/cloudinit" |
1175 | "launchpad.net/juju-core/environs/config" |
1176 | "launchpad.net/juju-core/environs/tools" |
1177 | + "launchpad.net/juju-core/instance" |
1178 | "launchpad.net/juju-core/log" |
1179 | "launchpad.net/juju-core/state" |
1180 | "launchpad.net/juju-core/state/api" |
1181 | @@ -84,7 +85,7 @@ |
1182 | } |
1183 | |
1184 | // startBootstrapNode starts the juju bootstrap node for this environment. |
1185 | -func (env *maasEnviron) startBootstrapNode(cons constraints.Value) (environs.Instance, error) { |
1186 | +func (env *maasEnviron) startBootstrapNode(cons constraints.Value) (instance.Instance, error) { |
1187 | // The bootstrap instance gets machine id "0". This is not related to |
1188 | // instance ids or MAAS system ids. Juju assigns the machine ID. |
1189 | const machineID = "0" |
1190 | @@ -352,7 +353,7 @@ |
1191 | } |
1192 | |
1193 | // StartInstance is specified in the Environ interface. |
1194 | -func (environ *maasEnviron) StartInstance(machineID, machineNonce string, series string, cons constraints.Value, stateInfo *state.Info, apiInfo *api.Info) (environs.Instance, error) { |
1195 | +func (environ *maasEnviron) StartInstance(machineID, machineNonce string, series string, cons constraints.Value, stateInfo *state.Info, apiInfo *api.Info) (instance.Instance, error) { |
1196 | possibleTools, err := environs.FindInstanceTools(environ, series, cons) |
1197 | if err != nil { |
1198 | return nil, err |
1199 | @@ -362,7 +363,7 @@ |
1200 | } |
1201 | |
1202 | // StopInstances is specified in the Environ interface. |
1203 | -func (environ *maasEnviron) StopInstances(instances []environs.Instance) error { |
1204 | +func (environ *maasEnviron) StopInstances(instances []instance.Instance) error { |
1205 | // Shortcut to exit quickly if 'instances' is an empty slice or nil. |
1206 | if len(instances) == 0 { |
1207 | return nil |
1208 | @@ -381,7 +382,7 @@ |
1209 | } |
1210 | |
1211 | // releaseInstance releases a single instance. |
1212 | -func (environ *maasEnviron) releaseInstance(inst environs.Instance) error { |
1213 | +func (environ *maasEnviron) releaseInstance(inst instance.Instance) error { |
1214 | maasInst := inst.(*maasInstance) |
1215 | maasObj := maasInst.maasObject |
1216 | _, err := maasObj.CallPost("release", nil) |
1217 | @@ -391,10 +392,10 @@ |
1218 | return err |
1219 | } |
1220 | |
1221 | -// Instances returns the environs.Instance objects corresponding to the given |
1222 | +// Instances returns the instance.Instance objects corresponding to the given |
1223 | // slice of state.InstanceId. Similar to what the ec2 provider does, |
1224 | // Instances returns nil if the given slice is empty or nil. |
1225 | -func (environ *maasEnviron) Instances(ids []state.InstanceId) ([]environs.Instance, error) { |
1226 | +func (environ *maasEnviron) Instances(ids []state.InstanceId) ([]instance.Instance, error) { |
1227 | if len(ids) == 0 { |
1228 | return nil, nil |
1229 | } |
1230 | @@ -406,7 +407,7 @@ |
1231 | // If the some of the intances could not be found, it returns the instance |
1232 | // that could be found plus the error environs.ErrPartialInstances in the error |
1233 | // return. |
1234 | -func (environ *maasEnviron) instances(ids []state.InstanceId) ([]environs.Instance, error) { |
1235 | +func (environ *maasEnviron) instances(ids []state.InstanceId) ([]instance.Instance, error) { |
1236 | nodeListing := environ.getMAASClient().GetSubObject("nodes") |
1237 | filter := getSystemIdValues(ids) |
1238 | listNodeObjects, err := nodeListing.CallGet("list", filter) |
1239 | @@ -417,7 +418,7 @@ |
1240 | if err != nil { |
1241 | return nil, err |
1242 | } |
1243 | - instances := make([]environs.Instance, len(listNodes)) |
1244 | + instances := make([]instance.Instance, len(listNodes)) |
1245 | for index, nodeObj := range listNodes { |
1246 | node, err := nodeObj.GetMAASObject() |
1247 | if err != nil { |
1248 | @@ -434,8 +435,8 @@ |
1249 | return instances, nil |
1250 | } |
1251 | |
1252 | -// AllInstances returns all the environs.Instance in this provider. |
1253 | -func (environ *maasEnviron) AllInstances() ([]environs.Instance, error) { |
1254 | +// AllInstances returns all the instance.Instance in this provider. |
1255 | +func (environ *maasEnviron) AllInstances() ([]instance.Instance, error) { |
1256 | return environ.instances(nil) |
1257 | } |
1258 | |
1259 | @@ -452,7 +453,7 @@ |
1260 | return environs.EmptyStorage |
1261 | } |
1262 | |
1263 | -func (environ *maasEnviron) Destroy(ensureInsts []environs.Instance) error { |
1264 | +func (environ *maasEnviron) Destroy(ensureInsts []instance.Instance) error { |
1265 | log.Debugf("environs/maas: destroying environment %q", environ.name) |
1266 | insts, err := environ.AllInstances() |
1267 | if err != nil { |
1268 | |
1269 | === modified file 'environs/maas/environ_test.go' |
1270 | --- environs/maas/environ_test.go 2013-06-10 10:30:13 +0000 |
1271 | +++ environs/maas/environ_test.go 2013-06-17 04:13:30 +0000 |
1272 | @@ -15,6 +15,7 @@ |
1273 | envtesting "launchpad.net/juju-core/environs/testing" |
1274 | "launchpad.net/juju-core/environs/tools" |
1275 | "launchpad.net/juju-core/errors" |
1276 | + "launchpad.net/juju-core/instance" |
1277 | "launchpad.net/juju-core/state" |
1278 | "launchpad.net/juju-core/testing" |
1279 | "launchpad.net/juju-core/utils" |
1280 | @@ -344,7 +345,7 @@ |
1281 | func (suite *EnvironSuite) TestStopInstancesReturnsIfParameterEmpty(c *C) { |
1282 | suite.getInstance("test1") |
1283 | |
1284 | - err := suite.environ.StopInstances([]environs.Instance{}) |
1285 | + err := suite.environ.StopInstances([]instance.Instance{}) |
1286 | c.Check(err, IsNil) |
1287 | operations := suite.testMAASObject.TestServer.NodeOperations() |
1288 | c.Check(operations, DeepEquals, map[string][]string{}) |
1289 | @@ -354,7 +355,7 @@ |
1290 | instance1 := suite.getInstance("test1") |
1291 | instance2 := suite.getInstance("test2") |
1292 | suite.getInstance("test3") |
1293 | - instances := []environs.Instance{instance1, instance2} |
1294 | + instances := []instance.Instance{instance1, instance2} |
1295 | |
1296 | err := suite.environ.StopInstances(instances) |
1297 | |
1298 | @@ -394,12 +395,12 @@ |
1299 | func (suite *EnvironSuite) TestDestroy(c *C) { |
1300 | env := suite.makeEnviron() |
1301 | suite.getInstance("test1") |
1302 | - instance := suite.getInstance("test2") |
1303 | + testInstance := suite.getInstance("test2") |
1304 | data := makeRandomBytes(10) |
1305 | suite.testMAASObject.TestServer.NewFile("filename", data) |
1306 | storage := env.Storage() |
1307 | |
1308 | - err := env.Destroy([]environs.Instance{instance}) |
1309 | + err := env.Destroy([]instance.Instance{testInstance}) |
1310 | |
1311 | c.Check(err, IsNil) |
1312 | // Instances have been stopped. |
1313 | |
1314 | === modified file 'environs/maas/instance.go' |
1315 | --- environs/maas/instance.go 2013-05-02 15:55:42 +0000 |
1316 | +++ environs/maas/instance.go 2013-06-17 04:13:30 +0000 |
1317 | @@ -5,7 +5,7 @@ |
1318 | |
1319 | import ( |
1320 | "launchpad.net/gomaasapi" |
1321 | - "launchpad.net/juju-core/environs" |
1322 | + "launchpad.net/juju-core/instance" |
1323 | "launchpad.net/juju-core/log" |
1324 | "launchpad.net/juju-core/state" |
1325 | "launchpad.net/juju-core/state/api/params" |
1326 | @@ -16,7 +16,7 @@ |
1327 | environ *maasEnviron |
1328 | } |
1329 | |
1330 | -var _ environs.Instance = (*maasInstance)(nil) |
1331 | +var _ instance.Instance = (*maasInstance)(nil) |
1332 | |
1333 | func (instance *maasInstance) Id() state.InstanceId { |
1334 | // Use the node's 'resource_uri' value. |
1335 | |
1336 | === modified file 'environs/openstack/local_test.go' |
1337 | --- environs/openstack/local_test.go 2013-05-28 08:05:49 +0000 |
1338 | +++ environs/openstack/local_test.go 2013-06-17 04:13:30 +0000 |
1339 | @@ -17,6 +17,7 @@ |
1340 | "launchpad.net/juju-core/environs/jujutest" |
1341 | "launchpad.net/juju-core/environs/openstack" |
1342 | envtesting "launchpad.net/juju-core/environs/testing" |
1343 | + "launchpad.net/juju-core/instance" |
1344 | "launchpad.net/juju-core/juju/testing" |
1345 | "launchpad.net/juju-core/state" |
1346 | coretesting "launchpad.net/juju-core/testing" |
1347 | @@ -281,7 +282,7 @@ |
1348 | err = environs.Bootstrap(env, constraints.Value{}) |
1349 | c.Assert(err, IsNil) |
1350 | inst := testing.StartInstance(c, env, "100") |
1351 | - err = s.Env.StopInstances([]environs.Instance{inst}) |
1352 | + err = s.Env.StopInstances([]instance.Instance{inst}) |
1353 | c.Assert(err, IsNil) |
1354 | } |
1355 | |
1356 | @@ -338,7 +339,7 @@ |
1357 | inst1 := testing.StartInstance(c, s.Env, "101") |
1358 | id1 := inst1.Id() |
1359 | defer func() { |
1360 | - err := s.Env.StopInstances([]environs.Instance{inst0, inst1}) |
1361 | + err := s.Env.StopInstances([]instance.Instance{inst0, inst1}) |
1362 | c.Assert(err, IsNil) |
1363 | }() |
1364 | |
1365 | |
1366 | === modified file 'environs/openstack/provider.go' |
1367 | --- environs/openstack/provider.go 2013-06-10 10:30:13 +0000 |
1368 | +++ environs/openstack/provider.go 2013-06-17 04:13:30 +0000 |
1369 | @@ -23,6 +23,7 @@ |
1370 | "launchpad.net/juju-core/environs/instances" |
1371 | "launchpad.net/juju-core/environs/tools" |
1372 | coreerrors "launchpad.net/juju-core/errors" |
1373 | + "launchpad.net/juju-core/instance" |
1374 | "launchpad.net/juju-core/log" |
1375 | "launchpad.net/juju-core/state" |
1376 | "launchpad.net/juju-core/state/api" |
1377 | @@ -270,19 +271,19 @@ |
1378 | |
1379 | var _ environs.Environ = (*environ)(nil) |
1380 | |
1381 | -type instance struct { |
1382 | +type openstackInstance struct { |
1383 | e *environ |
1384 | *nova.ServerDetail |
1385 | address string |
1386 | } |
1387 | |
1388 | -func (inst *instance) String() string { |
1389 | +func (inst *openstackInstance) String() string { |
1390 | return inst.ServerDetail.Id |
1391 | } |
1392 | |
1393 | -var _ environs.Instance = (*instance)(nil) |
1394 | +var _ instance.Instance = (*openstackInstance)(nil) |
1395 | |
1396 | -func (inst *instance) Id() state.InstanceId { |
1397 | +func (inst *openstackInstance) Id() state.InstanceId { |
1398 | return state.InstanceId(inst.ServerDetail.Id) |
1399 | } |
1400 | |
1401 | @@ -319,12 +320,12 @@ |
1402 | public = private |
1403 | } |
1404 | if public == "" { |
1405 | - return "", environs.ErrNoDNSName |
1406 | + return "", instance.ErrNoDNSName |
1407 | } |
1408 | return public, nil |
1409 | } |
1410 | |
1411 | -func (inst *instance) DNSName() (string, error) { |
1412 | +func (inst *openstackInstance) DNSName() (string, error) { |
1413 | if inst.address != "" { |
1414 | return inst.address, nil |
1415 | } |
1416 | @@ -341,10 +342,10 @@ |
1417 | return inst.address, nil |
1418 | } |
1419 | |
1420 | -func (inst *instance) WaitDNSName() (string, error) { |
1421 | +func (inst *openstackInstance) WaitDNSName() (string, error) { |
1422 | for a := longAttempt.Start(); a.Next(); { |
1423 | addr, err := inst.DNSName() |
1424 | - if err == nil || err != environs.ErrNoDNSName { |
1425 | + if err == nil || err != instance.ErrNoDNSName { |
1426 | return addr, err |
1427 | } |
1428 | } |
1429 | @@ -353,7 +354,7 @@ |
1430 | |
1431 | // TODO: following 30 lines nearly verbatim from environs/ec2 |
1432 | |
1433 | -func (inst *instance) OpenPorts(machineId string, ports []params.Port) error { |
1434 | +func (inst *openstackInstance) OpenPorts(machineId string, ports []params.Port) error { |
1435 | if inst.e.Config().FirewallMode() != config.FwInstance { |
1436 | return fmt.Errorf("invalid firewall mode for opening ports on instance: %q", |
1437 | inst.e.Config().FirewallMode()) |
1438 | @@ -366,7 +367,7 @@ |
1439 | return nil |
1440 | } |
1441 | |
1442 | -func (inst *instance) ClosePorts(machineId string, ports []params.Port) error { |
1443 | +func (inst *openstackInstance) ClosePorts(machineId string, ports []params.Port) error { |
1444 | if inst.e.Config().FirewallMode() != config.FwInstance { |
1445 | return fmt.Errorf("invalid firewall mode for closing ports on instance: %q", |
1446 | inst.e.Config().FirewallMode()) |
1447 | @@ -379,7 +380,7 @@ |
1448 | return nil |
1449 | } |
1450 | |
1451 | -func (inst *instance) Ports(machineId string) ([]params.Port, error) { |
1452 | +func (inst *openstackInstance) Ports(machineId string) ([]params.Port, error) { |
1453 | if inst.e.Config().FirewallMode() != config.FwInstance { |
1454 | return nil, fmt.Errorf("invalid firewall mode for retrieving ports from instance: %q", |
1455 | inst.e.Config().FirewallMode()) |
1456 | @@ -507,7 +508,7 @@ |
1457 | if err != nil { |
1458 | // ignore error on StopInstance because the previous error is |
1459 | // more important. |
1460 | - e.StopInstances([]environs.Instance{inst}) |
1461 | + e.StopInstances([]instance.Instance{inst}) |
1462 | return fmt.Errorf("cannot save state: %v", err) |
1463 | } |
1464 | // TODO make safe in the case of racing Bootstraps |
1465 | @@ -545,7 +546,7 @@ |
1466 | if inst == nil { |
1467 | continue |
1468 | } |
1469 | - name, err := inst.(*instance).DNSName() |
1470 | + name, err := inst.(*openstackInstance).DNSName() |
1471 | if err != nil { |
1472 | continue |
1473 | } |
1474 | @@ -657,7 +658,7 @@ |
1475 | return e.imageBaseURLs, nil |
1476 | } |
1477 | |
1478 | -func (e *environ) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (environs.Instance, error) { |
1479 | +func (e *environ) StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (instance.Instance, error) { |
1480 | possibleTools, err := environs.FindInstanceTools(e, series, cons) |
1481 | if err != nil { |
1482 | return nil, err |
1483 | @@ -767,7 +768,7 @@ |
1484 | |
1485 | // startInstance is the internal version of StartInstance, used by Bootstrap |
1486 | // as well as via StartInstance itself. |
1487 | -func (e *environ) startInstance(scfg *startInstanceParams) (environs.Instance, error) { |
1488 | +func (e *environ) startInstance(scfg *startInstanceParams) (instance.Instance, error) { |
1489 | series := scfg.possibleTools.Series() |
1490 | if len(series) != 1 { |
1491 | return nil, fmt.Errorf("expected single series, got %v", series) |
1492 | @@ -832,7 +833,7 @@ |
1493 | if err != nil { |
1494 | return nil, fmt.Errorf("cannot get started instance: %v", err) |
1495 | } |
1496 | - inst := &instance{e, detail, ""} |
1497 | + inst := &openstackInstance{e, detail, ""} |
1498 | log.Infof("environs/openstack: started instance %q", inst.Id()) |
1499 | if scfg.withPublicIP { |
1500 | if err := e.assignPublicIP(publicIP, string(inst.Id())); err != nil { |
1501 | @@ -847,12 +848,12 @@ |
1502 | return inst, nil |
1503 | } |
1504 | |
1505 | -func (e *environ) StopInstances(insts []environs.Instance) error { |
1506 | +func (e *environ) StopInstances(insts []instance.Instance) error { |
1507 | ids := make([]state.InstanceId, len(insts)) |
1508 | for i, inst := range insts { |
1509 | - instanceValue, ok := inst.(*instance) |
1510 | + instanceValue, ok := inst.(*openstackInstance) |
1511 | if !ok { |
1512 | - return errors.New("Incompatible environs.Instance supplied") |
1513 | + return errors.New("Incompatible instance.Instance supplied") |
1514 | } |
1515 | ids[i] = instanceValue.Id() |
1516 | } |
1517 | @@ -863,7 +864,7 @@ |
1518 | // collectInstances tries to get information on each instance id in ids. |
1519 | // It fills the slots in the given map for known servers with status |
1520 | // either ACTIVE or BUILD. Returns a list of missing ids. |
1521 | -func (e *environ) collectInstances(ids []state.InstanceId, out map[state.InstanceId]environs.Instance) []state.InstanceId { |
1522 | +func (e *environ) collectInstances(ids []state.InstanceId, out map[state.InstanceId]instance.Instance) []state.InstanceId { |
1523 | var err error |
1524 | serversById := make(map[string]nova.ServerDetail) |
1525 | if len(ids) == 1 { |
1526 | @@ -887,7 +888,7 @@ |
1527 | for _, id := range ids { |
1528 | if server, found := serversById[string(id)]; found { |
1529 | if server.Status == nova.StatusActive || server.Status == nova.StatusBuild { |
1530 | - out[id] = &instance{e, &server, ""} |
1531 | + out[id] = &openstackInstance{e, &server, ""} |
1532 | } |
1533 | continue |
1534 | } |
1535 | @@ -896,12 +897,12 @@ |
1536 | return missing |
1537 | } |
1538 | |
1539 | -func (e *environ) Instances(ids []state.InstanceId) ([]environs.Instance, error) { |
1540 | +func (e *environ) Instances(ids []state.InstanceId) ([]instance.Instance, error) { |
1541 | if len(ids) == 0 { |
1542 | return nil, nil |
1543 | } |
1544 | missing := ids |
1545 | - found := make(map[state.InstanceId]environs.Instance) |
1546 | + found := make(map[state.InstanceId]instance.Instance) |
1547 | // Make a series of requests to cope with eventual consistency. |
1548 | // Each request will attempt to add more instances to the requested |
1549 | // set. |
1550 | @@ -913,7 +914,7 @@ |
1551 | if len(found) == 0 { |
1552 | return nil, environs.ErrNoInstances |
1553 | } |
1554 | - insts := make([]environs.Instance, len(ids)) |
1555 | + insts := make([]instance.Instance, len(ids)) |
1556 | var err error |
1557 | for i, id := range ids { |
1558 | if inst := found[id]; inst != nil { |
1559 | @@ -925,7 +926,7 @@ |
1560 | return insts, err |
1561 | } |
1562 | |
1563 | -func (e *environ) AllInstances() (insts []environs.Instance, err error) { |
1564 | +func (e *environ) AllInstances() (insts []instance.Instance, err error) { |
1565 | servers, err := e.nova().ListServersDetail(e.machinesFilter()) |
1566 | if err != nil { |
1567 | return nil, err |
1568 | @@ -933,13 +934,13 @@ |
1569 | for _, server := range servers { |
1570 | if server.Status == nova.StatusActive || server.Status == nova.StatusBuild { |
1571 | var s = server |
1572 | - insts = append(insts, &instance{e, &s, ""}) |
1573 | + insts = append(insts, &openstackInstance{e, &s, ""}) |
1574 | } |
1575 | } |
1576 | return insts, err |
1577 | } |
1578 | |
1579 | -func (e *environ) Destroy(ensureInsts []environs.Instance) error { |
1580 | +func (e *environ) Destroy(ensureInsts []instance.Instance) error { |
1581 | log.Infof("environs/openstack: destroying environment %q", e.name) |
1582 | insts, err := e.AllInstances() |
1583 | if err != nil { |
1584 | @@ -955,7 +956,7 @@ |
1585 | // Add any instances we've been told about but haven't yet shown |
1586 | // up in the instance list. |
1587 | for _, inst := range ensureInsts { |
1588 | - id := state.InstanceId(inst.(*instance).Id()) |
1589 | + id := state.InstanceId(inst.(*openstackInstance).Id()) |
1590 | if !found[id] { |
1591 | ids = append(ids, id) |
1592 | found[id] = true |
1593 | |
1594 | === modified file 'environs/openstack/provider_test.go' |
1595 | --- environs/openstack/provider_test.go 2013-05-20 00:10:30 +0000 |
1596 | +++ environs/openstack/provider_test.go 2013-06-17 04:13:30 +0000 |
1597 | @@ -8,8 +8,8 @@ |
1598 | . "launchpad.net/gocheck" |
1599 | "launchpad.net/goose/identity" |
1600 | "launchpad.net/goose/nova" |
1601 | - "launchpad.net/juju-core/environs" |
1602 | "launchpad.net/juju-core/environs/openstack" |
1603 | + "launchpad.net/juju-core/instance" |
1604 | "testing" |
1605 | ) |
1606 | |
1607 | @@ -44,14 +44,14 @@ |
1608 | { |
1609 | summary: "missing", |
1610 | expected: "", |
1611 | - failure: environs.ErrNoDNSName, |
1612 | + failure: instance.ErrNoDNSName, |
1613 | }, |
1614 | { |
1615 | summary: "empty", |
1616 | private: []nova.IPAddress{}, |
1617 | networks: []string{"private"}, |
1618 | expected: "", |
1619 | - failure: environs.ErrNoDNSName, |
1620 | + failure: instance.ErrNoDNSName, |
1621 | }, |
1622 | { |
1623 | summary: "private only", |
1624 | @@ -110,7 +110,7 @@ |
1625 | private: []nova.IPAddress{{6, "::dead:beef:f00d"}}, |
1626 | networks: []string{"private"}, |
1627 | expected: "", |
1628 | - failure: environs.ErrNoDNSName, |
1629 | + failure: instance.ErrNoDNSName, |
1630 | }, |
1631 | } |
1632 | |
1633 | |
1634 | === added directory 'instance' |
1635 | === added file 'instance/instance.go' |
1636 | --- instance/instance.go 1970-01-01 00:00:00 +0000 |
1637 | +++ instance/instance.go 2013-06-17 04:13:30 +0000 |
1638 | @@ -0,0 +1,41 @@ |
1639 | +// Copyright 2013 Canonical Ltd. |
1640 | +// Licensed under the AGPLv3, see LICENCE file for details. |
1641 | + |
1642 | +package instance |
1643 | + |
1644 | +import ( |
1645 | + "errors" |
1646 | + |
1647 | + "launchpad.net/juju-core/state" |
1648 | + "launchpad.net/juju-core/state/api/params" |
1649 | +) |
1650 | + |
1651 | +var ErrNoDNSName = errors.New("DNS name not allocated") |
1652 | + |
1653 | +// Instance represents the the realization of a machine in state. |
1654 | +type Instance interface { |
1655 | + // Id returns a provider-generated identifier for the Instance. |
1656 | + Id() state.InstanceId |
1657 | + |
1658 | + // DNSName returns the DNS name for the instance. |
1659 | + // If the name is not yet allocated, it will return |
1660 | + // an ErrNoDNSName error. |
1661 | + DNSName() (string, error) |
1662 | + |
1663 | + // WaitDNSName returns the DNS name for the instance, |
1664 | + // waiting until it is allocated if necessary. |
1665 | + WaitDNSName() (string, error) |
1666 | + |
1667 | + // OpenPorts opens the given ports on the instance, which |
1668 | + // should have been started with the given machine id. |
1669 | + OpenPorts(machineId string, ports []params.Port) error |
1670 | + |
1671 | + // ClosePorts closes the given ports on the instance, which |
1672 | + // should have been started with the given machine id. |
1673 | + ClosePorts(machineId string, ports []params.Port) error |
1674 | + |
1675 | + // Ports returns the set of ports open on the instance, which |
1676 | + // should have been started with the given machine id. |
1677 | + // The ports are returned as sorted by state.SortPorts. |
1678 | + Ports(machineId string) ([]params.Port, error) |
1679 | +} |
1680 | |
1681 | === modified file 'juju/testing/conn.go' |
1682 | --- juju/testing/conn.go 2013-05-02 15:55:42 +0000 |
1683 | +++ juju/testing/conn.go 2013-06-17 04:13:30 +0000 |
1684 | @@ -12,6 +12,7 @@ |
1685 | "launchpad.net/juju-core/environs" |
1686 | "launchpad.net/juju-core/environs/config" |
1687 | "launchpad.net/juju-core/environs/dummy" |
1688 | + "launchpad.net/juju-core/instance" |
1689 | "launchpad.net/juju-core/juju" |
1690 | "launchpad.net/juju-core/state" |
1691 | "launchpad.net/juju-core/state/api" |
1692 | @@ -77,7 +78,7 @@ |
1693 | |
1694 | // StartInstance is a test helper function that starts an instance on the |
1695 | // environment using the current series and invalid info states. |
1696 | -func StartInstance(c *C, env environs.Environ, machineId string) environs.Instance { |
1697 | +func StartInstance(c *C, env environs.Environ, machineId string) instance.Instance { |
1698 | series := config.DefaultSeries |
1699 | inst, err := env.StartInstance( |
1700 | machineId, |
1701 | |
1702 | === modified file 'state/container.go' |
1703 | --- state/container.go 2013-06-11 22:40:34 +0000 |
1704 | +++ state/container.go 2013-06-17 04:13:30 +0000 |
1705 | @@ -88,9 +88,9 @@ |
1706 | return ops |
1707 | } |
1708 | |
1709 | -// parentId returns the id of the host machine if machineId a container id, or "" |
1710 | +// ParentId returns the id of the host machine if machineId a container id, or "" |
1711 | // if machineId is not for a container. |
1712 | -func parentId(machineId string) string { |
1713 | +func ParentId(machineId string) string { |
1714 | idParts := strings.Split(machineId, "/") |
1715 | if len(idParts) < 3 { |
1716 | return "" |
1717 | @@ -98,6 +98,18 @@ |
1718 | return strings.Join(idParts[:len(idParts)-2], "/") |
1719 | } |
1720 | |
1721 | +// NestingLevel returns how many levels of nesting exist for a machine id. |
1722 | +func NestingLevel(machineId string) int { |
1723 | + idParts := strings.Split(machineId, "/") |
1724 | + return (len(idParts) - 1) / 2 |
1725 | +} |
1726 | + |
1727 | +// TopParentId returns the id of the top level host machine for a container id. |
1728 | +func TopParentId(machineId string) string { |
1729 | + idParts := strings.Split(machineId, "/") |
1730 | + return idParts[0] |
1731 | +} |
1732 | + |
1733 | // removeContainerRefOps returns the txn.Op's necessary to remove a machine container record. |
1734 | // These include removing the record itself and updating the host machine's children property. |
1735 | func removeContainerRefOps(st *State, machineId string) []txn.Op { |
1736 | @@ -108,7 +120,7 @@ |
1737 | Remove: true, |
1738 | } |
1739 | // If the machine is a container, figure out it's parent host. |
1740 | - parentId := parentId(machineId) |
1741 | + parentId := ParentId(machineId) |
1742 | if parentId == "" { |
1743 | return []txn.Op{removeRefOp} |
1744 | } |
1745 | |
1746 | === modified file 'state/export_test.go' |
1747 | --- state/export_test.go 2013-05-02 15:55:42 +0000 |
1748 | +++ state/export_test.go 2013-06-17 04:13:30 +0000 |
1749 | @@ -93,6 +93,10 @@ |
1750 | return sch |
1751 | } |
1752 | |
1753 | +func MachineIdLessThan(id1, id2 string) bool { |
1754 | + return machineIdLessThan(id1, id2) |
1755 | +} |
1756 | + |
1757 | func init() { |
1758 | logSize = logSizeTests |
1759 | } |
1760 | |
1761 | === modified file 'state/machine.go' |
1762 | --- state/machine.go 2013-06-13 14:39:31 +0000 |
1763 | +++ state/machine.go 2013-06-17 04:13:30 +0000 |
1764 | @@ -107,15 +107,26 @@ |
1765 | return machineGlobalKey(m.doc.Id) |
1766 | } |
1767 | |
1768 | +const machineTagPrefix = "machine-" |
1769 | + |
1770 | // MachineTag returns the tag for the |
1771 | // machine with the given id. |
1772 | func MachineTag(id string) string { |
1773 | - tag := fmt.Sprintf("machine-%s", id) |
1774 | + tag := fmt.Sprintf("%s%s", machineTagPrefix, id) |
1775 | // Containers require "/" to be replaced by "-". |
1776 | tag = strings.Replace(tag, "/", "-", -1) |
1777 | return tag |
1778 | } |
1779 | |
1780 | +// MachineIdFromTag returns the machine id that was used to create the tag. |
1781 | +func MachineIdFromTag(tag string) string { |
1782 | + // Strip off the "machine-" prefix. |
1783 | + id := tag[len(machineTagPrefix):] |
1784 | + // Put the slashes back. |
1785 | + id = strings.Replace(id, "-", "/", -1) |
1786 | + return id |
1787 | +} |
1788 | + |
1789 | // Tag returns a name identifying the machine that is safe to use |
1790 | // as a file name. The returned name will be different from other |
1791 | // Tag values returned by any other entities from the same state. |
1792 | @@ -240,7 +251,7 @@ |
1793 | |
1794 | // ParentId returns the Id of the host machine if this machine is a container. |
1795 | func (m *Machine) ParentId() (string, bool) { |
1796 | - parentId := parentId(m.Id()) |
1797 | + parentId := ParentId(m.Id()) |
1798 | return parentId, parentId != "" |
1799 | } |
1800 | |
1801 | |
1802 | === modified file 'state/machine_test.go' |
1803 | --- state/machine_test.go 2013-06-12 00:01:40 +0000 |
1804 | +++ state/machine_test.go 2013-06-17 04:13:30 +0000 |
1805 | @@ -192,6 +192,15 @@ |
1806 | c.Assert(state.MachineTag("10/lxc/1"), Equals, "machine-10-lxc-1") |
1807 | } |
1808 | |
1809 | +func (s *MachineSuite) TestMachineIdFromTag(c *C) { |
1810 | + c.Assert(state.MachineIdFromTag("machine-10"), Equals, "10") |
1811 | + // Check a container id. |
1812 | + c.Assert(state.MachineIdFromTag("machine-10-lxc-1"), Equals, "10/lxc/1") |
1813 | + // Check reversability. |
1814 | + nested := "2/kvm/0/lxc/3" |
1815 | + c.Assert(state.MachineIdFromTag(state.MachineTag(nested)), Equals, nested) |
1816 | +} |
1817 | + |
1818 | func (s *MachineSuite) TestSetMongoPassword(c *C) { |
1819 | testSetMongoPassword(c, func(st *state.State) (entity, error) { |
1820 | return st.Machine(s.machine.Id()) |
1821 | |
1822 | === modified file 'state/state.go' |
1823 | --- state/state.go 2013-06-13 14:39:31 +0000 |
1824 | +++ state/state.go 2013-06-17 04:13:30 +0000 |
1825 | @@ -378,10 +378,49 @@ |
1826 | func (ms machineDocSlice) Len() int { return len(ms) } |
1827 | func (ms machineDocSlice) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] } |
1828 | func (ms machineDocSlice) Less(i, j int) bool { |
1829 | - // There's nothing we can do with errors at this point. |
1830 | - m1, _ := strconv.Atoi(ms[i].Id) |
1831 | - m2, _ := strconv.Atoi(ms[j].Id) |
1832 | - return m1 < m2 |
1833 | + return machineIdLessThan(ms[i].Id, ms[j].Id) |
1834 | +} |
1835 | + |
1836 | +// machineIdLessThan returns true if id1 < id2, false otherwise. |
1837 | +// Machine ids may include "/" separators if they are for a container so |
1838 | +// the comparison is done by comparing the id component values from |
1839 | +// left to right (most significant part to least significant). Ids for |
1840 | +// host machines are always less than ids for their containers. |
1841 | +func machineIdLessThan(id1, id2 string) bool { |
1842 | + // Most times, we are dealing with host machines and not containers, so we will |
1843 | + // try interpreting the ids as ints - this will be faster than dealing with the |
1844 | + // container ids below. |
1845 | + mint1, err1 := strconv.Atoi(id1) |
1846 | + mint2, err2 := strconv.Atoi(id2) |
1847 | + if err1 == nil && err2 == nil { |
1848 | + return mint1 < mint2 |
1849 | + } |
1850 | + // We have at least one container id so it gets complicated. |
1851 | + idParts1 := strings.Split(id1, "/") |
1852 | + idParts2 := strings.Split(id2, "/") |
1853 | + nrParts1 := len(idParts1) |
1854 | + nrParts2 := len(idParts2) |
1855 | + minLen := nrParts1 |
1856 | + if nrParts2 < minLen { |
1857 | + minLen = nrParts2 |
1858 | + } |
1859 | + for x := 0; x < minLen; x++ { |
1860 | + m1 := idParts1[x] |
1861 | + m2 := idParts2[x] |
1862 | + if m1 == m2 { |
1863 | + continue |
1864 | + } |
1865 | + // See if the id part is a container type, and if so compare directly. |
1866 | + if x%2 == 1 { |
1867 | + return m1 < m2 |
1868 | + } |
1869 | + // Compare the integer ids. |
1870 | + // There's nothing we can do with errors at this point. |
1871 | + mint1, _ := strconv.Atoi(m1) |
1872 | + mint2, _ := strconv.Atoi(m2) |
1873 | + return mint1 < mint2 |
1874 | + } |
1875 | + return nrParts1 < nrParts2 |
1876 | } |
1877 | |
1878 | // Machine returns the machine with the given id. |
1879 | |
1880 | === modified file 'state/state_test.go' |
1881 | --- state/state_test.go 2013-06-13 14:39:31 +0000 |
1882 | +++ state/state_test.go 2013-06-17 04:13:30 +0000 |
1883 | @@ -331,6 +331,39 @@ |
1884 | c.Assert(m.CheckProvisioned(state.BootstrapNonce), Equals, true) |
1885 | } |
1886 | |
1887 | +func (s *StateSuite) TestAddContainerToInjectedMachine(c *C) { |
1888 | + oneJob := []state.MachineJob{state.JobHostUnits} |
1889 | + m0, err := s.State.InjectMachine("series", emptyCons, state.InstanceId("i-mindustrious"), state.JobHostUnits, state.JobManageEnviron) |
1890 | + c.Assert(err, IsNil) |
1891 | + |
1892 | + // Add first container. |
1893 | + params := state.AddMachineParams{ |
1894 | + ParentId: "0", |
1895 | + ContainerType: state.LXC, |
1896 | + Series: "series", |
1897 | + Jobs: []state.MachineJob{state.JobHostUnits}, |
1898 | + } |
1899 | + m, err := s.State.AddMachineWithConstraints(¶ms) |
1900 | + c.Assert(err, IsNil) |
1901 | + c.Assert(m.Id(), Equals, "0/lxc/0") |
1902 | + c.Assert(m.Series(), Equals, "series") |
1903 | + c.Assert(m.ContainerType(), Equals, state.LXC) |
1904 | + mcons, err := m.Constraints() |
1905 | + c.Assert(err, IsNil) |
1906 | + c.Assert(mcons, DeepEquals, emptyCons) |
1907 | + c.Assert(m.Jobs(), DeepEquals, oneJob) |
1908 | + s.assertMachineContainers(c, m0, []string{"0/lxc/0"}) |
1909 | + |
1910 | + // Add second container. |
1911 | + m, err = s.State.AddMachineWithConstraints(¶ms) |
1912 | + c.Assert(err, IsNil) |
1913 | + c.Assert(m.Id(), Equals, "0/lxc/1") |
1914 | + c.Assert(m.Series(), Equals, "series") |
1915 | + c.Assert(m.ContainerType(), Equals, state.LXC) |
1916 | + c.Assert(m.Jobs(), DeepEquals, oneJob) |
1917 | + s.assertMachineContainers(c, m0, []string{"0/lxc/0", "0/lxc/1"}) |
1918 | +} |
1919 | + |
1920 | func (s *StateSuite) TestReadMachine(c *C) { |
1921 | machine, err := s.State.AddMachine("series", state.JobHostUnits) |
1922 | c.Assert(err, IsNil) |
1923 | @@ -346,6 +379,19 @@ |
1924 | c.Assert(errors.IsNotFoundError(err), Equals, true) |
1925 | } |
1926 | |
1927 | +func (s *StateSuite) TestMachineIdLessThan(c *C) { |
1928 | + c.Assert(state.MachineIdLessThan("0", "0"), Equals, false) |
1929 | + c.Assert(state.MachineIdLessThan("0", "1"), Equals, true) |
1930 | + c.Assert(state.MachineIdLessThan("1", "0"), Equals, false) |
1931 | + c.Assert(state.MachineIdLessThan("10", "2"), Equals, false) |
1932 | + c.Assert(state.MachineIdLessThan("0", "0/lxc/0"), Equals, true) |
1933 | + c.Assert(state.MachineIdLessThan("0/lxc/0", "0"), Equals, false) |
1934 | + c.Assert(state.MachineIdLessThan("1", "0/lxc/0"), Equals, false) |
1935 | + c.Assert(state.MachineIdLessThan("0/lxc/0", "1"), Equals, true) |
1936 | + c.Assert(state.MachineIdLessThan("0/lxc/0/lxc/1", "0/lxc/0"), Equals, false) |
1937 | + c.Assert(state.MachineIdLessThan("0/kvm/0", "0/lxc/0"), Equals, true) |
1938 | +} |
1939 | + |
1940 | func (s *StateSuite) TestAllMachines(c *C) { |
1941 | numInserts := 42 |
1942 | for i := 0; i < numInserts; i++ { |
1943 | @@ -1559,3 +1605,21 @@ |
1944 | } |
1945 | assertNoCleanupChange(c, st, cw) |
1946 | } |
1947 | + |
1948 | +func (s *StateSuite) TestNestingLevel(c *C) { |
1949 | + c.Assert(state.NestingLevel("0"), Equals, 0) |
1950 | + c.Assert(state.NestingLevel("0/lxc/1"), Equals, 1) |
1951 | + c.Assert(state.NestingLevel("0/lxc/1/kvm/0"), Equals, 2) |
1952 | +} |
1953 | + |
1954 | +func (s *StateSuite) TestTopParentId(c *C) { |
1955 | + c.Assert(state.TopParentId("0"), Equals, "0") |
1956 | + c.Assert(state.TopParentId("0/lxc/1"), Equals, "0") |
1957 | + c.Assert(state.TopParentId("0/lxc/1/kvm/2"), Equals, "0") |
1958 | +} |
1959 | + |
1960 | +func (s *StateSuite) TestParentId(c *C) { |
1961 | + c.Assert(state.ParentId("0"), Equals, "") |
1962 | + c.Assert(state.ParentId("0/lxc/1"), Equals, "0") |
1963 | + c.Assert(state.ParentId("0/lxc/1/kvm/0"), Equals, "0/lxc/1") |
1964 | +} |
1965 | |
1966 | === modified file 'worker/firewaller/firewaller_test.go' |
1967 | --- worker/firewaller/firewaller_test.go 2013-05-27 03:00:31 +0000 |
1968 | +++ worker/firewaller/firewaller_test.go 2013-06-17 04:13:30 +0000 |
1969 | @@ -5,9 +5,9 @@ |
1970 | |
1971 | import ( |
1972 | . "launchpad.net/gocheck" |
1973 | - "launchpad.net/juju-core/environs" |
1974 | "launchpad.net/juju-core/environs/config" |
1975 | "launchpad.net/juju-core/environs/dummy" |
1976 | + "launchpad.net/juju-core/instance" |
1977 | "launchpad.net/juju-core/juju/testing" |
1978 | "launchpad.net/juju-core/state" |
1979 | "launchpad.net/juju-core/state/api/params" |
1980 | @@ -33,7 +33,7 @@ |
1981 | |
1982 | // assertPorts retrieves the open ports of the instance and compares them |
1983 | // to the expected. |
1984 | -func (s *FirewallerSuite) assertPorts(c *C, inst environs.Instance, machineId string, expected []params.Port) { |
1985 | +func (s *FirewallerSuite) assertPorts(c *C, inst instance.Instance, machineId string, expected []params.Port) { |
1986 | s.State.StartSync() |
1987 | start := time.Now() |
1988 | for { |
1989 | @@ -133,7 +133,7 @@ |
1990 | } |
1991 | |
1992 | // startInstance starts a new instance for the given machine. |
1993 | -func (s *FirewallerSuite) startInstance(c *C, m *state.Machine) environs.Instance { |
1994 | +func (s *FirewallerSuite) startInstance(c *C, m *state.Machine) instance.Instance { |
1995 | inst := testing.StartInstance(c, s.Conn.Environ, m.Id()) |
1996 | err := m.SetProvisioned(inst.Id(), "fake_nonce") |
1997 | c.Assert(err, IsNil) |
1998 | |
1999 | === modified file 'worker/provisioner/broker.go' |
2000 | --- worker/provisioner/broker.go 2013-06-07 01:36:48 +0000 |
2001 | +++ worker/provisioner/broker.go 2013-06-17 04:13:30 +0000 |
2002 | @@ -5,7 +5,7 @@ |
2003 | |
2004 | import ( |
2005 | "launchpad.net/juju-core/constraints" |
2006 | - "launchpad.net/juju-core/environs" |
2007 | + "launchpad.net/juju-core/instance" |
2008 | "launchpad.net/juju-core/state" |
2009 | "launchpad.net/juju-core/state/api" |
2010 | ) |
2011 | @@ -17,11 +17,11 @@ |
2012 | // unique within an environment, is used by juju to protect against the |
2013 | // consequences of multiple instances being started with the same machine |
2014 | // id. |
2015 | - StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (environs.Instance, error) |
2016 | + StartInstance(machineId, machineNonce string, series string, cons constraints.Value, info *state.Info, apiInfo *api.Info) (instance.Instance, error) |
2017 | |
2018 | // StopInstances shuts down the given instances. |
2019 | - StopInstances([]environs.Instance) error |
2020 | + StopInstances([]instance.Instance) error |
2021 | |
2022 | // AllInstances returns all instances currently known to the broker. |
2023 | - AllInstances() ([]environs.Instance, error) |
2024 | + AllInstances() ([]instance.Instance, error) |
2025 | } |
2026 | |
2027 | === modified file 'worker/provisioner/export_test.go' |
2028 | --- worker/provisioner/export_test.go 2013-05-02 15:55:42 +0000 |
2029 | +++ worker/provisioner/export_test.go 2013-06-17 04:13:30 +0000 |
2030 | @@ -11,13 +11,13 @@ |
2031 | // exported so we can manually close the Provisioners underlying |
2032 | // state connection. |
2033 | func (p *Provisioner) CloseState() error { |
2034 | - return p.st.Close() |
2035 | + return p.state.Close() |
2036 | } |
2037 | |
2038 | // exported so we can discover all machines visible to the |
2039 | // Provisioners state connection. |
2040 | func (p *Provisioner) AllMachines() ([]*state.Machine, error) { |
2041 | - return p.st.AllMachines() |
2042 | + return p.state.AllMachines() |
2043 | } |
2044 | |
2045 | func (o *configObserver) SetObserver(observer chan<- *config.Config) { |
2046 | |
2047 | === modified file 'worker/provisioner/provisioner.go' |
2048 | --- worker/provisioner/provisioner.go 2013-06-11 02:15:31 +0000 |
2049 | +++ worker/provisioner/provisioner.go 2013-06-17 04:13:30 +0000 |
2050 | @@ -19,7 +19,7 @@ |
2051 | |
2052 | // Provisioner represents a running provisioning worker. |
2053 | type Provisioner struct { |
2054 | - st *state.State |
2055 | + state *state.State |
2056 | machineId string // Which machine runs the provisioner. |
2057 | environ environs.Environ |
2058 | tomb tomb.Tomb |
2059 | @@ -46,7 +46,7 @@ |
2060 | // and allocates them to the new machines. |
2061 | func NewProvisioner(st *state.State, machineId string) *Provisioner { |
2062 | p := &Provisioner{ |
2063 | - st: st, |
2064 | + state: st, |
2065 | machineId: machineId, |
2066 | } |
2067 | go func() { |
2068 | @@ -57,7 +57,7 @@ |
2069 | } |
2070 | |
2071 | func (p *Provisioner) loop() error { |
2072 | - environWatcher := p.st.WatchEnvironConfig() |
2073 | + environWatcher := p.state.WatchEnvironConfig() |
2074 | defer watcher.Stop(environWatcher, &p.tomb) |
2075 | |
2076 | var err error |
2077 | @@ -66,27 +66,18 @@ |
2078 | return err |
2079 | } |
2080 | |
2081 | - // Get a new StateInfo from the environment: the one used to |
2082 | - // launch the agent may refer to localhost, which will be |
2083 | - // unhelpful when attempting to run an agent on a new machine. |
2084 | - stateInfo, apiInfo, err := p.environ.StateInfo() |
2085 | - if err != nil { |
2086 | - return err |
2087 | - } |
2088 | - |
2089 | // Start a new worker for the environment provider. |
2090 | |
2091 | // Start responding to changes in machines, and to any further updates |
2092 | // to the environment config. |
2093 | - machinesWatcher := p.st.WatchEnvironMachines() |
2094 | + machinesWatcher := p.state.WatchEnvironMachines() |
2095 | environmentBroker := newEnvironBroker(p.environ) |
2096 | environmentProvisioner := newProvisionerTask( |
2097 | p.machineId, |
2098 | - p.st, |
2099 | + p.state, |
2100 | machinesWatcher, |
2101 | environmentBroker, |
2102 | - stateInfo, |
2103 | - apiInfo) |
2104 | + ) |
2105 | defer watcher.Stop(environmentProvisioner, &p.tomb) |
2106 | |
2107 | for { |
2108 | @@ -103,6 +94,11 @@ |
2109 | } |
2110 | if err := p.setConfig(cfg); err != nil { |
2111 | logger.Errorf("loaded invalid environment configuration: %v", err) |
2112 | + // We *shouldn't* ever get into a state here where we have an |
2113 | + // invalid config. If we do, stop the task and let jujud |
2114 | + // restart the provisioner, which will then wait for valid |
2115 | + // config. |
2116 | + return err |
2117 | } |
2118 | } |
2119 | } |
2120 | |
2121 | === modified file 'worker/provisioner/provisioner_task.go' |
2122 | --- worker/provisioner/provisioner_task.go 2013-06-10 04:25:51 +0000 |
2123 | +++ worker/provisioner/provisioner_task.go 2013-06-17 04:13:30 +0000 |
2124 | @@ -6,8 +6,8 @@ |
2125 | import ( |
2126 | "fmt" |
2127 | |
2128 | - "launchpad.net/juju-core/environs" |
2129 | "launchpad.net/juju-core/errors" |
2130 | + "launchpad.net/juju-core/instance" |
2131 | "launchpad.net/juju-core/state" |
2132 | "launchpad.net/juju-core/state/api" |
2133 | "launchpad.net/juju-core/state/api/params" |
2134 | @@ -30,25 +30,17 @@ |
2135 | Changes() <-chan []string |
2136 | } |
2137 | |
2138 | -type MachineGetter interface { |
2139 | - Machine(id string) (*state.Machine, error) |
2140 | -} |
2141 | - |
2142 | func newProvisionerTask( |
2143 | machineId string, |
2144 | - machineGetter MachineGetter, |
2145 | + st *state.State, |
2146 | watcher Watcher, |
2147 | broker Broker, |
2148 | - stateInfo *state.Info, |
2149 | - apiInfo *api.Info, |
2150 | ) ProvisionerTask { |
2151 | task := &provisionerTask{ |
2152 | machineId: machineId, |
2153 | - machineGetter: machineGetter, |
2154 | + state: st, |
2155 | machineWatcher: watcher, |
2156 | broker: broker, |
2157 | - stateInfo: stateInfo, |
2158 | - apiInfo: apiInfo, |
2159 | machines: make(map[string]*state.Machine), |
2160 | } |
2161 | go func() { |
2162 | @@ -60,15 +52,13 @@ |
2163 | |
2164 | type provisionerTask struct { |
2165 | machineId string |
2166 | - machineGetter MachineGetter |
2167 | + state *state.State |
2168 | machineWatcher Watcher |
2169 | broker Broker |
2170 | tomb tomb.Tomb |
2171 | - stateInfo *state.Info |
2172 | - apiInfo *api.Info |
2173 | |
2174 | // instance id -> instance |
2175 | - instances map[state.InstanceId]environs.Instance |
2176 | + instances map[state.InstanceId]instance.Instance |
2177 | // machine id -> machine |
2178 | machines map[string]*state.Machine |
2179 | } |
2180 | @@ -159,7 +149,7 @@ |
2181 | } |
2182 | |
2183 | func (task *provisionerTask) populateMachineMaps(ids []string) error { |
2184 | - task.instances = make(map[state.InstanceId]environs.Instance) |
2185 | + task.instances = make(map[state.InstanceId]instance.Instance) |
2186 | |
2187 | instances, err := task.broker.AllInstances() |
2188 | if err != nil { |
2189 | @@ -174,7 +164,7 @@ |
2190 | // change list. |
2191 | // TODO(thumper): update for API server later to get all machines in one go. |
2192 | for _, id := range ids { |
2193 | - machine, err := task.machineGetter.Machine(id) |
2194 | + machine, err := task.state.Machine(id) |
2195 | switch { |
2196 | case errors.IsNotFoundError(err): |
2197 | logger.Debugf("machine %q not found in state", id) |
2198 | @@ -238,9 +228,9 @@ |
2199 | } |
2200 | |
2201 | // findUnknownInstances finds instances which are not associated with a machine. |
2202 | -func (task *provisionerTask) findUnknownInstances() ([]environs.Instance, error) { |
2203 | +func (task *provisionerTask) findUnknownInstances() ([]instance.Instance, error) { |
2204 | // Make a copy of the instances we know about. |
2205 | - instances := make(map[state.InstanceId]environs.Instance) |
2206 | + instances := make(map[state.InstanceId]instance.Instance) |
2207 | for k, v := range task.instances { |
2208 | instances[k] = v |
2209 | } |
2210 | @@ -250,7 +240,7 @@ |
2211 | delete(instances, instId) |
2212 | } |
2213 | } |
2214 | - var unknown []environs.Instance |
2215 | + var unknown []instance.Instance |
2216 | for _, i := range instances { |
2217 | unknown = append(unknown, i) |
2218 | } |
2219 | @@ -258,11 +248,11 @@ |
2220 | return unknown, nil |
2221 | } |
2222 | |
2223 | -// instancesForMachines returns a list of environs.Instance that represent |
2224 | +// instancesForMachines returns a list of instance.Instance that represent |
2225 | // the list of machines running in the provider. Missing machines are |
2226 | // omitted from the list. |
2227 | -func (task *provisionerTask) instancesForMachines(machines []*state.Machine) []environs.Instance { |
2228 | - var instances []environs.Instance |
2229 | +func (task *provisionerTask) instancesForMachines(machines []*state.Machine) []instance.Instance { |
2230 | + var instances []instance.Instance |
2231 | for _, machine := range machines { |
2232 | instId, ok := machine.InstanceId() |
2233 | if ok { |
2234 | @@ -276,7 +266,7 @@ |
2235 | return instances |
2236 | } |
2237 | |
2238 | -func (task *provisionerTask) stopInstances(instances []environs.Instance) error { |
2239 | +func (task *provisionerTask) stopInstances(instances []instance.Instance) error { |
2240 | // Although calling StopInstance with an empty slice should produce no change in the |
2241 | // provider, environs like dummy do not consider this a noop. |
2242 | if len(instances) == 0 { |
2243 | @@ -306,7 +296,7 @@ |
2244 | // state.Info as the PA. |
2245 | stateInfo, apiInfo, err := task.setupAuthentication(machine) |
2246 | if err != nil { |
2247 | - logger.Errorf("failed to setup authentication: %v", err) |
2248 | + logger.Warningf("failed to setup authentication for machine %q: %v", machine.Id(), err) |
2249 | return err |
2250 | } |
2251 | cons, err := machine.Constraints() |
2252 | @@ -355,6 +345,22 @@ |
2253 | } |
2254 | |
2255 | func (task *provisionerTask) setupAuthentication(machine *state.Machine) (*state.Info, *api.Info, error) { |
2256 | + // Grab a new list of state and api addresses each time along with the |
2257 | + // cert, as these can change during a processing loop. If for example the |
2258 | + // provisioner was starting 100 machines in one go, some of those may be |
2259 | + // new api servers. We should take advantage of those ASAP. |
2260 | + stateAddresses, err := task.state.Addresses() |
2261 | + if err != nil { |
2262 | + // This will only return an error if the config becomes invalid. In |
2263 | + // those situations, the provisioner bombs out and is restarted. |
2264 | + return nil, nil, fmt.Errorf("cannot get addresses from state: %v", err) |
2265 | + } |
2266 | + apiAddresses, err := task.state.APIAddresses() |
2267 | + if err != nil { |
2268 | + // Same for the api addresses. We technically shouldn't get here if |
2269 | + // we didn't fail before, but best to check. |
2270 | + return nil, nil, fmt.Errorf("cannot get api addresses from state: %v", err) |
2271 | + } |
2272 | password, err := utils.RandomPassword() |
2273 | if err != nil { |
2274 | return nil, nil, fmt.Errorf("cannot make password for machine %v: %v", machine, err) |
2275 | @@ -362,11 +368,16 @@ |
2276 | if err := machine.SetMongoPassword(password); err != nil { |
2277 | return nil, nil, fmt.Errorf("cannot set password for machine %v: %v", machine, err) |
2278 | } |
2279 | - stateInfo := *task.stateInfo |
2280 | - stateInfo.Tag = machine.Tag() |
2281 | - stateInfo.Password = password |
2282 | - apiInfo := *task.apiInfo |
2283 | - apiInfo.Tag = machine.Tag() |
2284 | - apiInfo.Password = password |
2285 | - return &stateInfo, &apiInfo, nil |
2286 | + cert := task.state.CACert() |
2287 | + return &state.Info{ |
2288 | + Addrs: stateAddresses, |
2289 | + CACert: cert, |
2290 | + Tag: machine.Tag(), |
2291 | + Password: password, |
2292 | + }, &api.Info{ |
2293 | + Addrs: apiAddresses, |
2294 | + CACert: cert, |
2295 | + Tag: machine.Tag(), |
2296 | + Password: password, |
2297 | + }, nil |
2298 | } |
2299 | |
2300 | === modified file 'worker/provisioner/provisioner_test.go' |
2301 | --- worker/provisioner/provisioner_test.go 2013-06-11 02:15:31 +0000 |
2302 | +++ worker/provisioner/provisioner_test.go 2013-06-17 04:13:30 +0000 |
2303 | @@ -12,10 +12,10 @@ |
2304 | "labix.org/v2/mgo/bson" |
2305 | . "launchpad.net/gocheck" |
2306 | "launchpad.net/juju-core/constraints" |
2307 | - "launchpad.net/juju-core/environs" |
2308 | "launchpad.net/juju-core/environs/config" |
2309 | "launchpad.net/juju-core/environs/dummy" |
2310 | "launchpad.net/juju-core/errors" |
2311 | + "launchpad.net/juju-core/instance" |
2312 | "launchpad.net/juju-core/juju/testing" |
2313 | "launchpad.net/juju-core/state" |
2314 | "launchpad.net/juju-core/state/api/params" |
2315 | @@ -100,11 +100,11 @@ |
2316 | c.Assert(s.Stop(), IsNil) |
2317 | } |
2318 | |
2319 | -func (s *ProvisionerSuite) checkStartInstance(c *C, m *state.Machine) environs.Instance { |
2320 | +func (s *ProvisionerSuite) checkStartInstance(c *C, m *state.Machine) instance.Instance { |
2321 | return s.checkStartInstanceCustom(c, m, "pork", constraints.Value{}) |
2322 | } |
2323 | |
2324 | -func (s *ProvisionerSuite) checkStartInstanceCustom(c *C, m *state.Machine, secret string, cons constraints.Value) (instance environs.Instance) { |
2325 | +func (s *ProvisionerSuite) checkStartInstanceCustom(c *C, m *state.Machine, secret string, cons constraints.Value) (instance instance.Instance) { |
2326 | s.State.StartSync() |
2327 | for { |
2328 | select { |
2329 | @@ -160,7 +160,7 @@ |
2330 | } |
2331 | |
2332 | // checkStopInstances checks that an instance has been stopped. |
2333 | -func (s *ProvisionerSuite) checkStopInstances(c *C, instances ...environs.Instance) { |
2334 | +func (s *ProvisionerSuite) checkStopInstances(c *C, instances ...instance.Instance) { |
2335 | s.State.StartSync() |
2336 | instanceIds := set.NewStrings() |
2337 | for _, instance := range instances { |
2338 | @@ -361,27 +361,6 @@ |
2339 | s.checkStartInstance(c, m) |
2340 | } |
2341 | |
2342 | -func (s *ProvisionerSuite) TestProvisioningDoesOccurAfterInvalidEnvironmentPublished(c *C) { |
2343 | - p := provisioner.NewProvisioner(s.State, "0") |
2344 | - defer stop(c, p) |
2345 | - |
2346 | - // place a new machine into the state |
2347 | - m, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits) |
2348 | - c.Assert(err, IsNil) |
2349 | - |
2350 | - s.checkStartInstance(c, m) |
2351 | - |
2352 | - err = s.invalidateEnvironment(c) |
2353 | - c.Assert(err, IsNil) |
2354 | - |
2355 | - // create a second machine |
2356 | - m, err = s.State.AddMachine(config.DefaultSeries, state.JobHostUnits) |
2357 | - c.Assert(err, IsNil) |
2358 | - |
2359 | - // the PA should create it using the old environment |
2360 | - s.checkStartInstance(c, m) |
2361 | -} |
2362 | - |
2363 | func (s *ProvisionerSuite) TestProvisioningDoesNotProvisionTheSameMachineAfterRestart(c *C) { |
2364 | p := provisioner.NewProvisioner(s.State, "0") |
2365 | defer stop(c, p) |
2366 | @@ -466,55 +445,3 @@ |
2367 | c.Assert(err, IsNil) |
2368 | c.Assert(m0.Life(), Equals, state.Dying) |
2369 | } |
2370 | - |
2371 | -func (s *ProvisionerSuite) TestProvisioningRecoversAfterInvalidEnvironmentPublished(c *C) { |
2372 | - p := provisioner.NewProvisioner(s.State, "0") |
2373 | - defer stop(c, p) |
2374 | - |
2375 | - // place a new machine into the state |
2376 | - m, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits) |
2377 | - c.Assert(err, IsNil) |
2378 | - s.checkStartInstance(c, m) |
2379 | - |
2380 | - err = s.invalidateEnvironment(c) |
2381 | - c.Assert(err, IsNil) |
2382 | - s.State.StartSync() |
2383 | - |
2384 | - // create a second machine |
2385 | - m, err = s.State.AddMachine(config.DefaultSeries, state.JobHostUnits) |
2386 | - c.Assert(err, IsNil) |
2387 | - |
2388 | - // the PA should create it using the old environment |
2389 | - s.checkStartInstance(c, m) |
2390 | - |
2391 | - err = s.fixEnvironment() |
2392 | - c.Assert(err, IsNil) |
2393 | - |
2394 | - // insert our observer |
2395 | - cfgObserver := make(chan *config.Config, 1) |
2396 | - p.SetObserver(cfgObserver) |
2397 | - |
2398 | - cfg, err := s.State.EnvironConfig() |
2399 | - c.Assert(err, IsNil) |
2400 | - attrs := cfg.AllAttrs() |
2401 | - attrs["secret"] = "beef" |
2402 | - cfg, err = config.New(attrs) |
2403 | - c.Assert(err, IsNil) |
2404 | - err = s.State.SetEnvironConfig(cfg) |
2405 | - |
2406 | - s.State.StartSync() |
2407 | - |
2408 | - // wait for the PA to load the new configuration |
2409 | - select { |
2410 | - case <-cfgObserver: |
2411 | - case <-time.After(200 * time.Millisecond): |
2412 | - c.Fatalf("PA did not action config change") |
2413 | - } |
2414 | - |
2415 | - // create a third machine |
2416 | - m, err = s.State.AddMachine(config.DefaultSeries, state.JobHostUnits) |
2417 | - c.Assert(err, IsNil) |
2418 | - |
2419 | - // the PA should create it using the new environment |
2420 | - s.checkStartInstanceCustom(c, m, "beef", constraints.Value{}) |
2421 | -} |
Reviewers: mp+168562_ code.launchpad. net,
Message:
Please take a look.
Description:
Provisioner gets addresses for each new machine.
The addresses are retrieved each time we attempt to start a machine.
This
allows the provisioner to take advantage of any new api or state servers
that
are started as part of a block of machines being provisioned at one
time.
There is some saving of addresses at this stage to make the existing
tests
pass, even though this goes a little against what William has mentioned
before. If we have invalid config, the tests assume that we continue
with old
info, whereas William has suggested that we pause provisioning while the
config is broken.
One behavioural tweak in this branch. If we do fail to setup
authentication,
we no longer kill the task, but instead log and continue. We will
attempt to
start it again next time through the loop.
https:/ /code.launchpad .net/~thumper/ juju-core/ provisioner- reget-state- info/+merge/ 168562
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/9824047/
Affected files: provisioner/ export_ test.go provisioner/ provisioner. go provisioner/ provisioner_ task.go
A [revision details]
M worker/
M worker/
M worker/