1
// Copyright 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
4
package provisioner_test
9
jc "github.com/juju/testing/checkers"
10
gc "launchpad.net/gocheck"
12
"launchpad.net/juju-core/constraints"
13
"launchpad.net/juju-core/errors"
14
"launchpad.net/juju-core/instance"
15
"launchpad.net/juju-core/juju/testing"
16
"launchpad.net/juju-core/state"
17
"launchpad.net/juju-core/state/api"
18
"launchpad.net/juju-core/state/api/params"
19
"launchpad.net/juju-core/state/api/provisioner"
20
apitesting "launchpad.net/juju-core/state/api/testing"
21
statetesting "launchpad.net/juju-core/state/testing"
22
coretesting "launchpad.net/juju-core/testing"
23
"launchpad.net/juju-core/tools"
24
"launchpad.net/juju-core/utils"
25
"launchpad.net/juju-core/version"
28
func TestAll(t *stdtesting.T) {
29
coretesting.MgoTestPackage(t)
32
type provisionerSuite struct {
34
*apitesting.EnvironWatcherTests
35
*apitesting.APIAddresserTests
38
machine *state.Machine
40
provisioner *provisioner.State
43
var _ = gc.Suite(&provisionerSuite{})
45
func (s *provisionerSuite) SetUpTest(c *gc.C) {
46
s.JujuConnSuite.SetUpTest(c)
49
s.machine, err = s.State.AddMachine("quantal", state.JobManageEnviron)
50
c.Assert(err, gc.IsNil)
51
password, err := utils.RandomPassword()
52
c.Assert(err, gc.IsNil)
53
err = s.machine.SetPassword(password)
54
c.Assert(err, gc.IsNil)
55
err = s.machine.SetProvisioned("i-manager", "fake_nonce", nil)
56
c.Assert(err, gc.IsNil)
57
s.st = s.OpenAPIAsMachine(c, s.machine.Tag(), password, "fake_nonce")
58
c.Assert(s.st, gc.NotNil)
59
err = s.machine.SetAddresses(instance.NewAddresses([]string{"0.1.2.3"}))
60
c.Assert(err, gc.IsNil)
62
// Create the provisioner API facade.
63
s.provisioner = s.st.Provisioner()
64
c.Assert(s.provisioner, gc.NotNil)
66
s.EnvironWatcherTests = apitesting.NewEnvironWatcherTests(s.provisioner, s.BackingState, apitesting.HasSecrets)
67
s.APIAddresserTests = apitesting.NewAPIAddresserTests(s.provisioner, s.BackingState)
70
func (s *provisionerSuite) TestMachineTagAndId(c *gc.C) {
71
apiMachine, err := s.provisioner.Machine("machine-42")
72
c.Assert(err, gc.ErrorMatches, "machine 42 not found")
73
c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
74
c.Assert(apiMachine, gc.IsNil)
76
apiMachine, err = s.provisioner.Machine(s.machine.Tag())
77
c.Assert(err, gc.IsNil)
78
c.Assert(apiMachine.Tag(), gc.Equals, s.machine.Tag())
79
c.Assert(apiMachine.Id(), gc.Equals, s.machine.Id())
82
func (s *provisionerSuite) TestGetSetStatus(c *gc.C) {
83
apiMachine, err := s.provisioner.Machine(s.machine.Tag())
84
c.Assert(err, gc.IsNil)
86
status, info, err := apiMachine.Status()
87
c.Assert(err, gc.IsNil)
88
c.Assert(status, gc.Equals, params.StatusPending)
89
c.Assert(info, gc.Equals, "")
91
err = apiMachine.SetStatus(params.StatusStarted, "blah", nil)
92
c.Assert(err, gc.IsNil)
94
status, info, err = apiMachine.Status()
95
c.Assert(err, gc.IsNil)
96
c.Assert(status, gc.Equals, params.StatusStarted)
97
c.Assert(info, gc.Equals, "blah")
98
_, _, data, err := s.machine.Status()
99
c.Assert(err, gc.IsNil)
100
c.Assert(data, gc.HasLen, 0)
103
func (s *provisionerSuite) TestGetSetStatusWithData(c *gc.C) {
104
apiMachine, err := s.provisioner.Machine(s.machine.Tag())
105
c.Assert(err, gc.IsNil)
107
err = apiMachine.SetStatus(params.StatusError, "blah", params.StatusData{"foo": "bar"})
108
c.Assert(err, gc.IsNil)
110
status, info, err := apiMachine.Status()
111
c.Assert(err, gc.IsNil)
112
c.Assert(status, gc.Equals, params.StatusError)
113
c.Assert(info, gc.Equals, "blah")
114
_, _, data, err := s.machine.Status()
115
c.Assert(err, gc.IsNil)
116
c.Assert(data, gc.DeepEquals, params.StatusData{"foo": "bar"})
119
func (s *provisionerSuite) TestMachinesWithTransientErrors(c *gc.C) {
120
machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
121
c.Assert(err, gc.IsNil)
122
err = machine.SetStatus(params.StatusError, "blah", params.StatusData{"transient": true})
123
c.Assert(err, gc.IsNil)
124
machines, info, err := s.provisioner.MachinesWithTransientErrors()
125
c.Assert(err, gc.IsNil)
126
c.Assert(machines, gc.HasLen, 1)
127
c.Assert(machines[0].Id(), gc.Equals, "1")
128
c.Assert(info, gc.HasLen, 1)
129
c.Assert(info[0], gc.DeepEquals, params.StatusResult{
134
Data: params.StatusData{"transient": true},
138
func (s *provisionerSuite) TestEnsureDeadAndRemove(c *gc.C) {
139
// Create a fresh machine to test the complete scenario.
140
otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
141
c.Assert(err, gc.IsNil)
142
c.Assert(otherMachine.Life(), gc.Equals, state.Alive)
144
apiMachine, err := s.provisioner.Machine(otherMachine.Tag())
145
c.Assert(err, gc.IsNil)
147
err = apiMachine.Remove()
148
c.Assert(err, gc.ErrorMatches, `cannot remove entity "machine-1": still alive`)
149
err = apiMachine.EnsureDead()
150
c.Assert(err, gc.IsNil)
152
err = otherMachine.Refresh()
153
c.Assert(err, gc.IsNil)
154
c.Assert(otherMachine.Life(), gc.Equals, state.Dead)
156
err = apiMachine.EnsureDead()
157
c.Assert(err, gc.IsNil)
158
err = otherMachine.Refresh()
159
c.Assert(err, gc.IsNil)
160
c.Assert(otherMachine.Life(), gc.Equals, state.Dead)
162
err = apiMachine.Remove()
163
c.Assert(err, gc.IsNil)
164
err = otherMachine.Refresh()
165
c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
167
err = apiMachine.EnsureDead()
168
c.Assert(err, gc.ErrorMatches, "machine 1 not found")
169
c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
171
// Now try to EnsureDead machine 0 - should fail.
172
apiMachine, err = s.provisioner.Machine(s.machine.Tag())
173
c.Assert(err, gc.IsNil)
174
err = apiMachine.EnsureDead()
175
c.Assert(err, gc.ErrorMatches, "machine 0 is required by the environment")
178
func (s *provisionerSuite) TestRefreshAndLife(c *gc.C) {
179
// Create a fresh machine to test the complete scenario.
180
otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
181
c.Assert(err, gc.IsNil)
182
c.Assert(otherMachine.Life(), gc.Equals, state.Alive)
184
apiMachine, err := s.provisioner.Machine(otherMachine.Tag())
185
c.Assert(err, gc.IsNil)
186
c.Assert(apiMachine.Life(), gc.Equals, params.Alive)
188
err = apiMachine.EnsureDead()
189
c.Assert(err, gc.IsNil)
190
c.Assert(apiMachine.Life(), gc.Equals, params.Alive)
192
err = apiMachine.Refresh()
193
c.Assert(err, gc.IsNil)
194
c.Assert(apiMachine.Life(), gc.Equals, params.Dead)
197
func (s *provisionerSuite) TestSetProvisionedAndInstanceId(c *gc.C) {
198
// Create a fresh machine, since machine 0 is already provisioned.
199
notProvisionedMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
200
c.Assert(err, gc.IsNil)
202
apiMachine, err := s.provisioner.Machine(notProvisionedMachine.Tag())
203
c.Assert(err, gc.IsNil)
205
instanceId, err := apiMachine.InstanceId()
206
c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned)
207
c.Assert(err, gc.ErrorMatches, "machine 1 is not provisioned")
208
c.Assert(instanceId, gc.Equals, instance.Id(""))
210
hwChars := instance.MustParseHardware("cpu-cores=123", "mem=4G")
211
err = apiMachine.SetProvisioned("i-will", "fake_nonce", &hwChars)
212
c.Assert(err, gc.IsNil)
214
instanceId, err = apiMachine.InstanceId()
215
c.Assert(err, gc.IsNil)
216
c.Assert(instanceId, gc.Equals, instance.Id("i-will"))
218
// Try it again - should fail.
219
err = apiMachine.SetProvisioned("i-wont", "fake", nil)
220
c.Assert(err, gc.ErrorMatches, `cannot set instance data for machine "1": already set`)
222
// Now try to get machine 0's instance id.
223
apiMachine, err = s.provisioner.Machine(s.machine.Tag())
224
c.Assert(err, gc.IsNil)
225
instanceId, err = apiMachine.InstanceId()
226
c.Assert(err, gc.IsNil)
227
c.Assert(instanceId, gc.Equals, instance.Id("i-manager"))
230
func (s *provisionerSuite) TestSeries(c *gc.C) {
231
// Create a fresh machine with different series.
232
foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits)
233
c.Assert(err, gc.IsNil)
235
apiMachine, err := s.provisioner.Machine(foobarMachine.Tag())
236
c.Assert(err, gc.IsNil)
237
series, err := apiMachine.Series()
238
c.Assert(err, gc.IsNil)
239
c.Assert(series, gc.Equals, "foobar")
241
// Now try machine 0.
242
apiMachine, err = s.provisioner.Machine(s.machine.Tag())
243
c.Assert(err, gc.IsNil)
244
series, err = apiMachine.Series()
245
c.Assert(err, gc.IsNil)
246
c.Assert(series, gc.Equals, "quantal")
249
func (s *provisionerSuite) TestConstraints(c *gc.C) {
250
// Create a fresh machine with some constraints.
251
template := state.MachineTemplate{
253
Jobs: []state.MachineJob{state.JobHostUnits},
254
Constraints: constraints.MustParse("cpu-cores=12", "mem=8G"),
256
consMachine, err := s.State.AddOneMachine(template)
257
c.Assert(err, gc.IsNil)
259
apiMachine, err := s.provisioner.Machine(consMachine.Tag())
260
c.Assert(err, gc.IsNil)
261
cons, err := apiMachine.Constraints()
262
c.Assert(err, gc.IsNil)
263
c.Assert(cons, gc.DeepEquals, template.Constraints)
265
// Now try machine 0.
266
apiMachine, err = s.provisioner.Machine(s.machine.Tag())
267
c.Assert(err, gc.IsNil)
268
cons, err = apiMachine.Constraints()
269
c.Assert(err, gc.IsNil)
270
c.Assert(cons, gc.DeepEquals, constraints.Value{})
273
func (s *provisionerSuite) TestWatchContainers(c *gc.C) {
274
apiMachine, err := s.provisioner.Machine(s.machine.Tag())
275
c.Assert(err, gc.IsNil)
277
// Add one LXC container.
278
template := state.MachineTemplate{
280
Jobs: []state.MachineJob{state.JobHostUnits},
282
container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
283
c.Assert(err, gc.IsNil)
285
w, err := apiMachine.WatchContainers(instance.LXC)
286
c.Assert(err, gc.IsNil)
287
defer statetesting.AssertStop(c, w)
288
wc := statetesting.NewStringsWatcherC(c, s.BackingState, w)
291
wc.AssertChange(container.Id())
293
// Change something other than the containers and make sure it's
295
err = apiMachine.SetStatus(params.StatusStarted, "not really", nil)
296
c.Assert(err, gc.IsNil)
299
// Add a KVM container and make sure it's not detected.
300
container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.KVM)
301
c.Assert(err, gc.IsNil)
304
// Add another LXC container and make sure it's detected.
305
container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
306
c.Assert(err, gc.IsNil)
307
wc.AssertChange(container.Id())
309
statetesting.AssertStop(c, w)
313
func (s *provisionerSuite) TestWatchContainersAcceptsSupportedContainers(c *gc.C) {
314
apiMachine, err := s.provisioner.Machine(s.machine.Tag())
315
c.Assert(err, gc.IsNil)
317
for _, ctype := range instance.ContainerTypes {
318
w, err := apiMachine.WatchContainers(ctype)
319
c.Assert(w, gc.NotNil)
320
c.Assert(err, gc.IsNil)
324
func (s *provisionerSuite) TestWatchContainersErrors(c *gc.C) {
325
apiMachine, err := s.provisioner.Machine(s.machine.Tag())
326
c.Assert(err, gc.IsNil)
328
_, err = apiMachine.WatchContainers(instance.NONE)
329
c.Assert(err, gc.ErrorMatches, `unsupported container type "none"`)
331
_, err = apiMachine.WatchContainers("")
332
c.Assert(err, gc.ErrorMatches, "container type must be specified")
335
func (s *provisionerSuite) TestWatchEnvironMachines(c *gc.C) {
336
w, err := s.provisioner.WatchEnvironMachines()
337
c.Assert(err, gc.IsNil)
338
defer statetesting.AssertStop(c, w)
339
wc := statetesting.NewStringsWatcherC(c, s.BackingState, w)
342
wc.AssertChange(s.machine.Id())
344
// Add another 2 machines make sure they are detected.
345
otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
346
c.Assert(err, gc.IsNil)
347
otherMachine, err = s.State.AddMachine("quantal", state.JobHostUnits)
348
c.Assert(err, gc.IsNil)
349
wc.AssertChange("1", "2")
351
// Change the lifecycle of last machine.
352
err = otherMachine.EnsureDead()
353
c.Assert(err, gc.IsNil)
356
// Add a container and make sure it's not detected.
357
template := state.MachineTemplate{
359
Jobs: []state.MachineJob{state.JobHostUnits},
361
_, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
362
c.Assert(err, gc.IsNil)
365
statetesting.AssertStop(c, w)
369
func (s *provisionerSuite) TestStateAddresses(c *gc.C) {
370
err := s.machine.SetAddresses([]instance.Address{
371
instance.NewAddress("0.1.2.3"),
373
c.Assert(err, gc.IsNil)
375
stateAddresses, err := s.State.Addresses()
376
c.Assert(err, gc.IsNil)
378
addresses, err := s.provisioner.StateAddresses()
379
c.Assert(err, gc.IsNil)
380
c.Assert(addresses, gc.DeepEquals, stateAddresses)
383
func (s *provisionerSuite) TestContainerConfig(c *gc.C) {
384
result, err := s.provisioner.ContainerConfig()
385
c.Assert(err, gc.IsNil)
386
c.Assert(result.ProviderType, gc.Equals, "dummy")
387
c.Assert(result.AuthorizedKeys, gc.Equals, coretesting.FakeAuthKeys)
388
c.Assert(result.SSLHostnameVerification, jc.IsTrue)
391
func (s *provisionerSuite) TestToolsWrongMachine(c *gc.C) {
392
tools, err := s.provisioner.Tools("42")
393
c.Assert(err, gc.ErrorMatches, "permission denied")
394
c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized)
395
c.Assert(tools, gc.IsNil)
398
func (s *provisionerSuite) TestTools(c *gc.C) {
399
cur := version.Current
400
curTools := &tools.Tools{Version: cur, URL: ""}
401
curTools.Version.Minor++
402
s.machine.SetAgentVersion(cur)
403
// Provisioner.Tools returns the *desired* set of tools, not the
404
// currently running set. We want to be upgraded to cur.Version
405
stateTools, err := s.provisioner.Tools(s.machine.Tag())
406
c.Assert(err, gc.IsNil)
407
c.Assert(stateTools.Version, gc.Equals, cur)
408
c.Assert(stateTools.URL, gc.Not(gc.Equals), "")
411
func (s *provisionerSuite) TestSetSupportedContainers(c *gc.C) {
412
apiMachine, err := s.provisioner.Machine(s.machine.Tag())
413
c.Assert(err, gc.IsNil)
414
err = apiMachine.SetSupportedContainers(instance.LXC, instance.KVM)
415
c.Assert(err, gc.IsNil)
417
err = s.machine.Refresh()
418
c.Assert(err, gc.IsNil)
419
containers, ok := s.machine.SupportedContainers()
420
c.Assert(ok, jc.IsTrue)
421
c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC, instance.KVM})
424
func (s *provisionerSuite) TestSupportsNoContainers(c *gc.C) {
425
apiMachine, err := s.provisioner.Machine(s.machine.Tag())
426
c.Assert(err, gc.IsNil)
427
err = apiMachine.SupportsNoContainers()
428
c.Assert(err, gc.IsNil)
430
err = s.machine.Refresh()
431
c.Assert(err, gc.IsNil)
432
containers, ok := s.machine.SupportedContainers()
433
c.Assert(ok, jc.IsTrue)
434
c.Assert(containers, gc.DeepEquals, []instance.ContainerType{})