Merge lp:~axwalk/juju-core/startinstance-principalunit into lp:~go-bot/juju-core/trunk
- startinstance-principalunit
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Andrew Wilkins |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2551 |
Proposed branch: | lp:~axwalk/juju-core/startinstance-principalunit |
Merge into: | lp:~go-bot/juju-core/trunk |
Prerequisite: | lp:~axwalk/juju-core/startinstance-param-struct |
Diff against target: |
430 lines (+325/-4) 8 files modified
environs/broker.go (+9/-1) provider/manual/environ.go (+1/-0) state/api/params/params.go (+13/-0) state/api/provisioner/machine.go (+23/-0) state/api/provisioner/provisioner_test.go (+46/-0) state/apiserver/provisioner/provisioner.go (+102/-0) state/apiserver/provisioner/provisioner_test.go (+127/-0) worker/provisioner/provisioner_task.go (+4/-3) |
To merge this branch: | bzr merge lp:~axwalk/juju-core/startinstance-principalunit |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+210746@code.launchpad.net |
Commit message
Add DistributionGroup to StartInstanceParams
DistributionGroup returns instances that
StartInstance should consider when provisioning
for high availability (i.e. the new instance +
those in DistributionGroup should be distributed
for high availability.)
DistributionGroup is implemented in terms of
a new provisioner API method of the same name.
This API returns different instances depending
on the machine passed in. For an environ manager,
all other environ manager instances are returned;
for a non-environ manager, all other instances
with services in common are returned.
This is in preparation for modifying the Azure
provider to group instances into the same cloud
service when in availability-
Description of the change
Add DistributionGroup to StartInstanceParams
DistributionGroup returns instances that
StartInstance should consider when provisioning
for high availability (i.e. the new instance +
those in DistributionGroup should be distributed
for high availability.)
DistributionGroup is implemented in terms of
a new provisioner API method of the same name.
This API returns different instances depending
on the machine passed in. For an environ manager,
all other environ manager instances are returned;
for a non-environ manager, all other instances
with services in common are returned.
This is in preparation for modifying the Azure
provider to group instances into the same cloud
service when in availability-
(Note: the previous patch included a change to
PrecheckInstance; this has been reverted, and
will be implemented differently in another CL.)
Andrew Wilkins (axwalk) wrote : | # |
Ian Booth (wallyworld) wrote : | # |
Looks ok pending William's +1.
But there's a missing test for the client PrincipalUnits API call in
state/api/
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
Horacio Durán (hduran-8) wrote : | # |
https:/
File state/api/
https:/
state/api/
In CommonServiceIn
them with error states yet this test only sees the possibility of a
successful run of Call, is there no way to test the other three possible
outcomes?
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
https:/
File state/api/
https:/
state/api/
On 2014/03/19 17:31:42, hduran wrote:
> In CommonServiceIn
them with
> error states yet this test only sees the possibility of a successful
run of
> Call, is there no way to test the other three possible outcomes?
Testing the first two errors is not possible without creating a custom
API server. Kind of a cop out, but precisely none of the other API
methods test them either.
The third error can be tested, and in fact is tested in
apiserver/
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
William Reade (fwereade) wrote : | # |
Looks really good. I'm open to arguments re notfound/unauth; the only
thing I'm not sure about is handling for container provisioners. Have
these been directly considered?
https:/
File state/apiserver
https:/
state/apiserver
results, but it will have a blank instance.Id.
I'm not 100% sure about that. Feels better to filter them out at API
level than to make every provider have to deal with empty instances in
the group.
https:/
state/apiserver
apiservertestin
I'm wondering about notfound vs unauthorized. For an env provisioner, I
suspect that the Right Thing is to NotFound unknown top-level machines,
and to Unauthorized all hosted machines regardless of existence; and for
container provisioners, to Unauthorized everything except precisely
those containers for which the provisioner is directly responsible; but
that's a pile of tedious complexity, and if we just use unauth instead
of notfound across the board we might end up with simpler code and less
theoretical info leakage. Thoughts?
https:/
File state/state_test.go (right):
https:/
state/state_
constraints.
fwiw, it makes me ever so happy to see this just casually being called
in tests :)
William Reade (fwereade) wrote : | # |
WIP for last round of changes (then probably WIP again until 1.19)
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
https:/
File state/apiserver
https:/
state/apiserver
results, but it will have a blank instance.Id.
On 2014/03/20 09:23:53, fwereade wrote:
> I'm not 100% sure about that. Feels better to filter them out at API
level than
> to make every provider have to deal with empty instances in the group.
Sorry, that's actually a leftover comment from a previous
implementation. It doesn't do that anymore. I've fixed up the comments.
https:/
state/apiserver
apiservertestin
On 2014/03/20 09:23:53, fwereade wrote:
> I'm wondering about notfound vs unauthorized. For an env provisioner,
I suspect
> that the Right Thing is to NotFound unknown top-level machines, and to
> Unauthorized all hosted machines regardless of existence; and for
container
> provisioners, to Unauthorized everything except precisely those
containers for
> which the provisioner is directly responsible; but that's a pile of
tedious
> complexity, and if we just use unauth instead of notfound across the
board we
> might end up with simpler code and less theoretical info leakage.
Thoughts?
At the moment, the auth function allows the env provisioner to access; a
machine agent may access its own machine; and hosted machines are only
accessible to the machine agent that contains it. That seems sane to me.
The tests don't reflect this, as there's no containers. I'll update the
tests.
However... I don't plan to use DistributionGroup on container managers,
at least not yet. You can't really change how a container is
distributed, since its host is fixed before we get to this point.
William Reade (fwereade) wrote : | # |
LGTM. Taking DG into account when choosing pre-existing instances is not
in scope for this CL, but please make sure it's on your list of
necessary-
https:/
File state/apiserver
https:/
state/apiserver
apiservertestin
On 2014/03/21 07:55:56, axw wrote:
> However... I don't plan to use DistributionGroup on container
managers, at least
> not yet. You can't really change how a container is distributed, since
its host
> is fixed before we get to this point.
That's fine, I think, although we still need to pay some attention to DG
in containers in *some* way -- ie, if we have a containerised service,
we still want to distribute its units' containers across real instances
that are themselves distributed. That's a different piece of code
though.
https:/
File state/apiserver
https:/
state/apiserver
simplify testing.
copy(instanceIds, instanceIdSet.
?
https:/
File state/apiserver
https:/
state/apiserver
wordpress/1 from machine-1.
blank lines before comments for ease of reading please
https:/
File state/state.go (right):
https:/
state/state.go:323: func (st *State) ManagerMachines() (machines
[]*Machine, err error) {
Please liaise with rog, this may need to change and I want to be sure he
knows about it.
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
https:/
File state/apiserver
https:/
state/apiserver
simplify testing.
On 2014/03/24 10:12:20, fwereade wrote:
> copy(instanceIds, instanceIdSet.
> ?
Nope, different types: []instance.
https:/
File state/apiserver
https:/
state/apiserver
wordpress/1 from machine-1.
On 2014/03/24 10:12:20, fwereade wrote:
> blank lines before comments for ease of reading please
Done.
https:/
File state/state.go (right):
https:/
state/state.go:323: func (st *State) ManagerMachines() (machines
[]*Machine, err error) {
On 2014/03/24 10:12:20, fwereade wrote:
> Please liaise with rog, this may need to change and I want to be sure
he knows
> about it.
Rog brought State.StateServ
need. There'll be up to 7 (replicaset.Max) additional State.Machine
calls, but this is low volume so I think that's fine.
William Reade (fwereade) wrote : | # |
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
Preview Diff
1 | === modified file 'environs/broker.go' |
2 | --- environs/broker.go 2014-04-01 16:27:22 +0000 |
3 | +++ environs/broker.go 2014-04-03 02:58:17 +0000 |
4 | @@ -11,7 +11,7 @@ |
5 | ) |
6 | |
7 | // StartInstanceParams holds parameters for the |
8 | -// InstanceBroker.StartInstace method. |
9 | +// InstanceBroker.StartInstance method. |
10 | type StartInstanceParams struct { |
11 | // Constraints is a set of constraints on |
12 | // the kind of instance to create. |
13 | @@ -23,6 +23,14 @@ |
14 | |
15 | // MachineConfig describes the machine's configuration. |
16 | MachineConfig *cloudinit.MachineConfig |
17 | + |
18 | + // DistributionGroup, if non-nil, is a function |
19 | + // that returns a slice of instance.Ids that belong |
20 | + // to the same distribution group as the machine |
21 | + // being provisioned. The InstanceBroker may use |
22 | + // this information to distribute instances for |
23 | + // high availability. |
24 | + DistributionGroup func() ([]instance.Id, error) |
25 | } |
26 | |
27 | // TODO(wallyworld) - we want this in the environs/instance package but import loops |
28 | |
29 | === modified file 'provider/manual/environ.go' |
30 | --- provider/manual/environ.go 2014-03-28 13:27:45 +0000 |
31 | +++ provider/manual/environ.go 2014-04-03 02:58:17 +0000 |
32 | @@ -57,6 +57,7 @@ |
33 | } |
34 | |
35 | var _ envtools.SupportsCustomSources = (*manualEnviron)(nil) |
36 | +var _ state.Prechecker = (*manualEnviron)(nil) |
37 | |
38 | var errNoStartInstance = errors.New("manual provider cannot start instances") |
39 | var errNoStopInstance = errors.New("manual provider cannot stop instances") |
40 | |
41 | === modified file 'state/api/params/params.go' |
42 | --- state/api/params/params.go 2014-04-02 15:46:57 +0000 |
43 | +++ state/api/params/params.go 2014-04-03 02:58:17 +0000 |
44 | @@ -647,6 +647,19 @@ |
45 | CACert []byte |
46 | } |
47 | |
48 | +// DistributionGroupResult contains the result of |
49 | +// the DistributionGroup provisioner API call. |
50 | +type DistributionGroupResult struct { |
51 | + Error *Error |
52 | + Result []instance.Id |
53 | +} |
54 | + |
55 | +// DistributionGroupResults is the bulk form of |
56 | +// DistributionGroupResult. |
57 | +type DistributionGroupResults struct { |
58 | + Results []DistributionGroupResult |
59 | +} |
60 | + |
61 | // APIHostPortsResult holds the result of an APIHostPorts |
62 | // call. Each element in the top level slice holds |
63 | // the addresses for one API server. |
64 | |
65 | === modified file 'state/api/provisioner/machine.go' |
66 | --- state/api/provisioner/machine.go 2014-03-31 11:59:16 +0000 |
67 | +++ state/api/provisioner/machine.go 2014-04-03 02:58:17 +0000 |
68 | @@ -182,6 +182,29 @@ |
69 | return result.Result, nil |
70 | } |
71 | |
72 | +// DistributionGroup returns a slice of instance.Ids |
73 | +// that belong to the same distribution group as this |
74 | +// Machine. The provisioner may use this information |
75 | +// to distribute instances for high availability. |
76 | +func (m *Machine) DistributionGroup() ([]instance.Id, error) { |
77 | + var results params.DistributionGroupResults |
78 | + args := params.Entities{ |
79 | + Entities: []params.Entity{{Tag: m.tag}}, |
80 | + } |
81 | + err := m.st.caller.Call("Provisioner", "", "DistributionGroup", args, &results) |
82 | + if err != nil { |
83 | + return nil, err |
84 | + } |
85 | + if len(results.Results) != 1 { |
86 | + return nil, fmt.Errorf("expected one result, got %d", len(results.Results)) |
87 | + } |
88 | + result := results.Results[0] |
89 | + if result.Error != nil { |
90 | + return nil, result.Error |
91 | + } |
92 | + return result.Result, nil |
93 | +} |
94 | + |
95 | // SetProvisioned sets the provider specific machine id, nonce and also metadata for |
96 | // this machine. Once set, the instance id cannot be changed. |
97 | func (m *Machine) SetProvisioned(id instance.Id, nonce string, characteristics *instance.HardwareCharacteristics) error { |
98 | |
99 | === modified file 'state/api/provisioner/provisioner_test.go' |
100 | --- state/api/provisioner/provisioner_test.go 2014-04-02 10:36:23 +0000 |
101 | +++ state/api/provisioner/provisioner_test.go 2014-04-03 02:58:17 +0000 |
102 | @@ -246,6 +246,52 @@ |
103 | c.Assert(series, gc.Equals, "quantal") |
104 | } |
105 | |
106 | +func (s *provisionerSuite) TestDistributionGroup(c *gc.C) { |
107 | + apiMachine, err := s.provisioner.Machine(s.machine.Tag()) |
108 | + c.Assert(err, gc.IsNil) |
109 | + instances, err := apiMachine.DistributionGroup() |
110 | + c.Assert(err, gc.IsNil) |
111 | + c.Assert(instances, gc.DeepEquals, []instance.Id{"i-manager"}) |
112 | + |
113 | + machine1, err := s.State.AddMachine("quantal", state.JobHostUnits) |
114 | + c.Assert(err, gc.IsNil) |
115 | + apiMachine, err = s.provisioner.Machine(machine1.Tag()) |
116 | + c.Assert(err, gc.IsNil) |
117 | + wordpress := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) |
118 | + |
119 | + err = apiMachine.SetProvisioned("i-d", "fake", nil) |
120 | + c.Assert(err, gc.IsNil) |
121 | + instances, err = apiMachine.DistributionGroup() |
122 | + c.Assert(err, gc.IsNil) |
123 | + c.Assert(instances, gc.HasLen, 0) // no units assigned |
124 | + |
125 | + var unitNames []string |
126 | + for i := 0; i < 3; i++ { |
127 | + unit, err := wordpress.AddUnit() |
128 | + c.Assert(err, gc.IsNil) |
129 | + unitNames = append(unitNames, unit.Name()) |
130 | + err = unit.AssignToMachine(machine1) |
131 | + c.Assert(err, gc.IsNil) |
132 | + instances, err := apiMachine.DistributionGroup() |
133 | + c.Assert(err, gc.IsNil) |
134 | + c.Assert(instances, gc.DeepEquals, []instance.Id{"i-d"}) |
135 | + } |
136 | +} |
137 | + |
138 | +func (s *provisionerSuite) TestDistributionGroupMachineNotFound(c *gc.C) { |
139 | + stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) |
140 | + c.Assert(err, gc.IsNil) |
141 | + apiMachine, err := s.provisioner.Machine(stateMachine.Tag()) |
142 | + c.Assert(err, gc.IsNil) |
143 | + err = apiMachine.EnsureDead() |
144 | + c.Assert(err, gc.IsNil) |
145 | + err = apiMachine.Remove() |
146 | + c.Assert(err, gc.IsNil) |
147 | + _, err = apiMachine.DistributionGroup() |
148 | + c.Assert(err, gc.ErrorMatches, "machine 1 not found") |
149 | + c.Assert(err, jc.Satisfies, params.IsCodeNotFound) |
150 | +} |
151 | + |
152 | func (s *provisionerSuite) TestConstraints(c *gc.C) { |
153 | // Create a fresh machine with some constraints. |
154 | template := state.MachineTemplate{ |
155 | |
156 | === modified file 'state/apiserver/provisioner/provisioner.go' |
157 | --- state/apiserver/provisioner/provisioner.go 2014-03-31 11:59:16 +0000 |
158 | +++ state/apiserver/provisioner/provisioner.go 2014-04-03 02:58:17 +0000 |
159 | @@ -11,6 +11,7 @@ |
160 | "launchpad.net/juju-core/state/api/params" |
161 | "launchpad.net/juju-core/state/apiserver/common" |
162 | "launchpad.net/juju-core/state/watcher" |
163 | + "launchpad.net/juju-core/utils/set" |
164 | ) |
165 | |
166 | // ProvisionerAPI provides access to the Provisioner API facade. |
167 | @@ -282,6 +283,107 @@ |
168 | return result, nil |
169 | } |
170 | |
171 | +// DistributionGroup returns, for each given machine entity, |
172 | +// a slice of instance.Ids that belong to the same distribution |
173 | +// group as that machine. This information may be used to |
174 | +// distribute instances for high availability. |
175 | +func (p *ProvisionerAPI) DistributionGroup(args params.Entities) (params.DistributionGroupResults, error) { |
176 | + result := params.DistributionGroupResults{ |
177 | + Results: make([]params.DistributionGroupResult, len(args.Entities)), |
178 | + } |
179 | + canAccess, err := p.getAuthFunc() |
180 | + if err != nil { |
181 | + return result, err |
182 | + } |
183 | + for i, entity := range args.Entities { |
184 | + machine, err := p.getMachine(canAccess, entity.Tag) |
185 | + if err == nil { |
186 | + // If the machine is an environment manager, return |
187 | + // environment manager instances. Otherwise, return |
188 | + // instances with services in common with the machine |
189 | + // being provisioned. |
190 | + if machine.IsManager() { |
191 | + result.Results[i].Result, err = environManagerInstances(p.st) |
192 | + } else { |
193 | + result.Results[i].Result, err = commonServiceInstances(p.st, machine) |
194 | + } |
195 | + } |
196 | + result.Results[i].Error = common.ServerError(err) |
197 | + } |
198 | + return result, nil |
199 | +} |
200 | + |
201 | +// environManagerInstances returns all environ manager instances. |
202 | +func environManagerInstances(st *state.State) ([]instance.Id, error) { |
203 | + info, err := st.StateServerInfo() |
204 | + if err != nil { |
205 | + return nil, err |
206 | + } |
207 | + instances := make([]instance.Id, 0, len(info.MachineIds)) |
208 | + for _, id := range info.MachineIds { |
209 | + machine, err := st.Machine(id) |
210 | + if err != nil { |
211 | + return nil, err |
212 | + } |
213 | + instanceId, err := machine.InstanceId() |
214 | + if err == nil { |
215 | + instances = append(instances, instanceId) |
216 | + } else if !state.IsNotProvisionedError(err) { |
217 | + return nil, err |
218 | + } |
219 | + } |
220 | + return instances, nil |
221 | +} |
222 | + |
223 | +// commonServiceInstances returns instances with |
224 | +// services in common with the specified machine. |
225 | +func commonServiceInstances(st *state.State, m *state.Machine) ([]instance.Id, error) { |
226 | + units, err := m.Units() |
227 | + if err != nil { |
228 | + return nil, err |
229 | + } |
230 | + var instanceIdSet set.Strings |
231 | + for _, unit := range units { |
232 | + if !unit.IsPrincipal() { |
233 | + continue |
234 | + } |
235 | + service, err := unit.Service() |
236 | + if err != nil { |
237 | + return nil, err |
238 | + } |
239 | + allUnits, err := service.AllUnits() |
240 | + if err != nil { |
241 | + return nil, err |
242 | + } |
243 | + for _, unit := range allUnits { |
244 | + machineId, err := unit.AssignedMachineId() |
245 | + if state.IsNotAssigned(err) { |
246 | + continue |
247 | + } else if err != nil { |
248 | + return nil, err |
249 | + } |
250 | + machine, err := st.Machine(machineId) |
251 | + if err != nil { |
252 | + return nil, err |
253 | + } |
254 | + instanceId, err := machine.InstanceId() |
255 | + if err == nil { |
256 | + instanceIdSet.Add(string(instanceId)) |
257 | + } else if state.IsNotProvisionedError(err) { |
258 | + continue |
259 | + } else { |
260 | + return nil, err |
261 | + } |
262 | + } |
263 | + } |
264 | + instanceIds := make([]instance.Id, instanceIdSet.Size()) |
265 | + // Sort values to simplify testing. |
266 | + for i, instanceId := range instanceIdSet.SortedValues() { |
267 | + instanceIds[i] = instance.Id(instanceId) |
268 | + } |
269 | + return instanceIds, nil |
270 | +} |
271 | + |
272 | // Constraints returns the constraints for each given machine entity. |
273 | func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsResults, error) { |
274 | result := params.ConstraintsResults{ |
275 | |
276 | === modified file 'state/apiserver/provisioner/provisioner_test.go' |
277 | --- state/apiserver/provisioner/provisioner_test.go 2014-04-02 10:36:23 +0000 |
278 | +++ state/apiserver/provisioner/provisioner_test.go 2014-04-03 02:58:17 +0000 |
279 | @@ -598,6 +598,133 @@ |
280 | }) |
281 | } |
282 | |
283 | +func (s *withoutStateServerSuite) TestDistributionGroup(c *gc.C) { |
284 | + addUnits := func(name string, machines ...*state.Machine) (units []*state.Unit) { |
285 | + svc := s.AddTestingService(c, name, s.AddTestingCharm(c, name)) |
286 | + for _, m := range machines { |
287 | + unit, err := svc.AddUnit() |
288 | + c.Assert(err, gc.IsNil) |
289 | + err = unit.AssignToMachine(m) |
290 | + c.Assert(err, gc.IsNil) |
291 | + units = append(units, unit) |
292 | + } |
293 | + return units |
294 | + } |
295 | + setProvisioned := func(id string) { |
296 | + m, err := s.State.Machine(id) |
297 | + c.Assert(err, gc.IsNil) |
298 | + err = m.SetProvisioned(instance.Id("machine-"+id+"-inst"), "nonce", nil) |
299 | + c.Assert(err, gc.IsNil) |
300 | + } |
301 | + |
302 | + mysqlUnit := addUnits("mysql", s.machines[0], s.machines[3])[0] |
303 | + wordpressUnits := addUnits("wordpress", s.machines[0], s.machines[1], s.machines[2]) |
304 | + |
305 | + // Unassign wordpress/1 from machine-1. |
306 | + // The unit should not show up in the results. |
307 | + err := wordpressUnits[1].UnassignFromMachine() |
308 | + c.Assert(err, gc.IsNil) |
309 | + |
310 | + // Provision machines 1, 2 and 3. Machine-0 remains |
311 | + // unprovisioned, and machine-1 has no units, and so |
312 | + // neither will show up in the results. |
313 | + setProvisioned("1") |
314 | + setProvisioned("2") |
315 | + setProvisioned("3") |
316 | + |
317 | + // Add a few state servers, provision two of them. |
318 | + err = s.State.EnsureAvailability(3, constraints.Value{}, "quantal") |
319 | + c.Assert(err, gc.IsNil) |
320 | + setProvisioned("5") |
321 | + setProvisioned("7") |
322 | + |
323 | + // Create a logging service, subordinate to mysql. |
324 | + s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) |
325 | + eps, err := s.State.InferEndpoints([]string{"mysql", "logging"}) |
326 | + c.Assert(err, gc.IsNil) |
327 | + rel, err := s.State.AddRelation(eps...) |
328 | + c.Assert(err, gc.IsNil) |
329 | + ru, err := rel.Unit(mysqlUnit) |
330 | + c.Assert(err, gc.IsNil) |
331 | + err = ru.EnterScope(nil) |
332 | + c.Assert(err, gc.IsNil) |
333 | + |
334 | + args := params.Entities{Entities: []params.Entity{ |
335 | + {Tag: s.machines[0].Tag()}, |
336 | + {Tag: s.machines[1].Tag()}, |
337 | + {Tag: s.machines[2].Tag()}, |
338 | + {Tag: s.machines[3].Tag()}, |
339 | + {Tag: "machine-5"}, |
340 | + }} |
341 | + result, err := s.provisioner.DistributionGroup(args) |
342 | + c.Assert(err, gc.IsNil) |
343 | + c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ |
344 | + Results: []params.DistributionGroupResult{ |
345 | + {Result: []instance.Id{"machine-2-inst", "machine-3-inst"}}, |
346 | + {Result: []instance.Id{}}, |
347 | + {Result: []instance.Id{"machine-2-inst"}}, |
348 | + {Result: []instance.Id{"machine-3-inst"}}, |
349 | + {Result: []instance.Id{"machine-5-inst", "machine-7-inst"}}, |
350 | + }, |
351 | + }) |
352 | +} |
353 | + |
354 | +func (s *withoutStateServerSuite) TestDistributionGroupEnvironManagerAuth(c *gc.C) { |
355 | + args := params.Entities{Entities: []params.Entity{ |
356 | + {Tag: "machine-0"}, |
357 | + {Tag: "machine-42"}, |
358 | + {Tag: "machine-0-lxc-99"}, |
359 | + {Tag: "unit-foo-0"}, |
360 | + {Tag: "service-bar"}, |
361 | + }} |
362 | + result, err := s.provisioner.DistributionGroup(args) |
363 | + c.Assert(err, gc.IsNil) |
364 | + c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ |
365 | + Results: []params.DistributionGroupResult{ |
366 | + // environ manager may access any top-level machines. |
367 | + {Result: []instance.Id{}}, |
368 | + {Error: apiservertesting.NotFoundError("machine 42")}, |
369 | + // only a machine agent for the container or its |
370 | + // parent may access it. |
371 | + {Error: apiservertesting.ErrUnauthorized}, |
372 | + // non-machines always unauthorized |
373 | + {Error: apiservertesting.ErrUnauthorized}, |
374 | + {Error: apiservertesting.ErrUnauthorized}, |
375 | + }, |
376 | + }) |
377 | +} |
378 | + |
379 | +func (s *withoutStateServerSuite) TestDistributionGroupMachineAgentAuth(c *gc.C) { |
380 | + anAuthorizer := s.authorizer |
381 | + anAuthorizer.Tag = "machine-1" |
382 | + anAuthorizer.EnvironManager = false |
383 | + anAuthorizer.MachineAgent = true |
384 | + provisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) |
385 | + c.Check(err, gc.IsNil) |
386 | + args := params.Entities{Entities: []params.Entity{ |
387 | + {Tag: "machine-0"}, |
388 | + {Tag: "machine-1"}, |
389 | + {Tag: "machine-42"}, |
390 | + {Tag: "machine-0-lxc-99"}, |
391 | + {Tag: "machine-1-lxc-99"}, |
392 | + {Tag: "machine-1-lxc-99-lxc-100"}, |
393 | + }} |
394 | + result, err := provisioner.DistributionGroup(args) |
395 | + c.Assert(err, gc.IsNil) |
396 | + c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ |
397 | + Results: []params.DistributionGroupResult{ |
398 | + {Error: apiservertesting.ErrUnauthorized}, |
399 | + {Result: []instance.Id{}}, |
400 | + {Error: apiservertesting.ErrUnauthorized}, |
401 | + // only a machine agent for the container or its |
402 | + // parent may access it. |
403 | + {Error: apiservertesting.ErrUnauthorized}, |
404 | + {Error: apiservertesting.NotFoundError("machine 1/lxc/99")}, |
405 | + {Error: apiservertesting.ErrUnauthorized}, |
406 | + }, |
407 | + }) |
408 | +} |
409 | + |
410 | func (s *withoutStateServerSuite) TestConstraints(c *gc.C) { |
411 | // Add a machine with some constraints. |
412 | template := state.MachineTemplate{ |
413 | |
414 | === modified file 'worker/provisioner/provisioner_task.go' |
415 | --- worker/provisioner/provisioner_task.go 2014-04-02 11:35:49 +0000 |
416 | +++ worker/provisioner/provisioner_task.go 2014-04-03 02:58:17 +0000 |
417 | @@ -426,9 +426,10 @@ |
418 | return err |
419 | } |
420 | inst, metadata, err := task.broker.StartInstance(environs.StartInstanceParams{ |
421 | - Constraints: cons, |
422 | - Tools: possibleTools, |
423 | - MachineConfig: machineConfig, |
424 | + Constraints: cons, |
425 | + Tools: possibleTools, |
426 | + MachineConfig: machineConfig, |
427 | + DistributionGroup: machine.DistributionGroup, |
428 | }) |
429 | if err != nil { |
430 | // Set the state to error, so the machine will be skipped next |
Reviewers: mp+210746_ code.launchpad. net,
Message:
Please take a look.
Description:
Add PrincipalUnits to StartInstanceParams
Also, pass to principalUnits to PrecheckInstance.
This is in preparation for modifying the Azure
provider to prevent "juju add-machine" when in
availability set mode, and use the principal unit's
service name to decide on which Cloud Service to
allocate the instance to.
https:/ /code.launchpad .net/~axwalk/ juju-core/ startinstance- principalunit/ +merge/ 210746
Requires: /code.launchpad .net/~axwalk/ juju-core/ startinstance- param-struct/ +merge/ 210738
https:/
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/75250043/
Affected files (+139, -16 lines): jujutest/ livetests. go manual/ environ. go provisioner/ machine. go /provisioner/ provisioner. go /provisioner/ provisioner_ test.go r_test. go provisioner/ provisioner_ task.go
A [revision details]
M environs/broker.go
M environs/
M provider/
M state/addmachine.go
M state/api/
M state/apiserver
M state/apiserver
M state/policy.go
M state/prechecke
M worker/