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