~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/state/machine_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012, 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package state_test
 
5
 
 
6
import (
 
7
        "sort"
 
8
        "time"
 
9
 
 
10
        "github.com/juju/errors"
 
11
        "github.com/juju/loggo"
 
12
        jc "github.com/juju/testing/checkers"
 
13
        jujutxn "github.com/juju/txn"
 
14
        "github.com/juju/version"
 
15
        gc "gopkg.in/check.v1"
 
16
        "gopkg.in/juju/names.v2"
 
17
        "gopkg.in/mgo.v2"
 
18
        "gopkg.in/mgo.v2/bson"
 
19
 
 
20
        "github.com/juju/juju/constraints"
 
21
        "github.com/juju/juju/instance"
 
22
        "github.com/juju/juju/mongo/mongotest"
 
23
        "github.com/juju/juju/network"
 
24
        "github.com/juju/juju/provider/dummy"
 
25
        "github.com/juju/juju/state"
 
26
        "github.com/juju/juju/state/testing"
 
27
        "github.com/juju/juju/status"
 
28
        "github.com/juju/juju/storage/poolmanager"
 
29
        "github.com/juju/juju/storage/provider"
 
30
        coretesting "github.com/juju/juju/testing"
 
31
        "github.com/juju/juju/worker"
 
32
)
 
33
 
 
34
type MachineSuite struct {
 
35
        ConnSuite
 
36
        machine0 *state.Machine
 
37
        machine  *state.Machine
 
38
}
 
39
 
 
40
var _ = gc.Suite(&MachineSuite{})
 
41
 
 
42
func (s *MachineSuite) SetUpTest(c *gc.C) {
 
43
        s.ConnSuite.SetUpTest(c)
 
44
        s.policy.GetConstraintsValidator = func() (constraints.Validator, error) {
 
45
                validator := constraints.NewValidator()
 
46
                validator.RegisterConflicts([]string{constraints.InstanceType}, []string{constraints.Mem})
 
47
                validator.RegisterUnsupported([]string{constraints.CpuPower})
 
48
                return validator, nil
 
49
        }
 
50
        var err error
 
51
        s.machine0, err = s.State.AddMachine("quantal", state.JobManageModel)
 
52
        c.Assert(err, jc.ErrorIsNil)
 
53
        s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
 
54
        c.Assert(err, jc.ErrorIsNil)
 
55
}
 
56
 
 
57
func (s *MachineSuite) TestSetRebootFlagDeadMachine(c *gc.C) {
 
58
        err := s.machine.EnsureDead()
 
59
        c.Assert(err, jc.ErrorIsNil)
 
60
 
 
61
        err = s.machine.SetRebootFlag(true)
 
62
        c.Assert(err, gc.Equals, mgo.ErrNotFound)
 
63
 
 
64
        rFlag, err := s.machine.GetRebootFlag()
 
65
        c.Assert(err, jc.ErrorIsNil)
 
66
        c.Assert(rFlag, jc.IsFalse)
 
67
 
 
68
        err = s.machine.SetRebootFlag(false)
 
69
        c.Assert(err, jc.ErrorIsNil)
 
70
 
 
71
        action, err := s.machine.ShouldRebootOrShutdown()
 
72
        c.Assert(err, jc.ErrorIsNil)
 
73
        c.Assert(action, gc.Equals, state.ShouldDoNothing)
 
74
}
 
75
 
 
76
func (s *MachineSuite) TestSetRebootFlagDeadMachineRace(c *gc.C) {
 
77
        setFlag := jujutxn.TestHook{
 
78
                Before: func() {
 
79
                        err := s.machine.EnsureDead()
 
80
                        c.Assert(err, jc.ErrorIsNil)
 
81
                },
 
82
        }
 
83
        defer state.SetTestHooks(c, s.State, setFlag).Check()
 
84
 
 
85
        err := s.machine.SetRebootFlag(true)
 
86
        c.Assert(err, gc.Equals, mgo.ErrNotFound)
 
87
}
 
88
 
 
89
func (s *MachineSuite) TestSetRebootFlag(c *gc.C) {
 
90
        err := s.machine.SetRebootFlag(true)
 
91
        c.Assert(err, jc.ErrorIsNil)
 
92
 
 
93
        rebootFlag, err := s.machine.GetRebootFlag()
 
94
        c.Assert(err, jc.ErrorIsNil)
 
95
        c.Assert(rebootFlag, jc.IsTrue)
 
96
}
 
97
 
 
98
func (s *MachineSuite) TestSetUnsetRebootFlag(c *gc.C) {
 
99
        err := s.machine.SetRebootFlag(true)
 
100
        c.Assert(err, jc.ErrorIsNil)
 
101
 
 
102
        rebootFlag, err := s.machine.GetRebootFlag()
 
103
        c.Assert(err, jc.ErrorIsNil)
 
104
        c.Assert(rebootFlag, jc.IsTrue)
 
105
 
 
106
        err = s.machine.SetRebootFlag(false)
 
107
        c.Assert(err, jc.ErrorIsNil)
 
108
 
 
109
        rebootFlag, err = s.machine.GetRebootFlag()
 
110
        c.Assert(err, jc.ErrorIsNil)
 
111
        c.Assert(rebootFlag, jc.IsFalse)
 
112
}
 
113
 
 
114
func (s *MachineSuite) TestAddMachineInsideMachineModelDying(c *gc.C) {
 
115
        model, err := s.State.Model()
 
116
        c.Assert(err, jc.ErrorIsNil)
 
117
        c.Assert(model.Destroy(), jc.ErrorIsNil)
 
118
 
 
119
        _, err = s.State.AddMachineInsideMachine(state.MachineTemplate{
 
120
                Series: "quantal",
 
121
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
122
        }, s.machine.Id(), instance.LXD)
 
123
        c.Assert(err, gc.ErrorMatches, `model "testenv" is no longer alive`)
 
124
}
 
125
 
 
126
func (s *MachineSuite) TestAddMachineInsideMachineModelMigrating(c *gc.C) {
 
127
        model, err := s.State.Model()
 
128
        c.Assert(err, jc.ErrorIsNil)
 
129
        c.Assert(model.SetMigrationMode(state.MigrationModeExporting), jc.ErrorIsNil)
 
130
 
 
131
        _, err = s.State.AddMachineInsideMachine(state.MachineTemplate{
 
132
                Series: "quantal",
 
133
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
134
        }, s.machine.Id(), instance.LXD)
 
135
        c.Assert(err, gc.ErrorMatches, `model "testenv" is being migrated`)
 
136
}
 
137
 
 
138
func (s *MachineSuite) TestShouldShutdownOrReboot(c *gc.C) {
 
139
        // Add first container.
 
140
        c1, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
 
141
                Series: "quantal",
 
142
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
143
        }, s.machine.Id(), instance.LXD)
 
144
        c.Assert(err, jc.ErrorIsNil)
 
145
 
 
146
        // Add second container.
 
147
        c2, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
 
148
                Series: "quantal",
 
149
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
150
        }, c1.Id(), instance.LXD)
 
151
        c.Assert(err, jc.ErrorIsNil)
 
152
 
 
153
        err = c2.SetRebootFlag(true)
 
154
        c.Assert(err, jc.ErrorIsNil)
 
155
 
 
156
        rAction, err := s.machine.ShouldRebootOrShutdown()
 
157
        c.Assert(err, jc.ErrorIsNil)
 
158
        c.Assert(rAction, gc.Equals, state.ShouldDoNothing)
 
159
 
 
160
        rAction, err = c1.ShouldRebootOrShutdown()
 
161
        c.Assert(err, jc.ErrorIsNil)
 
162
        c.Assert(rAction, gc.Equals, state.ShouldDoNothing)
 
163
 
 
164
        rAction, err = c2.ShouldRebootOrShutdown()
 
165
        c.Assert(err, jc.ErrorIsNil)
 
166
        c.Assert(rAction, gc.Equals, state.ShouldReboot)
 
167
 
 
168
        // // Reboot happens on the root node
 
169
        err = c2.SetRebootFlag(false)
 
170
        c.Assert(err, jc.ErrorIsNil)
 
171
 
 
172
        err = s.machine.SetRebootFlag(true)
 
173
        c.Assert(err, jc.ErrorIsNil)
 
174
 
 
175
        rAction, err = s.machine.ShouldRebootOrShutdown()
 
176
        c.Assert(err, jc.ErrorIsNil)
 
177
        c.Assert(rAction, gc.Equals, state.ShouldReboot)
 
178
 
 
179
        rAction, err = c1.ShouldRebootOrShutdown()
 
180
        c.Assert(err, jc.ErrorIsNil)
 
181
        c.Assert(rAction, gc.Equals, state.ShouldShutdown)
 
182
 
 
183
        rAction, err = c2.ShouldRebootOrShutdown()
 
184
        c.Assert(err, jc.ErrorIsNil)
 
185
        c.Assert(rAction, gc.Equals, state.ShouldShutdown)
 
186
}
 
187
 
 
188
func (s *MachineSuite) TestContainerDefaults(c *gc.C) {
 
189
        c.Assert(string(s.machine.ContainerType()), gc.Equals, "")
 
190
        containers, err := s.machine.Containers()
 
191
        c.Assert(err, jc.ErrorIsNil)
 
192
        c.Assert(containers, gc.DeepEquals, []string(nil))
 
193
}
 
194
 
 
195
func (s *MachineSuite) TestParentId(c *gc.C) {
 
196
        parentId, ok := s.machine.ParentId()
 
197
        c.Assert(parentId, gc.Equals, "")
 
198
        c.Assert(ok, jc.IsFalse)
 
199
        container, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
 
200
                Series: "quantal",
 
201
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
202
        }, s.machine.Id(), instance.LXD)
 
203
        c.Assert(err, jc.ErrorIsNil)
 
204
        parentId, ok = container.ParentId()
 
205
        c.Assert(parentId, gc.Equals, s.machine.Id())
 
206
        c.Assert(ok, jc.IsTrue)
 
207
}
 
208
 
 
209
func (s *MachineSuite) TestMachineIsManager(c *gc.C) {
 
210
        c.Assert(s.machine0.IsManager(), jc.IsTrue)
 
211
        c.Assert(s.machine.IsManager(), jc.IsFalse)
 
212
}
 
213
 
 
214
func (s *MachineSuite) TestMachineIsManualBootstrap(c *gc.C) {
 
215
        cfg, err := s.State.ModelConfig()
 
216
        c.Assert(err, jc.ErrorIsNil)
 
217
        c.Assert(cfg.Type(), gc.Not(gc.Equals), "null")
 
218
        c.Assert(s.machine.Id(), gc.Equals, "1")
 
219
        manual, err := s.machine0.IsManual()
 
220
        c.Assert(err, jc.ErrorIsNil)
 
221
        c.Assert(manual, jc.IsFalse)
 
222
        attrs := map[string]interface{}{"type": "null"}
 
223
        err = s.State.UpdateModelConfig(attrs, nil, nil)
 
224
        c.Assert(err, jc.ErrorIsNil)
 
225
        manual, err = s.machine0.IsManual()
 
226
        c.Assert(err, jc.ErrorIsNil)
 
227
        c.Assert(manual, jc.IsTrue)
 
228
}
 
229
 
 
230
func (s *MachineSuite) TestMachineIsManual(c *gc.C) {
 
231
        tests := []struct {
 
232
                instanceId instance.Id
 
233
                nonce      string
 
234
                isManual   bool
 
235
        }{
 
236
                {instanceId: "x", nonce: "y", isManual: false},
 
237
                {instanceId: "manual:", nonce: "y", isManual: false},
 
238
                {instanceId: "x", nonce: "manual:", isManual: true},
 
239
                {instanceId: "x", nonce: "manual:y", isManual: true},
 
240
                {instanceId: "x", nonce: "manual", isManual: false},
 
241
        }
 
242
        for _, test := range tests {
 
243
                m, err := s.State.AddOneMachine(state.MachineTemplate{
 
244
                        Series:     "quantal",
 
245
                        Jobs:       []state.MachineJob{state.JobHostUnits},
 
246
                        InstanceId: test.instanceId,
 
247
                        Nonce:      test.nonce,
 
248
                })
 
249
                c.Assert(err, jc.ErrorIsNil)
 
250
                isManual, err := m.IsManual()
 
251
                c.Assert(isManual, gc.Equals, test.isManual)
 
252
        }
 
253
}
 
254
 
 
255
func (s *MachineSuite) TestMachineIsContainer(c *gc.C) {
 
256
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
257
        c.Assert(err, jc.ErrorIsNil)
 
258
 
 
259
        template := state.MachineTemplate{
 
260
                Series: "quantal",
 
261
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
262
        }
 
263
        container, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.LXD)
 
264
        c.Assert(err, jc.ErrorIsNil)
 
265
 
 
266
        c.Assert(machine.IsContainer(), jc.IsFalse)
 
267
        c.Assert(container.IsContainer(), jc.IsTrue)
 
268
}
 
269
 
 
270
func (s *MachineSuite) TestLifeJobManageModel(c *gc.C) {
 
271
        // A JobManageModel machine must never advance lifecycle.
 
272
        m := s.machine0
 
273
        err := m.Destroy()
 
274
        c.Assert(err, gc.ErrorMatches, "machine 0 is required by the model")
 
275
        err = m.ForceDestroy()
 
276
        c.Assert(err, gc.ErrorMatches, "machine is required by the model")
 
277
        err = m.EnsureDead()
 
278
        c.Assert(err, gc.ErrorMatches, "machine 0 is required by the model")
 
279
}
 
280
 
 
281
func (s *MachineSuite) TestLifeMachineWithContainer(c *gc.C) {
 
282
        // A machine hosting a container must not advance lifecycle.
 
283
        _, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
 
284
                Series: "quantal",
 
285
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
286
        }, s.machine.Id(), instance.LXD)
 
287
        c.Assert(err, jc.ErrorIsNil)
 
288
        err = s.machine.Destroy()
 
289
        c.Assert(err, gc.FitsTypeOf, &state.HasContainersError{})
 
290
        c.Assert(err, gc.ErrorMatches, `machine 1 is hosting containers "1/lxd/0"`)
 
291
        err1 := s.machine.EnsureDead()
 
292
        c.Assert(err1, gc.DeepEquals, err)
 
293
        c.Assert(s.machine.Life(), gc.Equals, state.Alive)
 
294
}
 
295
 
 
296
func (s *MachineSuite) TestLifeJobHostUnits(c *gc.C) {
 
297
        // A machine with an assigned unit must not advance lifecycle.
 
298
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
299
        unit, err := svc.AddUnit()
 
300
        c.Assert(err, jc.ErrorIsNil)
 
301
        err = unit.AssignToMachine(s.machine)
 
302
        c.Assert(err, jc.ErrorIsNil)
 
303
        err = s.machine.Destroy()
 
304
        c.Assert(err, jc.Satisfies, state.IsHasAssignedUnitsError)
 
305
        c.Assert(err, gc.ErrorMatches, `machine 1 has unit "wordpress/0" assigned`)
 
306
        err1 := s.machine.EnsureDead()
 
307
        c.Assert(err1, gc.DeepEquals, err)
 
308
        c.Assert(s.machine.Life(), gc.Equals, state.Alive)
 
309
 
 
310
        // Once no unit is assigned, lifecycle can advance.
 
311
        err = unit.UnassignFromMachine()
 
312
        c.Assert(err, jc.ErrorIsNil)
 
313
        err = s.machine.Destroy()
 
314
        c.Assert(s.machine.Life(), gc.Equals, state.Dying)
 
315
        c.Assert(err, jc.ErrorIsNil)
 
316
        err = s.machine.EnsureDead()
 
317
        c.Assert(err, jc.ErrorIsNil)
 
318
        c.Assert(s.machine.Life(), gc.Equals, state.Dead)
 
319
 
 
320
        // A machine that has never had units assigned can advance lifecycle.
 
321
        m, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
322
        c.Assert(err, jc.ErrorIsNil)
 
323
        err = m.Destroy()
 
324
        c.Assert(err, jc.ErrorIsNil)
 
325
        c.Assert(m.Life(), gc.Equals, state.Dying)
 
326
        err = m.EnsureDead()
 
327
        c.Assert(err, jc.ErrorIsNil)
 
328
        c.Assert(m.Life(), gc.Equals, state.Dead)
 
329
}
 
330
 
 
331
func (s *MachineSuite) TestDestroyRemovePorts(c *gc.C) {
 
332
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
333
        unit, err := svc.AddUnit()
 
334
        c.Assert(err, jc.ErrorIsNil)
 
335
        err = unit.AssignToMachine(s.machine)
 
336
        c.Assert(err, jc.ErrorIsNil)
 
337
        err = unit.OpenPort("tcp", 8080)
 
338
        c.Assert(err, jc.ErrorIsNil)
 
339
        ports, err := state.GetPorts(s.State, s.machine.Id(), "")
 
340
        c.Assert(ports, gc.NotNil)
 
341
        c.Assert(err, jc.ErrorIsNil)
 
342
        err = unit.UnassignFromMachine()
 
343
        c.Assert(err, jc.ErrorIsNil)
 
344
        err = s.machine.Destroy()
 
345
        c.Assert(err, jc.ErrorIsNil)
 
346
        err = s.machine.EnsureDead()
 
347
        c.Assert(err, jc.ErrorIsNil)
 
348
        err = s.machine.Remove()
 
349
        c.Assert(err, jc.ErrorIsNil)
 
350
        // once the machine is destroyed, there should be no ports documents present for it
 
351
        ports, err = state.GetPorts(s.State, s.machine.Id(), "")
 
352
        c.Assert(ports, gc.IsNil)
 
353
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
354
}
 
355
 
 
356
func (s *MachineSuite) TestDestroyOps(c *gc.C) {
 
357
        m := s.Factory.MakeMachine(c, nil)
 
358
        ops, err := state.ForceDestroyMachineOps(m)
 
359
        c.Assert(err, jc.ErrorIsNil)
 
360
        c.Assert(ops, gc.NotNil)
 
361
}
 
362
 
 
363
func (s *MachineSuite) TestDestroyOpsForManagerFails(c *gc.C) {
 
364
        // s.Factory does not allow us to make a manager machine, so we grab one
 
365
        // from State ...
 
366
        machines, err := s.State.AllMachines()
 
367
        c.Assert(err, jc.ErrorIsNil)
 
368
        c.Assert(len(machines), jc.GreaterThan, 0)
 
369
        m := machines[0]
 
370
        c.Assert(m.IsManager(), jc.IsTrue)
 
371
 
 
372
        // ... and assert that we cannot get the destroy ops for it.
 
373
        ops, err := state.ForceDestroyMachineOps(m)
 
374
        c.Assert(err, jc.Satisfies, state.IsManagerMachineError)
 
375
        c.Assert(ops, gc.IsNil)
 
376
}
 
377
 
 
378
func (s *MachineSuite) TestDestroyAbort(c *gc.C) {
 
379
        defer state.SetBeforeHooks(c, s.State, func() {
 
380
                c.Assert(s.machine.Destroy(), gc.IsNil)
 
381
        }).Check()
 
382
        err := s.machine.Destroy()
 
383
        c.Assert(err, jc.ErrorIsNil)
 
384
}
 
385
 
 
386
func (s *MachineSuite) TestDestroyCancel(c *gc.C) {
 
387
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
388
        unit, err := svc.AddUnit()
 
389
        c.Assert(err, jc.ErrorIsNil)
 
390
 
 
391
        defer state.SetBeforeHooks(c, s.State, func() {
 
392
                c.Assert(unit.AssignToMachine(s.machine), gc.IsNil)
 
393
        }).Check()
 
394
        err = s.machine.Destroy()
 
395
        c.Assert(err, jc.Satisfies, state.IsHasAssignedUnitsError)
 
396
}
 
397
 
 
398
func (s *MachineSuite) TestDestroyContention(c *gc.C) {
 
399
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
400
        unit, err := svc.AddUnit()
 
401
        c.Assert(err, jc.ErrorIsNil)
 
402
 
 
403
        perturb := jujutxn.TestHook{
 
404
                Before: func() { c.Assert(unit.AssignToMachine(s.machine), gc.IsNil) },
 
405
                After:  func() { c.Assert(unit.UnassignFromMachine(), gc.IsNil) },
 
406
        }
 
407
        defer state.SetTestHooks(c, s.State, perturb, perturb, perturb).Check()
 
408
 
 
409
        err = s.machine.Destroy()
 
410
        c.Assert(err, gc.ErrorMatches, "machine 1 cannot advance lifecycle: state changing too quickly; try again soon")
 
411
}
 
412
 
 
413
func (s *MachineSuite) TestDestroyWithServiceDestroyPending(c *gc.C) {
 
414
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
415
        unit, err := svc.AddUnit()
 
416
        c.Assert(err, jc.ErrorIsNil)
 
417
        err = unit.AssignToMachine(s.machine)
 
418
        c.Assert(err, jc.ErrorIsNil)
 
419
 
 
420
        err = svc.Destroy()
 
421
        c.Assert(err, jc.ErrorIsNil)
 
422
        err = s.machine.Destroy()
 
423
        c.Assert(err, jc.ErrorIsNil)
 
424
        // Machine is still advanced to Dying.
 
425
        life := s.machine.Life()
 
426
        c.Assert(life, gc.Equals, state.Dying)
 
427
}
 
428
 
 
429
func (s *MachineSuite) TestDestroyFailsWhenNewUnitAdded(c *gc.C) {
 
430
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
431
        unit, err := svc.AddUnit()
 
432
        c.Assert(err, jc.ErrorIsNil)
 
433
        err = unit.AssignToMachine(s.machine)
 
434
        c.Assert(err, jc.ErrorIsNil)
 
435
 
 
436
        err = svc.Destroy()
 
437
        c.Assert(err, jc.ErrorIsNil)
 
438
 
 
439
        defer state.SetBeforeHooks(c, s.State, func() {
 
440
                anotherSvc := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
 
441
                anotherUnit, err := anotherSvc.AddUnit()
 
442
                c.Assert(err, jc.ErrorIsNil)
 
443
                err = anotherUnit.AssignToMachine(s.machine)
 
444
                c.Assert(err, jc.ErrorIsNil)
 
445
        }).Check()
 
446
 
 
447
        err = s.machine.Destroy()
 
448
        c.Assert(err, jc.Satisfies, state.IsHasAssignedUnitsError)
 
449
        life := s.machine.Life()
 
450
        c.Assert(life, gc.Equals, state.Alive)
 
451
}
 
452
 
 
453
func (s *MachineSuite) TestDestroyWithUnitDestroyPending(c *gc.C) {
 
454
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
455
        unit, err := svc.AddUnit()
 
456
        c.Assert(err, jc.ErrorIsNil)
 
457
        err = unit.AssignToMachine(s.machine)
 
458
        c.Assert(err, jc.ErrorIsNil)
 
459
 
 
460
        err = unit.Destroy()
 
461
        c.Assert(err, jc.ErrorIsNil)
 
462
        err = s.machine.Destroy()
 
463
        c.Assert(err, jc.ErrorIsNil)
 
464
        // Machine is still advanced to Dying.
 
465
        life := s.machine.Life()
 
466
        c.Assert(life, gc.Equals, state.Dying)
 
467
}
 
468
 
 
469
func (s *MachineSuite) TestDestroyFailsWhenNewContainerAdded(c *gc.C) {
 
470
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
471
        unit, err := svc.AddUnit()
 
472
        c.Assert(err, jc.ErrorIsNil)
 
473
        err = unit.AssignToMachine(s.machine)
 
474
        c.Assert(err, jc.ErrorIsNil)
 
475
 
 
476
        err = svc.Destroy()
 
477
        c.Assert(err, jc.ErrorIsNil)
 
478
 
 
479
        defer state.SetBeforeHooks(c, s.State, func() {
 
480
                _, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
 
481
                        Series: "quantal",
 
482
                        Jobs:   []state.MachineJob{state.JobHostUnits},
 
483
                }, s.machine.Id(), instance.LXD)
 
484
                c.Assert(err, jc.ErrorIsNil)
 
485
        }).Check()
 
486
 
 
487
        err = s.machine.Destroy()
 
488
        c.Assert(err, jc.Satisfies, state.IsHasAssignedUnitsError)
 
489
        life := s.machine.Life()
 
490
        c.Assert(life, gc.Equals, state.Alive)
 
491
}
 
492
 
 
493
func (s *MachineSuite) TestRemove(c *gc.C) {
 
494
        err := s.State.SetSSHHostKeys(s.machine.MachineTag(), state.SSHHostKeys{"rsa", "dsa"})
 
495
        c.Assert(err, jc.ErrorIsNil)
 
496
 
 
497
        err = s.machine.Remove()
 
498
        c.Assert(err, gc.ErrorMatches, "cannot remove machine 1: machine is not dead")
 
499
 
 
500
        err = s.machine.EnsureDead()
 
501
        c.Assert(err, jc.ErrorIsNil)
 
502
 
 
503
        err = s.machine.Remove()
 
504
        c.Assert(err, jc.ErrorIsNil)
 
505
 
 
506
        err = s.machine.Refresh()
 
507
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
508
 
 
509
        _, err = s.machine.HardwareCharacteristics()
 
510
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
511
 
 
512
        _, err = s.machine.Containers()
 
513
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
514
 
 
515
        _, err = s.State.GetSSHHostKeys(s.machine.MachineTag())
 
516
        c.Assert(errors.IsNotFound(err), jc.IsTrue)
 
517
 
 
518
        // Removing an already removed machine is OK.
 
519
        err = s.machine.Remove()
 
520
        c.Assert(err, jc.ErrorIsNil)
 
521
}
 
522
 
 
523
func (s *MachineSuite) TestHasVote(c *gc.C) {
 
524
        c.Assert(s.machine.HasVote(), jc.IsFalse)
 
525
 
 
526
        // Make another machine value so that
 
527
        // it won't have the cached HasVote value.
 
528
        m, err := s.State.Machine(s.machine.Id())
 
529
        c.Assert(err, jc.ErrorIsNil)
 
530
 
 
531
        err = s.machine.SetHasVote(true)
 
532
        c.Assert(err, jc.ErrorIsNil)
 
533
        c.Assert(s.machine.HasVote(), jc.IsTrue)
 
534
        c.Assert(m.HasVote(), jc.IsFalse)
 
535
 
 
536
        err = m.Refresh()
 
537
        c.Assert(err, jc.ErrorIsNil)
 
538
        c.Assert(m.HasVote(), jc.IsTrue)
 
539
 
 
540
        err = m.SetHasVote(false)
 
541
        c.Assert(err, jc.ErrorIsNil)
 
542
        c.Assert(m.HasVote(), jc.IsFalse)
 
543
 
 
544
        c.Assert(s.machine.HasVote(), jc.IsTrue)
 
545
        err = s.machine.Refresh()
 
546
        c.Assert(err, jc.ErrorIsNil)
 
547
        c.Assert(s.machine.HasVote(), jc.IsFalse)
 
548
}
 
549
 
 
550
func (s *MachineSuite) TestCannotDestroyMachineWithVote(c *gc.C) {
 
551
        err := s.machine.SetHasVote(true)
 
552
        c.Assert(err, jc.ErrorIsNil)
 
553
 
 
554
        // Make another machine value so that
 
555
        // it won't have the cached HasVote value.
 
556
        m, err := s.State.Machine(s.machine.Id())
 
557
        c.Assert(err, jc.ErrorIsNil)
 
558
 
 
559
        err = s.machine.Destroy()
 
560
        c.Assert(err, gc.ErrorMatches, "machine "+s.machine.Id()+" is a voting replica set member")
 
561
 
 
562
        err = m.Destroy()
 
563
        c.Assert(err, gc.ErrorMatches, "machine "+s.machine.Id()+" is a voting replica set member")
 
564
}
 
565
 
 
566
func (s *MachineSuite) TestRemoveAbort(c *gc.C) {
 
567
        err := s.machine.EnsureDead()
 
568
        c.Assert(err, jc.ErrorIsNil)
 
569
 
 
570
        defer state.SetBeforeHooks(c, s.State, func() {
 
571
                c.Assert(s.machine.Remove(), gc.IsNil)
 
572
        }).Check()
 
573
        err = s.machine.Remove()
 
574
        c.Assert(err, jc.ErrorIsNil)
 
575
}
 
576
 
 
577
func (s *MachineSuite) TestMachineSetAgentPresence(c *gc.C) {
 
578
        alive, err := s.machine.AgentPresence()
 
579
        c.Assert(err, jc.ErrorIsNil)
 
580
        c.Assert(alive, jc.IsFalse)
 
581
 
 
582
        pinger, err := s.machine.SetAgentPresence()
 
583
        c.Assert(err, jc.ErrorIsNil)
 
584
        c.Assert(pinger, gc.NotNil)
 
585
        defer func() {
 
586
                c.Assert(worker.Stop(pinger), jc.ErrorIsNil)
 
587
        }()
 
588
 
 
589
        s.State.StartSync()
 
590
        alive, err = s.machine.AgentPresence()
 
591
        c.Assert(err, jc.ErrorIsNil)
 
592
        c.Assert(alive, jc.IsTrue)
 
593
}
 
594
 
 
595
func (s *MachineSuite) TestTag(c *gc.C) {
 
596
        tag := s.machine.MachineTag()
 
597
        c.Assert(tag.Kind(), gc.Equals, names.MachineTagKind)
 
598
        c.Assert(tag.Id(), gc.Equals, "1")
 
599
 
 
600
        // To keep gccgo happy, don't compare an interface with a struct.
 
601
        var asTag names.Tag = tag
 
602
        c.Assert(s.machine.Tag(), gc.Equals, asTag)
 
603
}
 
604
 
 
605
func (s *MachineSuite) TestSetMongoPassword(c *gc.C) {
 
606
        info := testing.NewMongoInfo()
 
607
        st, err := state.Open(s.modelTag, info, mongotest.DialOpts(), state.NewPolicyFunc(nil))
 
608
        c.Assert(err, jc.ErrorIsNil)
 
609
        defer func() {
 
610
                // Remove the admin password so that the test harness can reset the state.
 
611
                err := st.SetAdminMongoPassword("")
 
612
                c.Check(err, jc.ErrorIsNil)
 
613
                err = st.Close()
 
614
                c.Check(err, jc.ErrorIsNil)
 
615
        }()
 
616
 
 
617
        // Turn on fully-authenticated mode.
 
618
        err = st.SetAdminMongoPassword("admin-secret")
 
619
        c.Assert(err, jc.ErrorIsNil)
 
620
        err = st.MongoSession().DB("admin").Login("admin", "admin-secret")
 
621
        c.Assert(err, jc.ErrorIsNil)
 
622
 
 
623
        // Set the password for the entity
 
624
        ent, err := st.Machine("0")
 
625
        c.Assert(err, jc.ErrorIsNil)
 
626
        err = ent.SetMongoPassword("foo")
 
627
        c.Assert(err, jc.ErrorIsNil)
 
628
 
 
629
        // Check that we cannot log in with the wrong password.
 
630
        info.Tag = ent.Tag()
 
631
        info.Password = "bar"
 
632
        err = tryOpenState(s.modelTag, info)
 
633
        c.Check(errors.Cause(err), jc.Satisfies, errors.IsUnauthorized)
 
634
        c.Check(err, gc.ErrorMatches, `cannot log in to admin database as "machine-0": unauthorized mongo access: .*`)
 
635
 
 
636
        // Check that we can log in with the correct password.
 
637
        info.Password = "foo"
 
638
        st1, err := state.Open(s.modelTag, info, mongotest.DialOpts(), state.NewPolicyFunc(nil))
 
639
        c.Assert(err, jc.ErrorIsNil)
 
640
        defer st1.Close()
 
641
 
 
642
        // Change the password with an entity derived from the newly
 
643
        // opened and authenticated state.
 
644
        ent, err = st.Machine("0")
 
645
        c.Assert(err, jc.ErrorIsNil)
 
646
        err = ent.SetMongoPassword("bar")
 
647
        c.Assert(err, jc.ErrorIsNil)
 
648
 
 
649
        // Check that we cannot log in with the old password.
 
650
        info.Password = "foo"
 
651
        err = tryOpenState(s.modelTag, info)
 
652
        c.Check(errors.Cause(err), jc.Satisfies, errors.IsUnauthorized)
 
653
        c.Check(err, gc.ErrorMatches, `cannot log in to admin database as "machine-0": unauthorized mongo access: .*`)
 
654
 
 
655
        // Check that we can log in with the correct password.
 
656
        info.Password = "bar"
 
657
        err = tryOpenState(s.modelTag, info)
 
658
        c.Assert(err, jc.ErrorIsNil)
 
659
 
 
660
        // Check that the administrator can still log in.
 
661
        info.Tag, info.Password = nil, "admin-secret"
 
662
        err = tryOpenState(s.modelTag, info)
 
663
        c.Assert(err, jc.ErrorIsNil)
 
664
}
 
665
 
 
666
func (s *MachineSuite) TestSetPassword(c *gc.C) {
 
667
        testSetPassword(c, func() (state.Authenticator, error) {
 
668
                return s.State.Machine(s.machine.Id())
 
669
        })
 
670
}
 
671
 
 
672
func (s *MachineSuite) TestMachineWaitAgentPresence(c *gc.C) {
 
673
        alive, err := s.machine.AgentPresence()
 
674
        c.Assert(err, jc.ErrorIsNil)
 
675
        c.Assert(alive, jc.IsFalse)
 
676
 
 
677
        s.State.StartSync()
 
678
        err = s.machine.WaitAgentPresence(coretesting.ShortWait)
 
679
        c.Assert(err, gc.ErrorMatches, `waiting for agent of machine 1: still not alive after timeout`)
 
680
 
 
681
        pinger, err := s.machine.SetAgentPresence()
 
682
        c.Assert(err, jc.ErrorIsNil)
 
683
 
 
684
        s.State.StartSync()
 
685
        err = s.machine.WaitAgentPresence(coretesting.LongWait)
 
686
        c.Assert(err, jc.ErrorIsNil)
 
687
 
 
688
        alive, err = s.machine.AgentPresence()
 
689
        c.Assert(err, jc.ErrorIsNil)
 
690
        c.Assert(alive, jc.IsTrue)
 
691
 
 
692
        err = pinger.KillForTesting()
 
693
        c.Assert(err, jc.ErrorIsNil)
 
694
 
 
695
        s.State.StartSync()
 
696
        alive, err = s.machine.AgentPresence()
 
697
        c.Assert(err, jc.ErrorIsNil)
 
698
        c.Assert(alive, jc.IsFalse)
 
699
}
 
700
 
 
701
func (s *MachineSuite) TestMachineInstanceIdCorrupt(c *gc.C) {
 
702
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
703
        c.Assert(err, jc.ErrorIsNil)
 
704
        err = s.machines.Update(
 
705
                bson.D{{"_id", state.DocID(s.State, machine.Id())}},
 
706
                bson.D{{"$set", bson.D{{"instanceid", bson.D{{"foo", "bar"}}}}}},
 
707
        )
 
708
        c.Assert(err, jc.ErrorIsNil)
 
709
 
 
710
        err = machine.Refresh()
 
711
        c.Assert(err, jc.ErrorIsNil)
 
712
        iid, err := machine.InstanceId()
 
713
        c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
 
714
        c.Assert(iid, gc.Equals, instance.Id(""))
 
715
}
 
716
 
 
717
func (s *MachineSuite) TestMachineInstanceIdMissing(c *gc.C) {
 
718
        iid, err := s.machine.InstanceId()
 
719
        c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
 
720
        c.Assert(string(iid), gc.Equals, "")
 
721
}
 
722
 
 
723
func (s *MachineSuite) TestMachineInstanceIdBlank(c *gc.C) {
 
724
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
725
        c.Assert(err, jc.ErrorIsNil)
 
726
        err = s.machines.Update(
 
727
                bson.D{{"_id", state.DocID(s.State, machine.Id())}},
 
728
                bson.D{{"$set", bson.D{{"instanceid", ""}}}},
 
729
        )
 
730
        c.Assert(err, jc.ErrorIsNil)
 
731
 
 
732
        err = machine.Refresh()
 
733
        c.Assert(err, jc.ErrorIsNil)
 
734
        iid, err := machine.InstanceId()
 
735
        c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
 
736
        c.Assert(string(iid), gc.Equals, "")
 
737
}
 
738
 
 
739
func (s *MachineSuite) TestMachineSetProvisionedUpdatesCharacteristics(c *gc.C) {
 
740
        // Before provisioning, there is no hardware characteristics.
 
741
        _, err := s.machine.HardwareCharacteristics()
 
742
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
743
        arch := "amd64"
 
744
        mem := uint64(4096)
 
745
        expected := &instance.HardwareCharacteristics{
 
746
                Arch: &arch,
 
747
                Mem:  &mem,
 
748
        }
 
749
        err = s.machine.SetProvisioned("umbrella/0", "fake_nonce", expected)
 
750
        c.Assert(err, jc.ErrorIsNil)
 
751
        md, err := s.machine.HardwareCharacteristics()
 
752
        c.Assert(err, jc.ErrorIsNil)
 
753
        c.Assert(*md, gc.DeepEquals, *expected)
 
754
 
 
755
        // Reload machine and check again.
 
756
        err = s.machine.Refresh()
 
757
        c.Assert(err, jc.ErrorIsNil)
 
758
        md, err = s.machine.HardwareCharacteristics()
 
759
        c.Assert(err, jc.ErrorIsNil)
 
760
        c.Assert(*md, gc.DeepEquals, *expected)
 
761
}
 
762
 
 
763
func (s *MachineSuite) TestMachineAvailabilityZone(c *gc.C) {
 
764
        zone := "a_zone"
 
765
        hwc := &instance.HardwareCharacteristics{
 
766
                AvailabilityZone: &zone,
 
767
        }
 
768
        err := s.machine.SetProvisioned("umbrella/0", "fake_nonce", hwc)
 
769
        c.Assert(err, jc.ErrorIsNil)
 
770
 
 
771
        zone, err = s.machine.AvailabilityZone()
 
772
        c.Assert(err, jc.ErrorIsNil)
 
773
        c.Check(zone, gc.Equals, "a_zone")
 
774
}
 
775
 
 
776
func (s *MachineSuite) TestMachineAvailabilityZoneEmpty(c *gc.C) {
 
777
        zone := ""
 
778
        hwc := &instance.HardwareCharacteristics{
 
779
                AvailabilityZone: &zone,
 
780
        }
 
781
        err := s.machine.SetProvisioned("umbrella/0", "fake_nonce", hwc)
 
782
        c.Assert(err, jc.ErrorIsNil)
 
783
 
 
784
        zone, err = s.machine.AvailabilityZone()
 
785
        c.Assert(err, jc.ErrorIsNil)
 
786
        c.Check(zone, gc.Equals, "")
 
787
}
 
788
 
 
789
func (s *MachineSuite) TestMachineAvailabilityZoneMissing(c *gc.C) {
 
790
        zone := "a_zone"
 
791
        hwc := &instance.HardwareCharacteristics{}
 
792
        err := s.machine.SetProvisioned("umbrella/0", "fake_nonce", hwc)
 
793
        c.Assert(err, jc.ErrorIsNil)
 
794
 
 
795
        zone, err = s.machine.AvailabilityZone()
 
796
        c.Assert(err, jc.ErrorIsNil)
 
797
        c.Check(zone, gc.Equals, "")
 
798
}
 
799
 
 
800
func (s *MachineSuite) TestMachineSetCheckProvisioned(c *gc.C) {
 
801
        // Check before provisioning.
 
802
        c.Assert(s.machine.CheckProvisioned("fake_nonce"), jc.IsFalse)
 
803
 
 
804
        // Either one should not be empty.
 
805
        err := s.machine.SetProvisioned("umbrella/0", "", nil)
 
806
        c.Assert(err, gc.ErrorMatches, `cannot set instance data for machine "1": instance id and nonce cannot be empty`)
 
807
        err = s.machine.SetProvisioned("", "fake_nonce", nil)
 
808
        c.Assert(err, gc.ErrorMatches, `cannot set instance data for machine "1": instance id and nonce cannot be empty`)
 
809
        err = s.machine.SetProvisioned("", "", nil)
 
810
        c.Assert(err, gc.ErrorMatches, `cannot set instance data for machine "1": instance id and nonce cannot be empty`)
 
811
 
 
812
        err = s.machine.SetProvisioned("umbrella/0", "fake_nonce", nil)
 
813
        c.Assert(err, jc.ErrorIsNil)
 
814
 
 
815
        m, err := s.State.Machine(s.machine.Id())
 
816
        c.Assert(err, jc.ErrorIsNil)
 
817
        id, err := m.InstanceId()
 
818
        c.Assert(err, jc.ErrorIsNil)
 
819
        c.Assert(string(id), gc.Equals, "umbrella/0")
 
820
        c.Assert(s.machine.CheckProvisioned("fake_nonce"), jc.IsTrue)
 
821
        id, err = s.machine.InstanceId()
 
822
        c.Assert(err, jc.ErrorIsNil)
 
823
        c.Assert(string(id), gc.Equals, "umbrella/0")
 
824
        c.Assert(s.machine.CheckProvisioned("fake_nonce"), jc.IsTrue)
 
825
 
 
826
        // Try it twice, it should fail.
 
827
        err = s.machine.SetProvisioned("doesn't-matter", "phony", nil)
 
828
        c.Assert(err, gc.ErrorMatches, `cannot set instance data for machine "1": already set`)
 
829
 
 
830
        // Check it with invalid nonce.
 
831
        c.Assert(s.machine.CheckProvisioned("not-really"), jc.IsFalse)
 
832
}
 
833
 
 
834
func (s *MachineSuite) TestMachineSetInstanceInfoFailureDoesNotProvision(c *gc.C) {
 
835
        assertNotProvisioned := func() {
 
836
                c.Assert(s.machine.CheckProvisioned("fake_nonce"), jc.IsFalse)
 
837
        }
 
838
 
 
839
        assertNotProvisioned()
 
840
 
 
841
        invalidVolumes := map[names.VolumeTag]state.VolumeInfo{
 
842
                names.NewVolumeTag("1065"): state.VolumeInfo{VolumeId: "vol-ume"},
 
843
        }
 
844
        err := s.machine.SetInstanceInfo("umbrella/0", "fake_nonce", nil, nil, nil, invalidVolumes, nil)
 
845
        c.Assert(err, gc.ErrorMatches, `cannot set info for volume \"1065\": volume \"1065\" not found`)
 
846
        assertNotProvisioned()
 
847
 
 
848
        invalidVolumes = map[names.VolumeTag]state.VolumeInfo{
 
849
                names.NewVolumeTag("1065"): state.VolumeInfo{},
 
850
        }
 
851
        err = s.machine.SetInstanceInfo("umbrella/0", "fake_nonce", nil, nil, nil, invalidVolumes, nil)
 
852
        c.Assert(err, gc.ErrorMatches, `cannot set info for volume \"1065\": volume ID not set`)
 
853
        assertNotProvisioned()
 
854
 
 
855
        // TODO(axw) test invalid volume attachment
 
856
}
 
857
 
 
858
func (s *MachineSuite) addVolume(c *gc.C, params state.VolumeParams, machineId string) names.VolumeTag {
 
859
        ops, tag, err := state.AddVolumeOps(s.State, params, machineId)
 
860
        c.Assert(err, jc.ErrorIsNil)
 
861
        err = state.RunTransaction(s.State, ops)
 
862
        c.Assert(err, jc.ErrorIsNil)
 
863
        return tag
 
864
}
 
865
 
 
866
func (s *MachineSuite) TestMachineSetInstanceInfoSuccess(c *gc.C) {
 
867
        pm := poolmanager.New(state.NewStateSettings(s.State), dummy.StorageProviders())
 
868
        _, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{})
 
869
        c.Assert(err, jc.ErrorIsNil)
 
870
 
 
871
        // Must create the requested block device prior to SetInstanceInfo.
 
872
        volumeTag := s.addVolume(c, state.VolumeParams{Size: 1000, Pool: "loop-pool"}, "123")
 
873
        c.Assert(volumeTag, gc.Equals, names.NewVolumeTag("123/0"))
 
874
 
 
875
        c.Assert(s.machine.CheckProvisioned("fake_nonce"), jc.IsFalse)
 
876
        volumeInfo := state.VolumeInfo{
 
877
                VolumeId: "storage-123",
 
878
                Size:     1234,
 
879
        }
 
880
        volumes := map[names.VolumeTag]state.VolumeInfo{volumeTag: volumeInfo}
 
881
        err = s.machine.SetInstanceInfo("umbrella/0", "fake_nonce", nil, nil, nil, volumes, nil)
 
882
        c.Assert(err, jc.ErrorIsNil)
 
883
        c.Assert(s.machine.CheckProvisioned("fake_nonce"), jc.IsTrue)
 
884
 
 
885
        volume, err := s.State.Volume(volumeTag)
 
886
        c.Assert(err, jc.ErrorIsNil)
 
887
        info, err := volume.Info()
 
888
        c.Assert(err, jc.ErrorIsNil)
 
889
        volumeInfo.Pool = "loop-pool" // taken from params
 
890
        c.Assert(info, gc.Equals, volumeInfo)
 
891
}
 
892
 
 
893
func (s *MachineSuite) TestMachineSetProvisionedWhenNotAlive(c *gc.C) {
 
894
        testWhenDying(c, s.machine, notAliveErr, notAliveErr, func() error {
 
895
                return s.machine.SetProvisioned("umbrella/0", "fake_nonce", nil)
 
896
        })
 
897
}
 
898
 
 
899
func (s *MachineSuite) TestMachineSetInstanceStatus(c *gc.C) {
 
900
        // Machine needs to be provisioned first.
 
901
        err := s.machine.SetProvisioned("umbrella/0", "fake_nonce", nil)
 
902
        c.Assert(err, jc.ErrorIsNil)
 
903
 
 
904
        now := time.Now()
 
905
        sInfo := status.StatusInfo{
 
906
                Status:  status.StatusRunning,
 
907
                Message: "alive",
 
908
                Since:   &now,
 
909
        }
 
910
        err = s.machine.SetInstanceStatus(sInfo)
 
911
        c.Assert(err, jc.ErrorIsNil)
 
912
 
 
913
        // Reload machine and check result.
 
914
        err = s.machine.Refresh()
 
915
        c.Assert(err, jc.ErrorIsNil)
 
916
        machineStatus, err := s.machine.InstanceStatus()
 
917
        c.Assert(err, jc.ErrorIsNil)
 
918
        c.Assert(machineStatus.Status, gc.DeepEquals, status.StatusRunning)
 
919
        c.Assert(machineStatus.Message, gc.DeepEquals, "alive")
 
920
}
 
921
 
 
922
func (s *MachineSuite) TestMachineRefresh(c *gc.C) {
 
923
        m0, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
924
        c.Assert(err, jc.ErrorIsNil)
 
925
        oldTools, _ := m0.AgentTools()
 
926
        m1, err := s.State.Machine(m0.Id())
 
927
        c.Assert(err, jc.ErrorIsNil)
 
928
        err = m0.SetAgentVersion(version.MustParseBinary("0.0.3-quantal-amd64"))
 
929
        c.Assert(err, jc.ErrorIsNil)
 
930
        newTools, _ := m0.AgentTools()
 
931
 
 
932
        m1Tools, _ := m1.AgentTools()
 
933
        c.Assert(m1Tools, gc.DeepEquals, oldTools)
 
934
        err = m1.Refresh()
 
935
        c.Assert(err, jc.ErrorIsNil)
 
936
        m1Tools, _ = m1.AgentTools()
 
937
        c.Assert(*m1Tools, gc.Equals, *newTools)
 
938
 
 
939
        err = m0.EnsureDead()
 
940
        c.Assert(err, jc.ErrorIsNil)
 
941
        err = m0.Remove()
 
942
        c.Assert(err, jc.ErrorIsNil)
 
943
        err = m0.Refresh()
 
944
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
945
}
 
946
 
 
947
func (s *MachineSuite) TestRefreshWhenNotAlive(c *gc.C) {
 
948
        // Refresh should work regardless of liveness status.
 
949
        testWhenDying(c, s.machine, noErr, noErr, func() error {
 
950
                return s.machine.Refresh()
 
951
        })
 
952
}
 
953
 
 
954
func (s *MachineSuite) TestMachinePrincipalUnits(c *gc.C) {
 
955
        // Check that Machine.Units and st.UnitsFor work correctly.
 
956
 
 
957
        // Make three machines, three services and three units for each service;
 
958
        // variously assign units to machines and check that Machine.Units
 
959
        // tells us the right thing.
 
960
 
 
961
        m1 := s.machine
 
962
        m2, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
963
        c.Assert(err, jc.ErrorIsNil)
 
964
        m3, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
965
        c.Assert(err, jc.ErrorIsNil)
 
966
 
 
967
        dummy := s.AddTestingCharm(c, "dummy")
 
968
        logging := s.AddTestingCharm(c, "logging")
 
969
        s0 := s.AddTestingService(c, "s0", dummy)
 
970
        s1 := s.AddTestingService(c, "s1", dummy)
 
971
        s2 := s.AddTestingService(c, "s2", dummy)
 
972
        s3 := s.AddTestingService(c, "s3", logging)
 
973
 
 
974
        units := make([][]*state.Unit, 4)
 
975
        for i, svc := range []*state.Application{s0, s1, s2} {
 
976
                units[i] = make([]*state.Unit, 3)
 
977
                for j := range units[i] {
 
978
                        units[i][j], err = svc.AddUnit()
 
979
                        c.Assert(err, jc.ErrorIsNil)
 
980
                }
 
981
        }
 
982
        // Add the logging units subordinate to the s2 units.
 
983
        eps, err := s.State.InferEndpoints("s2", "s3")
 
984
        c.Assert(err, jc.ErrorIsNil)
 
985
        rel, err := s.State.AddRelation(eps...)
 
986
        c.Assert(err, jc.ErrorIsNil)
 
987
        for _, u := range units[2] {
 
988
                ru, err := rel.Unit(u)
 
989
                c.Assert(err, jc.ErrorIsNil)
 
990
                err = ru.EnterScope(nil)
 
991
                c.Assert(err, jc.ErrorIsNil)
 
992
        }
 
993
        units[3], err = s3.AllUnits()
 
994
        c.Assert(err, jc.ErrorIsNil)
 
995
        c.Assert(sortedUnitNames(units[3]), jc.DeepEquals, []string{"s3/0", "s3/1", "s3/2"})
 
996
 
 
997
        assignments := []struct {
 
998
                machine      *state.Machine
 
999
                units        []*state.Unit
 
1000
                subordinates []*state.Unit
 
1001
        }{
 
1002
                {m1, []*state.Unit{units[0][0]}, nil},
 
1003
                {m2, []*state.Unit{units[0][1], units[1][0], units[1][1], units[2][0]}, []*state.Unit{units[3][0]}},
 
1004
                {m3, []*state.Unit{units[2][2]}, []*state.Unit{units[3][2]}},
 
1005
        }
 
1006
 
 
1007
        for _, a := range assignments {
 
1008
                for _, u := range a.units {
 
1009
                        err := u.AssignToMachine(a.machine)
 
1010
                        c.Assert(err, jc.ErrorIsNil)
 
1011
                }
 
1012
        }
 
1013
 
 
1014
        for i, a := range assignments {
 
1015
                c.Logf("test %d", i)
 
1016
                expect := sortedUnitNames(append(a.units, a.subordinates...))
 
1017
 
 
1018
                // The units can be retrieved from the machine model.
 
1019
                got, err := a.machine.Units()
 
1020
                c.Assert(err, jc.ErrorIsNil)
 
1021
                c.Assert(sortedUnitNames(got), jc.DeepEquals, expect)
 
1022
 
 
1023
                // The units can be retrieved from the machine id.
 
1024
                got, err = s.State.UnitsFor(a.machine.Id())
 
1025
                c.Assert(err, jc.ErrorIsNil)
 
1026
                c.Assert(sortedUnitNames(got), jc.DeepEquals, expect)
 
1027
        }
 
1028
}
 
1029
 
 
1030
func sortedUnitNames(units []*state.Unit) []string {
 
1031
        names := make([]string, len(units))
 
1032
        for i, u := range units {
 
1033
                names[i] = u.Name()
 
1034
        }
 
1035
        sort.Strings(names)
 
1036
        return names
 
1037
}
 
1038
 
 
1039
func (s *MachineSuite) assertMachineDirtyAfterAddingUnit(c *gc.C) (*state.Machine, *state.Application, *state.Unit) {
 
1040
        m, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1041
        c.Assert(err, jc.ErrorIsNil)
 
1042
        c.Assert(m.Clean(), jc.IsTrue)
 
1043
 
 
1044
        svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
 
1045
        unit, err := svc.AddUnit()
 
1046
        c.Assert(err, jc.ErrorIsNil)
 
1047
        err = unit.AssignToMachine(m)
 
1048
        c.Assert(err, jc.ErrorIsNil)
 
1049
        c.Assert(m.Clean(), jc.IsFalse)
 
1050
        return m, svc, unit
 
1051
}
 
1052
 
 
1053
func (s *MachineSuite) TestMachineDirtyAfterAddingUnit(c *gc.C) {
 
1054
        s.assertMachineDirtyAfterAddingUnit(c)
 
1055
}
 
1056
 
 
1057
func (s *MachineSuite) TestMachineDirtyAfterUnassigningUnit(c *gc.C) {
 
1058
        m, _, unit := s.assertMachineDirtyAfterAddingUnit(c)
 
1059
        err := unit.UnassignFromMachine()
 
1060
        c.Assert(err, jc.ErrorIsNil)
 
1061
        c.Assert(m.Clean(), jc.IsFalse)
 
1062
}
 
1063
 
 
1064
func (s *MachineSuite) TestMachineDirtyAfterRemovingUnit(c *gc.C) {
 
1065
        m, svc, unit := s.assertMachineDirtyAfterAddingUnit(c)
 
1066
        err := unit.EnsureDead()
 
1067
        c.Assert(err, jc.ErrorIsNil)
 
1068
        err = unit.Remove()
 
1069
        c.Assert(err, jc.ErrorIsNil)
 
1070
        err = svc.Destroy()
 
1071
        c.Assert(err, jc.ErrorIsNil)
 
1072
        c.Assert(m.Clean(), jc.IsFalse)
 
1073
}
 
1074
 
 
1075
func (s *MachineSuite) TestWatchMachine(c *gc.C) {
 
1076
        w := s.machine.Watch()
 
1077
        defer testing.AssertStop(c, w)
 
1078
 
 
1079
        // Initial event.
 
1080
        wc := testing.NewNotifyWatcherC(c, s.State, w)
 
1081
        wc.AssertOneChange()
 
1082
 
 
1083
        // Make one change (to a separate instance), check one event.
 
1084
        machine, err := s.State.Machine(s.machine.Id())
 
1085
        c.Assert(err, jc.ErrorIsNil)
 
1086
        err = machine.SetProvisioned("m-foo", "fake_nonce", nil)
 
1087
        c.Assert(err, jc.ErrorIsNil)
 
1088
        wc.AssertOneChange()
 
1089
 
 
1090
        // Make two changes, check one event.
 
1091
        err = machine.SetAgentVersion(version.MustParseBinary("0.0.3-quantal-amd64"))
 
1092
        c.Assert(err, jc.ErrorIsNil)
 
1093
        err = machine.Destroy()
 
1094
        c.Assert(err, jc.ErrorIsNil)
 
1095
        wc.AssertOneChange()
 
1096
 
 
1097
        // Stop, check closed.
 
1098
        testing.AssertStop(c, w)
 
1099
        wc.AssertClosed()
 
1100
 
 
1101
        // Remove machine, start new watch, check single event.
 
1102
        err = machine.EnsureDead()
 
1103
        c.Assert(err, jc.ErrorIsNil)
 
1104
        err = machine.Remove()
 
1105
        c.Assert(err, jc.ErrorIsNil)
 
1106
        w = s.machine.Watch()
 
1107
        defer testing.AssertStop(c, w)
 
1108
        testing.NewNotifyWatcherC(c, s.State, w).AssertOneChange()
 
1109
}
 
1110
 
 
1111
func (s *MachineSuite) TestWatchDiesOnStateClose(c *gc.C) {
 
1112
        // This test is testing logic in watcher.entityWatcher, which
 
1113
        // is also used by:
 
1114
        //  Machine.WatchHardwareCharacteristics
 
1115
        //  Service.Watch
 
1116
        //  Unit.Watch
 
1117
        //  State.WatchForModelConfigChanges
 
1118
        //  Unit.WatchConfigSettings
 
1119
        testWatcherDiesWhenStateCloses(c, s.modelTag, func(c *gc.C, st *state.State) waiter {
 
1120
                m, err := st.Machine(s.machine.Id())
 
1121
                c.Assert(err, jc.ErrorIsNil)
 
1122
                w := m.Watch()
 
1123
                <-w.Changes()
 
1124
                return w
 
1125
        })
 
1126
}
 
1127
 
 
1128
func (s *MachineSuite) TestWatchPrincipalUnits(c *gc.C) {
 
1129
        // TODO(mjs) - MODELUUID - test with multiple models with
 
1130
        // identically named units and ensure there's no leakage.
 
1131
 
 
1132
        // Start a watch on an empty machine; check no units reported.
 
1133
        w := s.machine.WatchPrincipalUnits()
 
1134
        defer testing.AssertStop(c, w)
 
1135
        wc := testing.NewStringsWatcherC(c, s.State, w)
 
1136
        wc.AssertChange()
 
1137
        wc.AssertNoChange()
 
1138
 
 
1139
        // Change machine, and create a unit independently; no change.
 
1140
        err := s.machine.SetProvisioned("cheese", "fake_nonce", nil)
 
1141
        c.Assert(err, jc.ErrorIsNil)
 
1142
        wc.AssertNoChange()
 
1143
        mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
 
1144
        mysql0, err := mysql.AddUnit()
 
1145
        c.Assert(err, jc.ErrorIsNil)
 
1146
        wc.AssertNoChange()
 
1147
 
 
1148
        // Assign that unit (to a separate machine instance); change detected.
 
1149
        machine, err := s.State.Machine(s.machine.Id())
 
1150
        c.Assert(err, jc.ErrorIsNil)
 
1151
        err = mysql0.AssignToMachine(machine)
 
1152
        c.Assert(err, jc.ErrorIsNil)
 
1153
        wc.AssertChange("mysql/0")
 
1154
        wc.AssertNoChange()
 
1155
 
 
1156
        // Change the unit; no change.
 
1157
        now := time.Now()
 
1158
        sInfo := status.StatusInfo{
 
1159
                Status:  status.StatusIdle,
 
1160
                Message: "",
 
1161
                Since:   &now,
 
1162
        }
 
1163
        err = mysql0.SetAgentStatus(sInfo)
 
1164
        c.Assert(err, jc.ErrorIsNil)
 
1165
        wc.AssertNoChange()
 
1166
 
 
1167
        // Assign another unit and make the first Dying; check both changes detected.
 
1168
        mysql1, err := mysql.AddUnit()
 
1169
        c.Assert(err, jc.ErrorIsNil)
 
1170
        err = mysql1.AssignToMachine(machine)
 
1171
        c.Assert(err, jc.ErrorIsNil)
 
1172
        err = mysql0.Destroy()
 
1173
        c.Assert(err, jc.ErrorIsNil)
 
1174
        wc.AssertChange("mysql/0", "mysql/1")
 
1175
        wc.AssertNoChange()
 
1176
 
 
1177
        // Add a subordinate to the Alive unit; no change.
 
1178
        s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
 
1179
        eps, err := s.State.InferEndpoints("mysql", "logging")
 
1180
        c.Assert(err, jc.ErrorIsNil)
 
1181
        rel, err := s.State.AddRelation(eps...)
 
1182
        c.Assert(err, jc.ErrorIsNil)
 
1183
        mysqlru1, err := rel.Unit(mysql1)
 
1184
        c.Assert(err, jc.ErrorIsNil)
 
1185
        err = mysqlru1.EnterScope(nil)
 
1186
        c.Assert(err, jc.ErrorIsNil)
 
1187
        logging0, err := s.State.Unit("logging/0")
 
1188
        c.Assert(err, jc.ErrorIsNil)
 
1189
        wc.AssertNoChange()
 
1190
 
 
1191
        // Change the subordinate; no change.
 
1192
        sInfo = status.StatusInfo{
 
1193
                Status:  status.StatusIdle,
 
1194
                Message: "",
 
1195
                Since:   &now,
 
1196
        }
 
1197
        err = logging0.SetAgentStatus(sInfo)
 
1198
        c.Assert(err, jc.ErrorIsNil)
 
1199
        wc.AssertNoChange()
 
1200
 
 
1201
        // Make the Dying unit Dead; change detected.
 
1202
        err = mysql0.EnsureDead()
 
1203
        c.Assert(err, jc.ErrorIsNil)
 
1204
        wc.AssertChange("mysql/0")
 
1205
        wc.AssertNoChange()
 
1206
 
 
1207
        // Stop watcher; check Changes chan closed.
 
1208
        testing.AssertStop(c, w)
 
1209
        wc.AssertClosed()
 
1210
 
 
1211
        // Start a fresh watcher; check both principals reported.
 
1212
        w = s.machine.WatchPrincipalUnits()
 
1213
        defer testing.AssertStop(c, w)
 
1214
        wc = testing.NewStringsWatcherC(c, s.State, w)
 
1215
        wc.AssertChange("mysql/0", "mysql/1")
 
1216
        wc.AssertNoChange()
 
1217
 
 
1218
        // Remove the Dead unit; no change.
 
1219
        err = mysql0.Remove()
 
1220
        c.Assert(err, jc.ErrorIsNil)
 
1221
        wc.AssertNoChange()
 
1222
 
 
1223
        // Destroy the subordinate; no change.
 
1224
        err = logging0.Destroy()
 
1225
        c.Assert(err, jc.ErrorIsNil)
 
1226
        wc.AssertNoChange()
 
1227
 
 
1228
        // Unassign the unit; check change.
 
1229
        err = mysql1.UnassignFromMachine()
 
1230
        c.Assert(err, jc.ErrorIsNil)
 
1231
        wc.AssertChange("mysql/1")
 
1232
        wc.AssertNoChange()
 
1233
}
 
1234
 
 
1235
func (s *MachineSuite) TestWatchPrincipalUnitsDiesOnStateClose(c *gc.C) {
 
1236
        // This test is testing logic in watcher.unitsWatcher, which
 
1237
        // is also used by Unit.WatchSubordinateUnits.
 
1238
        testWatcherDiesWhenStateCloses(c, s.modelTag, func(c *gc.C, st *state.State) waiter {
 
1239
                m, err := st.Machine(s.machine.Id())
 
1240
                c.Assert(err, jc.ErrorIsNil)
 
1241
                w := m.WatchPrincipalUnits()
 
1242
                <-w.Changes()
 
1243
                return w
 
1244
        })
 
1245
}
 
1246
 
 
1247
func (s *MachineSuite) TestWatchUnits(c *gc.C) {
 
1248
        // Start a watch on an empty machine; check no units reported.
 
1249
        w := s.machine.WatchUnits()
 
1250
        defer testing.AssertStop(c, w)
 
1251
        wc := testing.NewStringsWatcherC(c, s.State, w)
 
1252
        wc.AssertChange()
 
1253
        wc.AssertNoChange()
 
1254
 
 
1255
        // Change machine; no change.
 
1256
        err := s.machine.SetProvisioned("cheese", "fake_nonce", nil)
 
1257
        c.Assert(err, jc.ErrorIsNil)
 
1258
        wc.AssertNoChange()
 
1259
 
 
1260
        // Assign a unit (to a separate instance); change detected.
 
1261
        mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
 
1262
        mysql0, err := mysql.AddUnit()
 
1263
        c.Assert(err, jc.ErrorIsNil)
 
1264
        machine, err := s.State.Machine(s.machine.Id())
 
1265
        c.Assert(err, jc.ErrorIsNil)
 
1266
        err = mysql0.AssignToMachine(machine)
 
1267
        c.Assert(err, jc.ErrorIsNil)
 
1268
        wc.AssertChange("mysql/0")
 
1269
        wc.AssertNoChange()
 
1270
 
 
1271
        // Change the unit; no change.
 
1272
        now := time.Now()
 
1273
        sInfo := status.StatusInfo{
 
1274
                Status:  status.StatusIdle,
 
1275
                Message: "",
 
1276
                Since:   &now,
 
1277
        }
 
1278
        err = mysql0.SetAgentStatus(sInfo)
 
1279
        c.Assert(err, jc.ErrorIsNil)
 
1280
        wc.AssertNoChange()
 
1281
 
 
1282
        // Assign another unit and make the first Dying; check both changes detected.
 
1283
        mysql1, err := mysql.AddUnit()
 
1284
        c.Assert(err, jc.ErrorIsNil)
 
1285
        err = mysql1.AssignToMachine(machine)
 
1286
        c.Assert(err, jc.ErrorIsNil)
 
1287
        err = mysql0.Destroy()
 
1288
        c.Assert(err, jc.ErrorIsNil)
 
1289
        wc.AssertChange("mysql/0", "mysql/1")
 
1290
        wc.AssertNoChange()
 
1291
 
 
1292
        // Add a subordinate to the Alive unit; change detected.
 
1293
        s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
 
1294
        eps, err := s.State.InferEndpoints("mysql", "logging")
 
1295
        c.Assert(err, jc.ErrorIsNil)
 
1296
        rel, err := s.State.AddRelation(eps...)
 
1297
        c.Assert(err, jc.ErrorIsNil)
 
1298
        mysqlru1, err := rel.Unit(mysql1)
 
1299
        c.Assert(err, jc.ErrorIsNil)
 
1300
        err = mysqlru1.EnterScope(nil)
 
1301
        c.Assert(err, jc.ErrorIsNil)
 
1302
        logging0, err := s.State.Unit("logging/0")
 
1303
        c.Assert(err, jc.ErrorIsNil)
 
1304
        wc.AssertChange("logging/0")
 
1305
        wc.AssertNoChange()
 
1306
 
 
1307
        // Change the subordinate; no change.
 
1308
        sInfo = status.StatusInfo{
 
1309
                Status:  status.StatusIdle,
 
1310
                Message: "",
 
1311
                Since:   &now,
 
1312
        }
 
1313
        err = logging0.SetAgentStatus(sInfo)
 
1314
        c.Assert(err, jc.ErrorIsNil)
 
1315
        wc.AssertNoChange()
 
1316
 
 
1317
        // Make the Dying unit Dead; change detected.
 
1318
        err = mysql0.EnsureDead()
 
1319
        c.Assert(err, jc.ErrorIsNil)
 
1320
        wc.AssertChange("mysql/0")
 
1321
        wc.AssertNoChange()
 
1322
 
 
1323
        // Stop watcher; check Changes chan closed.
 
1324
        testing.AssertStop(c, w)
 
1325
        wc.AssertClosed()
 
1326
 
 
1327
        // Start a fresh watcher; check all units reported.
 
1328
        w = s.machine.WatchUnits()
 
1329
        defer testing.AssertStop(c, w)
 
1330
        wc = testing.NewStringsWatcherC(c, s.State, w)
 
1331
        wc.AssertChange("mysql/0", "mysql/1", "logging/0")
 
1332
        wc.AssertNoChange()
 
1333
 
 
1334
        // Remove the Dead unit; no change.
 
1335
        err = mysql0.Remove()
 
1336
        c.Assert(err, jc.ErrorIsNil)
 
1337
        wc.AssertNoChange()
 
1338
 
 
1339
        // Destroy the subordinate; change detected.
 
1340
        err = logging0.Destroy()
 
1341
        c.Assert(err, jc.ErrorIsNil)
 
1342
        wc.AssertChange("logging/0")
 
1343
        wc.AssertNoChange()
 
1344
 
 
1345
        // Unassign the principal; check subordinate departure also reported.
 
1346
        err = mysql1.UnassignFromMachine()
 
1347
        c.Assert(err, jc.ErrorIsNil)
 
1348
        wc.AssertChange("mysql/1", "logging/0")
 
1349
        wc.AssertNoChange()
 
1350
}
 
1351
 
 
1352
func (s *MachineSuite) TestWatchUnitsDiesOnStateClose(c *gc.C) {
 
1353
        testWatcherDiesWhenStateCloses(c, s.modelTag, func(c *gc.C, st *state.State) waiter {
 
1354
                m, err := st.Machine(s.machine.Id())
 
1355
                c.Assert(err, jc.ErrorIsNil)
 
1356
                w := m.WatchUnits()
 
1357
                <-w.Changes()
 
1358
                return w
 
1359
        })
 
1360
}
 
1361
 
 
1362
func (s *MachineSuite) TestConstraintsFromModel(c *gc.C) {
 
1363
        econs1 := constraints.MustParse("mem=1G")
 
1364
        econs2 := constraints.MustParse("mem=2G")
 
1365
 
 
1366
        // A newly-created machine gets a copy of the model constraints.
 
1367
        err := s.State.SetModelConstraints(econs1)
 
1368
        c.Assert(err, jc.ErrorIsNil)
 
1369
        machine1, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1370
        c.Assert(err, jc.ErrorIsNil)
 
1371
        mcons1, err := machine1.Constraints()
 
1372
        c.Assert(err, jc.ErrorIsNil)
 
1373
        c.Assert(mcons1, gc.DeepEquals, econs1)
 
1374
 
 
1375
        // Change model constraints and add a new machine.
 
1376
        err = s.State.SetModelConstraints(econs2)
 
1377
        c.Assert(err, jc.ErrorIsNil)
 
1378
        machine2, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1379
        c.Assert(err, jc.ErrorIsNil)
 
1380
        mcons2, err := machine2.Constraints()
 
1381
        c.Assert(err, jc.ErrorIsNil)
 
1382
        c.Assert(mcons2, gc.DeepEquals, econs2)
 
1383
 
 
1384
        // Check the original machine has its original constraints.
 
1385
        mcons1, err = machine1.Constraints()
 
1386
        c.Assert(err, jc.ErrorIsNil)
 
1387
        c.Assert(mcons1, gc.DeepEquals, econs1)
 
1388
}
 
1389
 
 
1390
func (s *MachineSuite) TestSetConstraints(c *gc.C) {
 
1391
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1392
        c.Assert(err, jc.ErrorIsNil)
 
1393
 
 
1394
        // Constraints can be set...
 
1395
        cons1 := constraints.MustParse("mem=1G")
 
1396
        err = machine.SetConstraints(cons1)
 
1397
        c.Assert(err, jc.ErrorIsNil)
 
1398
        mcons, err := machine.Constraints()
 
1399
        c.Assert(err, jc.ErrorIsNil)
 
1400
        c.Assert(mcons, gc.DeepEquals, cons1)
 
1401
 
 
1402
        // ...until the machine is provisioned, at which point they stick.
 
1403
        err = machine.SetProvisioned("i-mstuck", "fake_nonce", nil)
 
1404
        c.Assert(err, jc.ErrorIsNil)
 
1405
        cons2 := constraints.MustParse("mem=2G")
 
1406
        err = machine.SetConstraints(cons2)
 
1407
        c.Assert(err, gc.ErrorMatches, "cannot set constraints: machine is already provisioned")
 
1408
 
 
1409
        // Check the failed set had no effect.
 
1410
        mcons, err = machine.Constraints()
 
1411
        c.Assert(err, jc.ErrorIsNil)
 
1412
        c.Assert(mcons, gc.DeepEquals, cons1)
 
1413
}
 
1414
 
 
1415
func (s *MachineSuite) TestSetAmbiguousConstraints(c *gc.C) {
 
1416
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1417
        c.Assert(err, jc.ErrorIsNil)
 
1418
        cons := constraints.MustParse("mem=4G instance-type=foo")
 
1419
        err = machine.SetConstraints(cons)
 
1420
        c.Assert(err, gc.ErrorMatches, `cannot set constraints: ambiguous constraints: "instance-type" overlaps with "mem"`)
 
1421
}
 
1422
 
 
1423
func (s *MachineSuite) TestSetUnsupportedConstraintsWarning(c *gc.C) {
 
1424
        defer loggo.ResetWriters()
 
1425
        logger := loggo.GetLogger("test")
 
1426
        logger.SetLogLevel(loggo.DEBUG)
 
1427
        var tw loggo.TestWriter
 
1428
        c.Assert(loggo.RegisterWriter("constraints-tester", &tw), gc.IsNil)
 
1429
 
 
1430
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1431
        c.Assert(err, jc.ErrorIsNil)
 
1432
        cons := constraints.MustParse("mem=4G cpu-power=10")
 
1433
        err = machine.SetConstraints(cons)
 
1434
        c.Assert(err, jc.ErrorIsNil)
 
1435
        c.Assert(tw.Log(), jc.LogMatches, jc.SimpleMessages{{
 
1436
                loggo.WARNING,
 
1437
                `setting constraints on machine "2": unsupported constraints: cpu-power`},
 
1438
        })
 
1439
        mcons, err := machine.Constraints()
 
1440
        c.Assert(err, jc.ErrorIsNil)
 
1441
        c.Assert(mcons, gc.DeepEquals, cons)
 
1442
}
 
1443
 
 
1444
func (s *MachineSuite) TestConstraintsLifecycle(c *gc.C) {
 
1445
        cons := constraints.MustParse("mem=1G")
 
1446
        cannotSet := `cannot set constraints: not found or not alive`
 
1447
        testWhenDying(c, s.machine, cannotSet, cannotSet, func() error {
 
1448
                err := s.machine.SetConstraints(cons)
 
1449
                mcons, err1 := s.machine.Constraints()
 
1450
                c.Assert(err1, gc.IsNil)
 
1451
                c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty)
 
1452
                return err
 
1453
        })
 
1454
 
 
1455
        err := s.machine.Remove()
 
1456
        c.Assert(err, jc.ErrorIsNil)
 
1457
        err = s.machine.SetConstraints(cons)
 
1458
        c.Assert(err, gc.ErrorMatches, cannotSet)
 
1459
        _, err = s.machine.Constraints()
 
1460
        c.Assert(err, gc.ErrorMatches, `constraints not found`)
 
1461
}
 
1462
 
 
1463
func (s *MachineSuite) TestSetProviderAddresses(c *gc.C) {
 
1464
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1465
        c.Assert(err, jc.ErrorIsNil)
 
1466
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1467
 
 
1468
        addresses := network.NewAddresses("127.0.0.1", "8.8.8.8")
 
1469
        err = machine.SetProviderAddresses(addresses...)
 
1470
        c.Assert(err, jc.ErrorIsNil)
 
1471
        err = machine.Refresh()
 
1472
        c.Assert(err, jc.ErrorIsNil)
 
1473
 
 
1474
        expectedAddresses := network.NewAddresses("8.8.8.8", "127.0.0.1")
 
1475
        c.Assert(machine.Addresses(), jc.DeepEquals, expectedAddresses)
 
1476
}
 
1477
 
 
1478
func (s *MachineSuite) TestSetProviderAddressesWithContainers(c *gc.C) {
 
1479
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1480
        c.Assert(err, jc.ErrorIsNil)
 
1481
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1482
 
 
1483
        // When setting all addresses the subnet addresses have to be
 
1484
        // filtered out.
 
1485
        addresses := network.NewAddresses(
 
1486
                "127.0.0.1",
 
1487
                "8.8.8.8",
 
1488
        )
 
1489
        err = machine.SetProviderAddresses(addresses...)
 
1490
        c.Assert(err, jc.ErrorIsNil)
 
1491
        err = machine.Refresh()
 
1492
        c.Assert(err, jc.ErrorIsNil)
 
1493
 
 
1494
        expectedAddresses := network.NewAddresses("8.8.8.8", "127.0.0.1")
 
1495
        c.Assert(machine.Addresses(), jc.DeepEquals, expectedAddresses)
 
1496
}
 
1497
 
 
1498
func (s *MachineSuite) TestSetProviderAddressesOnContainer(c *gc.C) {
 
1499
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1500
        c.Assert(err, jc.ErrorIsNil)
 
1501
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1502
 
 
1503
        // Create an LXC container inside the machine.
 
1504
        template := state.MachineTemplate{
 
1505
                Series: "quantal",
 
1506
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
1507
        }
 
1508
        container, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.LXD)
 
1509
        c.Assert(err, jc.ErrorIsNil)
 
1510
 
 
1511
        // When setting all addresses the subnet address has to accepted.
 
1512
        addresses := network.NewAddresses("127.0.0.1")
 
1513
        err = container.SetProviderAddresses(addresses...)
 
1514
        c.Assert(err, jc.ErrorIsNil)
 
1515
        err = container.Refresh()
 
1516
        c.Assert(err, jc.ErrorIsNil)
 
1517
 
 
1518
        expectedAddresses := network.NewAddresses("127.0.0.1")
 
1519
        c.Assert(container.Addresses(), jc.DeepEquals, expectedAddresses)
 
1520
}
 
1521
 
 
1522
func (s *MachineSuite) TestSetMachineAddresses(c *gc.C) {
 
1523
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1524
        c.Assert(err, jc.ErrorIsNil)
 
1525
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1526
 
 
1527
        addresses := network.NewAddresses("127.0.0.1", "8.8.8.8")
 
1528
        err = machine.SetMachineAddresses(addresses...)
 
1529
        c.Assert(err, jc.ErrorIsNil)
 
1530
        err = machine.Refresh()
 
1531
        c.Assert(err, jc.ErrorIsNil)
 
1532
 
 
1533
        expectedAddresses := network.NewAddresses("8.8.8.8", "127.0.0.1")
 
1534
        c.Assert(machine.MachineAddresses(), jc.DeepEquals, expectedAddresses)
 
1535
}
 
1536
 
 
1537
func (s *MachineSuite) TestSetEmptyMachineAddresses(c *gc.C) {
 
1538
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1539
        c.Assert(err, jc.ErrorIsNil)
 
1540
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1541
 
 
1542
        // Add some machine addresses initially to make sure they're removed.
 
1543
        addresses := network.NewAddresses("127.0.0.1", "8.8.8.8")
 
1544
        err = machine.SetMachineAddresses(addresses...)
 
1545
        c.Assert(err, jc.ErrorIsNil)
 
1546
        err = machine.Refresh()
 
1547
        c.Assert(err, jc.ErrorIsNil)
 
1548
        c.Assert(machine.MachineAddresses(), gc.HasLen, 2)
 
1549
 
 
1550
        // Make call with empty address list.
 
1551
        err = machine.SetMachineAddresses()
 
1552
        c.Assert(err, jc.ErrorIsNil)
 
1553
        err = machine.Refresh()
 
1554
        c.Assert(err, jc.ErrorIsNil)
 
1555
 
 
1556
        c.Assert(machine.MachineAddresses(), gc.HasLen, 0)
 
1557
}
 
1558
 
 
1559
func (s *MachineSuite) TestMergedAddresses(c *gc.C) {
 
1560
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1561
        c.Assert(err, jc.ErrorIsNil)
 
1562
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1563
 
 
1564
        providerAddresses := network.NewAddresses(
 
1565
                "127.0.0.2",
 
1566
                "8.8.8.8",
 
1567
                "fc00::1",
 
1568
                "::1",
 
1569
                "",
 
1570
                "2001:db8::1",
 
1571
                "127.0.0.2",
 
1572
                "example.org",
 
1573
        )
 
1574
        err = machine.SetProviderAddresses(providerAddresses...)
 
1575
        c.Assert(err, jc.ErrorIsNil)
 
1576
 
 
1577
        machineAddresses := network.NewAddresses(
 
1578
                "127.0.0.1",
 
1579
                "localhost",
 
1580
                "2001:db8::1",
 
1581
                "192.168.0.1",
 
1582
                "fe80::1",
 
1583
                "::1",
 
1584
                "fd00::1",
 
1585
        )
 
1586
        err = machine.SetMachineAddresses(machineAddresses...)
 
1587
        c.Assert(err, jc.ErrorIsNil)
 
1588
        err = machine.Refresh()
 
1589
        c.Assert(err, jc.ErrorIsNil)
 
1590
 
 
1591
        // Before setting the addresses coming from either the provider or
 
1592
        // the machine itself, they are sorted to prefer public IPs on
 
1593
        // top, then hostnames, cloud-local, machine-local, link-local.
 
1594
        // Duplicates are removed, then when calling Addresses() both
 
1595
        // sources are merged while preservig the provider addresses
 
1596
        // order.
 
1597
        c.Assert(machine.Addresses(), jc.DeepEquals, network.NewAddresses(
 
1598
                "8.8.8.8",
 
1599
                "2001:db8::1",
 
1600
                "example.org",
 
1601
                "fc00::1",
 
1602
                "127.0.0.2",
 
1603
                "::1",
 
1604
                "localhost",
 
1605
                "192.168.0.1",
 
1606
                "fd00::1",
 
1607
                "127.0.0.1",
 
1608
                "fe80::1",
 
1609
        ))
 
1610
}
 
1611
 
 
1612
func (s *MachineSuite) TestSetProviderAddressesConcurrentChangeDifferent(c *gc.C) {
 
1613
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1614
        c.Assert(err, jc.ErrorIsNil)
 
1615
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1616
 
 
1617
        addr0 := network.NewAddress("127.0.0.1")
 
1618
        addr1 := network.NewAddress("8.8.8.8")
 
1619
 
 
1620
        defer state.SetBeforeHooks(c, s.State, func() {
 
1621
                machine, err := s.State.Machine(machine.Id())
 
1622
                c.Assert(err, jc.ErrorIsNil)
 
1623
                err = machine.SetProviderAddresses(addr1, addr0)
 
1624
                c.Assert(err, jc.ErrorIsNil)
 
1625
        }).Check()
 
1626
 
 
1627
        err = machine.SetProviderAddresses(addr0, addr1)
 
1628
        c.Assert(err, jc.ErrorIsNil)
 
1629
        c.Assert(machine.Addresses(), jc.SameContents, []network.Address{addr0, addr1})
 
1630
}
 
1631
 
 
1632
func (s *MachineSuite) TestSetProviderAddressesConcurrentChangeEqual(c *gc.C) {
 
1633
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1634
        c.Assert(err, jc.ErrorIsNil)
 
1635
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1636
        machineDocID := state.DocID(s.State, machine.Id())
 
1637
        revno0, err := state.TxnRevno(s.State, "machines", machineDocID)
 
1638
        c.Assert(err, jc.ErrorIsNil)
 
1639
 
 
1640
        addr0 := network.NewAddress("127.0.0.1")
 
1641
        addr1 := network.NewAddress("8.8.8.8")
 
1642
 
 
1643
        var revno1 int64
 
1644
        defer state.SetBeforeHooks(c, s.State, func() {
 
1645
                machine, err := s.State.Machine(machine.Id())
 
1646
                c.Assert(err, jc.ErrorIsNil)
 
1647
                err = machine.SetProviderAddresses(addr0, addr1)
 
1648
                c.Assert(err, jc.ErrorIsNil)
 
1649
                revno1, err = state.TxnRevno(s.State, "machines", machineDocID)
 
1650
                c.Assert(err, jc.ErrorIsNil)
 
1651
                c.Assert(revno1, jc.GreaterThan, revno0)
 
1652
        }).Check()
 
1653
 
 
1654
        err = machine.SetProviderAddresses(addr0, addr1)
 
1655
        c.Assert(err, jc.ErrorIsNil)
 
1656
 
 
1657
        // Doc will be updated; concurrent changes are explicitly ignored.
 
1658
        revno2, err := state.TxnRevno(s.State, "machines", machineDocID)
 
1659
        c.Assert(err, jc.ErrorIsNil)
 
1660
        c.Assert(revno2, jc.GreaterThan, revno1)
 
1661
        c.Assert(machine.Addresses(), jc.SameContents, []network.Address{addr0, addr1})
 
1662
}
 
1663
 
 
1664
func (s *MachineSuite) TestSetProviderAddressesInvalidateMemory(c *gc.C) {
 
1665
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1666
        c.Assert(err, jc.ErrorIsNil)
 
1667
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1668
        machineDocID := state.DocID(s.State, machine.Id())
 
1669
 
 
1670
        addr0 := network.NewAddress("127.0.0.1")
 
1671
        addr1 := network.NewAddress("8.8.8.8")
 
1672
 
 
1673
        // Set addresses to [addr0] initially. We'll get a separate Machine
 
1674
        // object to update addresses, to ensure that the in-memory cache of
 
1675
        // addresses does not prevent the initial Machine from updating
 
1676
        // addresses back to the original value.
 
1677
        err = machine.SetProviderAddresses(addr0)
 
1678
        c.Assert(err, jc.ErrorIsNil)
 
1679
        revno0, err := state.TxnRevno(s.State, "machines", machineDocID)
 
1680
        c.Assert(err, jc.ErrorIsNil)
 
1681
 
 
1682
        machine2, err := s.State.Machine(machine.Id())
 
1683
        c.Assert(err, jc.ErrorIsNil)
 
1684
        err = machine2.SetProviderAddresses(addr1)
 
1685
        c.Assert(err, jc.ErrorIsNil)
 
1686
        revno1, err := state.TxnRevno(s.State, "machines", machineDocID)
 
1687
        c.Assert(err, jc.ErrorIsNil)
 
1688
        c.Assert(revno1, jc.GreaterThan, revno0)
 
1689
        c.Assert(machine.Addresses(), jc.SameContents, []network.Address{addr0})
 
1690
        c.Assert(machine2.Addresses(), jc.SameContents, []network.Address{addr1})
 
1691
 
 
1692
        err = machine.SetProviderAddresses(addr0)
 
1693
        c.Assert(err, jc.ErrorIsNil)
 
1694
        revno2, err := state.TxnRevno(s.State, "machines", machineDocID)
 
1695
        c.Assert(err, jc.ErrorIsNil)
 
1696
        c.Assert(revno2, jc.GreaterThan, revno1)
 
1697
        c.Assert(machine.Addresses(), jc.SameContents, []network.Address{addr0})
 
1698
}
 
1699
 
 
1700
func (s *MachineSuite) TestPublicAddressSetOnNewMachine(c *gc.C) {
 
1701
        m, err := s.State.AddOneMachine(state.MachineTemplate{
 
1702
                Series:    "quantal",
 
1703
                Jobs:      []state.MachineJob{state.JobHostUnits},
 
1704
                Addresses: network.NewAddresses("10.0.0.1", "8.8.8.8"),
 
1705
        })
 
1706
        c.Assert(err, jc.ErrorIsNil)
 
1707
        addr, err := m.PublicAddress()
 
1708
        c.Assert(err, jc.ErrorIsNil)
 
1709
        c.Assert(addr, jc.DeepEquals, network.NewAddress("8.8.8.8"))
 
1710
}
 
1711
 
 
1712
func (s *MachineSuite) TestPrivateAddressSetOnNewMachine(c *gc.C) {
 
1713
        m, err := s.State.AddOneMachine(state.MachineTemplate{
 
1714
                Series:    "quantal",
 
1715
                Jobs:      []state.MachineJob{state.JobHostUnits},
 
1716
                Addresses: network.NewAddresses("10.0.0.1", "8.8.8.8"),
 
1717
        })
 
1718
        c.Assert(err, jc.ErrorIsNil)
 
1719
        addr, err := m.PrivateAddress()
 
1720
        c.Assert(err, jc.ErrorIsNil)
 
1721
        c.Assert(addr, jc.DeepEquals, network.NewAddress("10.0.0.1"))
 
1722
}
 
1723
 
 
1724
func (s *MachineSuite) TestPublicAddressEmptyAddresses(c *gc.C) {
 
1725
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1726
        c.Assert(err, jc.ErrorIsNil)
 
1727
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1728
 
 
1729
        addr, err := machine.PublicAddress()
 
1730
        c.Assert(err, jc.Satisfies, network.IsNoAddressError)
 
1731
        c.Assert(addr.Value, gc.Equals, "")
 
1732
}
 
1733
 
 
1734
func (s *MachineSuite) TestPrivateAddressEmptyAddresses(c *gc.C) {
 
1735
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1736
        c.Assert(err, jc.ErrorIsNil)
 
1737
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
1738
 
 
1739
        addr, err := machine.PrivateAddress()
 
1740
        c.Assert(err, jc.Satisfies, network.IsNoAddressError)
 
1741
        c.Assert(addr.Value, gc.Equals, "")
 
1742
}
 
1743
 
 
1744
func (s *MachineSuite) TestPublicAddress(c *gc.C) {
 
1745
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1746
        c.Assert(err, jc.ErrorIsNil)
 
1747
 
 
1748
        err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
 
1749
        c.Assert(err, jc.ErrorIsNil)
 
1750
 
 
1751
        addr, err := machine.PublicAddress()
 
1752
        c.Assert(err, jc.ErrorIsNil)
 
1753
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
1754
}
 
1755
 
 
1756
func (s *MachineSuite) TestPrivateAddress(c *gc.C) {
 
1757
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1758
        c.Assert(err, jc.ErrorIsNil)
 
1759
 
 
1760
        err = machine.SetMachineAddresses(network.NewAddress("10.0.0.1"))
 
1761
        c.Assert(err, jc.ErrorIsNil)
 
1762
 
 
1763
        addr, err := machine.PrivateAddress()
 
1764
        c.Assert(err, jc.ErrorIsNil)
 
1765
        c.Assert(addr.Value, gc.Equals, "10.0.0.1")
 
1766
}
 
1767
 
 
1768
func (s *MachineSuite) TestPublicAddressBetterMatch(c *gc.C) {
 
1769
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1770
        c.Assert(err, jc.ErrorIsNil)
 
1771
 
 
1772
        err = machine.SetMachineAddresses(network.NewAddress("10.0.0.1"))
 
1773
        c.Assert(err, jc.ErrorIsNil)
 
1774
 
 
1775
        addr, err := machine.PublicAddress()
 
1776
        c.Assert(err, jc.ErrorIsNil)
 
1777
        c.Assert(addr.Value, gc.Equals, "10.0.0.1")
 
1778
 
 
1779
        err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
 
1780
        c.Assert(err, jc.ErrorIsNil)
 
1781
 
 
1782
        addr, err = machine.PublicAddress()
 
1783
        c.Assert(err, jc.ErrorIsNil)
 
1784
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
1785
}
 
1786
 
 
1787
func (s *MachineSuite) TestPrivateAddressBetterMatch(c *gc.C) {
 
1788
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1789
        c.Assert(err, jc.ErrorIsNil)
 
1790
 
 
1791
        err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
 
1792
        c.Assert(err, jc.ErrorIsNil)
 
1793
 
 
1794
        addr, err := machine.PrivateAddress()
 
1795
        c.Assert(err, jc.ErrorIsNil)
 
1796
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
1797
 
 
1798
        err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"), network.NewAddress("10.0.0.1"))
 
1799
        c.Assert(err, jc.ErrorIsNil)
 
1800
 
 
1801
        addr, err = machine.PrivateAddress()
 
1802
        c.Assert(err, jc.ErrorIsNil)
 
1803
        c.Assert(addr.Value, gc.Equals, "10.0.0.1")
 
1804
}
 
1805
 
 
1806
func (s *MachineSuite) TestPublicAddressChanges(c *gc.C) {
 
1807
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1808
        c.Assert(err, jc.ErrorIsNil)
 
1809
 
 
1810
        err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
 
1811
        c.Assert(err, jc.ErrorIsNil)
 
1812
 
 
1813
        addr, err := machine.PublicAddress()
 
1814
        c.Assert(err, jc.ErrorIsNil)
 
1815
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
1816
 
 
1817
        err = machine.SetProviderAddresses(network.NewAddress("8.8.4.4"))
 
1818
        c.Assert(err, jc.ErrorIsNil)
 
1819
 
 
1820
        addr, err = machine.PublicAddress()
 
1821
        c.Assert(err, jc.ErrorIsNil)
 
1822
        c.Assert(addr.Value, gc.Equals, "8.8.4.4")
 
1823
}
 
1824
 
 
1825
func (s *MachineSuite) TestPrivateAddressChanges(c *gc.C) {
 
1826
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1827
        c.Assert(err, jc.ErrorIsNil)
 
1828
 
 
1829
        err = machine.SetMachineAddresses(network.NewAddress("10.0.0.2"))
 
1830
        c.Assert(err, jc.ErrorIsNil)
 
1831
 
 
1832
        addr, err := machine.PrivateAddress()
 
1833
        c.Assert(err, jc.ErrorIsNil)
 
1834
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
1835
 
 
1836
        err = machine.SetMachineAddresses(network.NewAddress("10.0.0.1"))
 
1837
        c.Assert(err, jc.ErrorIsNil)
 
1838
 
 
1839
        addr, err = machine.PrivateAddress()
 
1840
        c.Assert(err, jc.ErrorIsNil)
 
1841
        c.Assert(addr.Value, gc.Equals, "10.0.0.1")
 
1842
}
 
1843
 
 
1844
func (s *MachineSuite) TestAddressesDeadMachine(c *gc.C) {
 
1845
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1846
        c.Assert(err, jc.ErrorIsNil)
 
1847
 
 
1848
        err = machine.SetProviderAddresses(network.NewAddress("10.0.0.2"), network.NewAddress("8.8.4.4"))
 
1849
        c.Assert(err, jc.ErrorIsNil)
 
1850
 
 
1851
        addr, err := machine.PrivateAddress()
 
1852
        c.Assert(err, jc.ErrorIsNil)
 
1853
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
1854
 
 
1855
        addr, err = machine.PublicAddress()
 
1856
        c.Assert(err, jc.ErrorIsNil)
 
1857
        c.Assert(addr.Value, gc.Equals, "8.8.4.4")
 
1858
 
 
1859
        err = machine.EnsureDead()
 
1860
        c.Assert(err, jc.ErrorIsNil)
 
1861
 
 
1862
        // A dead machine should still report the last known addresses.
 
1863
        addr, err = machine.PrivateAddress()
 
1864
        c.Assert(err, jc.ErrorIsNil)
 
1865
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
1866
 
 
1867
        addr, err = machine.PublicAddress()
 
1868
        c.Assert(err, jc.ErrorIsNil)
 
1869
        c.Assert(addr.Value, gc.Equals, "8.8.4.4")
 
1870
}
 
1871
 
 
1872
func (s *MachineSuite) TestStablePrivateAddress(c *gc.C) {
 
1873
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1874
        c.Assert(err, jc.ErrorIsNil)
 
1875
 
 
1876
        err = machine.SetMachineAddresses(network.NewAddress("10.0.0.2"))
 
1877
        c.Assert(err, jc.ErrorIsNil)
 
1878
 
 
1879
        addr, err := machine.PrivateAddress()
 
1880
        c.Assert(err, jc.ErrorIsNil)
 
1881
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
1882
 
 
1883
        // Now add an address that would previously have sorted before the
 
1884
        // default.
 
1885
        err = machine.SetMachineAddresses(network.NewAddress("10.0.0.1"), network.NewAddress("10.0.0.2"))
 
1886
        c.Assert(err, jc.ErrorIsNil)
 
1887
 
 
1888
        // Assert the address is unchanged.
 
1889
        addr, err = machine.PrivateAddress()
 
1890
        c.Assert(err, jc.ErrorIsNil)
 
1891
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
1892
}
 
1893
 
 
1894
func (s *MachineSuite) TestStablePublicAddress(c *gc.C) {
 
1895
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1896
        c.Assert(err, jc.ErrorIsNil)
 
1897
 
 
1898
        err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
 
1899
        c.Assert(err, jc.ErrorIsNil)
 
1900
 
 
1901
        addr, err := machine.PublicAddress()
 
1902
        c.Assert(err, jc.ErrorIsNil)
 
1903
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
1904
 
 
1905
        // Now add an address that would previously have sorted before the
 
1906
        // default.
 
1907
        err = machine.SetProviderAddresses(network.NewAddress("8.8.4.4"), network.NewAddress("8.8.8.8"))
 
1908
        c.Assert(err, jc.ErrorIsNil)
 
1909
 
 
1910
        // Assert the address is unchanged.
 
1911
        addr, err = machine.PublicAddress()
 
1912
        c.Assert(err, jc.ErrorIsNil)
 
1913
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
1914
}
 
1915
 
 
1916
func (s *MachineSuite) TestAddressesRaceMachineFirst(c *gc.C) {
 
1917
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1918
        c.Assert(err, jc.ErrorIsNil)
 
1919
 
 
1920
        changeAddresses := jujutxn.TestHook{
 
1921
                Before: func() {
 
1922
                        err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
 
1923
                        c.Assert(err, jc.ErrorIsNil)
 
1924
                        address, err := machine.PublicAddress()
 
1925
                        c.Assert(err, jc.ErrorIsNil)
 
1926
                        c.Assert(address, jc.DeepEquals, network.NewAddress("8.8.8.8"))
 
1927
                        address, err = machine.PrivateAddress()
 
1928
                        c.Assert(err, jc.ErrorIsNil)
 
1929
                        c.Assert(address, jc.DeepEquals, network.NewAddress("8.8.8.8"))
 
1930
                },
 
1931
        }
 
1932
        defer state.SetTestHooks(c, s.State, changeAddresses).Check()
 
1933
 
 
1934
        err = machine.SetMachineAddresses(network.NewAddress("8.8.4.4"))
 
1935
        c.Assert(err, jc.ErrorIsNil)
 
1936
 
 
1937
        machine, err = s.State.Machine(machine.Id())
 
1938
        c.Assert(err, jc.ErrorIsNil)
 
1939
        address, err := machine.PublicAddress()
 
1940
        c.Assert(err, jc.ErrorIsNil)
 
1941
        c.Assert(address, jc.DeepEquals, network.NewAddress("8.8.8.8"))
 
1942
        address, err = machine.PrivateAddress()
 
1943
        c.Assert(err, jc.ErrorIsNil)
 
1944
        c.Assert(address, jc.DeepEquals, network.NewAddress("8.8.8.8"))
 
1945
}
 
1946
 
 
1947
func (s *MachineSuite) TestAddressesRaceProviderFirst(c *gc.C) {
 
1948
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1949
        c.Assert(err, jc.ErrorIsNil)
 
1950
 
 
1951
        changeAddresses := jujutxn.TestHook{
 
1952
                Before: func() {
 
1953
                        err = machine.SetMachineAddresses(network.NewAddress("10.0.0.1"))
 
1954
                        c.Assert(err, jc.ErrorIsNil)
 
1955
                        address, err := machine.PublicAddress()
 
1956
                        c.Assert(err, jc.ErrorIsNil)
 
1957
                        c.Assert(address, jc.DeepEquals, network.NewAddress("10.0.0.1"))
 
1958
                        address, err = machine.PrivateAddress()
 
1959
                        c.Assert(err, jc.ErrorIsNil)
 
1960
                        c.Assert(address, jc.DeepEquals, network.NewAddress("10.0.0.1"))
 
1961
                },
 
1962
        }
 
1963
        defer state.SetTestHooks(c, s.State, changeAddresses).Check()
 
1964
 
 
1965
        err = machine.SetProviderAddresses(network.NewAddress("8.8.4.4"))
 
1966
        c.Assert(err, jc.ErrorIsNil)
 
1967
 
 
1968
        machine, err = s.State.Machine(machine.Id())
 
1969
        c.Assert(err, jc.ErrorIsNil)
 
1970
        address, err := machine.PublicAddress()
 
1971
        c.Assert(err, jc.ErrorIsNil)
 
1972
        c.Assert(address, jc.DeepEquals, network.NewAddress("8.8.4.4"))
 
1973
        address, err = machine.PrivateAddress()
 
1974
        c.Assert(err, jc.ErrorIsNil)
 
1975
        c.Assert(address, jc.DeepEquals, network.NewAddress("8.8.4.4"))
 
1976
}
 
1977
 
 
1978
func (s *MachineSuite) TestPrivateAddressPrefersProvider(c *gc.C) {
 
1979
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
1980
        c.Assert(err, jc.ErrorIsNil)
 
1981
 
 
1982
        err = machine.SetMachineAddresses(network.NewAddress("8.8.8.8"), network.NewAddress("10.0.0.2"))
 
1983
        c.Assert(err, jc.ErrorIsNil)
 
1984
 
 
1985
        addr, err := machine.PublicAddress()
 
1986
        c.Assert(err, jc.ErrorIsNil)
 
1987
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
1988
        addr, err = machine.PrivateAddress()
 
1989
        c.Assert(err, jc.ErrorIsNil)
 
1990
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
1991
 
 
1992
        err = machine.SetProviderAddresses(network.NewAddress("10.0.0.1"))
 
1993
        c.Assert(err, jc.ErrorIsNil)
 
1994
 
 
1995
        addr, err = machine.PublicAddress()
 
1996
        c.Assert(err, jc.ErrorIsNil)
 
1997
        c.Assert(addr.Value, gc.Equals, "10.0.0.1")
 
1998
        addr, err = machine.PrivateAddress()
 
1999
        c.Assert(err, jc.ErrorIsNil)
 
2000
        c.Assert(addr.Value, gc.Equals, "10.0.0.1")
 
2001
}
 
2002
 
 
2003
func (s *MachineSuite) TestPublicAddressPrefersProvider(c *gc.C) {
 
2004
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2005
        c.Assert(err, jc.ErrorIsNil)
 
2006
 
 
2007
        err = machine.SetMachineAddresses(network.NewAddress("8.8.8.8"), network.NewAddress("10.0.0.2"))
 
2008
        c.Assert(err, jc.ErrorIsNil)
 
2009
 
 
2010
        addr, err := machine.PublicAddress()
 
2011
        c.Assert(err, jc.ErrorIsNil)
 
2012
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
2013
        addr, err = machine.PrivateAddress()
 
2014
        c.Assert(err, jc.ErrorIsNil)
 
2015
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
2016
 
 
2017
        err = machine.SetProviderAddresses(network.NewAddress("8.8.4.4"))
 
2018
        c.Assert(err, jc.ErrorIsNil)
 
2019
 
 
2020
        addr, err = machine.PublicAddress()
 
2021
        c.Assert(err, jc.ErrorIsNil)
 
2022
        c.Assert(addr.Value, gc.Equals, "8.8.4.4")
 
2023
        addr, err = machine.PrivateAddress()
 
2024
        c.Assert(err, jc.ErrorIsNil)
 
2025
        c.Assert(addr.Value, gc.Equals, "8.8.4.4")
 
2026
}
 
2027
 
 
2028
func (s *MachineSuite) TestAddressesPrefersProviderBoth(c *gc.C) {
 
2029
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2030
        c.Assert(err, jc.ErrorIsNil)
 
2031
 
 
2032
        err = machine.SetMachineAddresses(network.NewAddress("8.8.8.8"), network.NewAddress("10.0.0.1"))
 
2033
        c.Assert(err, jc.ErrorIsNil)
 
2034
 
 
2035
        addr, err := machine.PublicAddress()
 
2036
        c.Assert(err, jc.ErrorIsNil)
 
2037
        c.Assert(addr.Value, gc.Equals, "8.8.8.8")
 
2038
        addr, err = machine.PrivateAddress()
 
2039
        c.Assert(err, jc.ErrorIsNil)
 
2040
        c.Assert(addr.Value, gc.Equals, "10.0.0.1")
 
2041
 
 
2042
        err = machine.SetProviderAddresses(network.NewAddress("8.8.4.4"), network.NewAddress("10.0.0.2"))
 
2043
        c.Assert(err, jc.ErrorIsNil)
 
2044
 
 
2045
        addr, err = machine.PublicAddress()
 
2046
        c.Assert(err, jc.ErrorIsNil)
 
2047
        c.Assert(addr.Value, gc.Equals, "8.8.4.4")
 
2048
        addr, err = machine.PrivateAddress()
 
2049
        c.Assert(err, jc.ErrorIsNil)
 
2050
        c.Assert(addr.Value, gc.Equals, "10.0.0.2")
 
2051
}
 
2052
 
 
2053
func (s *MachineSuite) addMachineWithSupportedContainer(c *gc.C, container instance.ContainerType) *state.Machine {
 
2054
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2055
        c.Assert(err, jc.ErrorIsNil)
 
2056
        containers := []instance.ContainerType{container}
 
2057
        err = machine.SetSupportedContainers(containers)
 
2058
        c.Assert(err, jc.ErrorIsNil)
 
2059
        assertSupportedContainers(c, machine, containers)
 
2060
        return machine
 
2061
}
 
2062
 
 
2063
// assertSupportedContainers checks the document in memory has the specified
 
2064
// containers and then reloads the document from the database to assert saved
 
2065
// values match also.
 
2066
func assertSupportedContainers(c *gc.C, machine *state.Machine, containers []instance.ContainerType) {
 
2067
        supportedContainers, known := machine.SupportedContainers()
 
2068
        c.Assert(known, jc.IsTrue)
 
2069
        c.Assert(supportedContainers, gc.DeepEquals, containers)
 
2070
        // Reload so we can check the saved values.
 
2071
        err := machine.Refresh()
 
2072
        c.Assert(err, jc.ErrorIsNil)
 
2073
        supportedContainers, known = machine.SupportedContainers()
 
2074
        c.Assert(known, jc.IsTrue)
 
2075
        c.Assert(supportedContainers, gc.DeepEquals, containers)
 
2076
}
 
2077
 
 
2078
func assertSupportedContainersUnknown(c *gc.C, machine *state.Machine) {
 
2079
        containers, known := machine.SupportedContainers()
 
2080
        c.Assert(known, jc.IsFalse)
 
2081
        c.Assert(containers, gc.HasLen, 0)
 
2082
}
 
2083
 
 
2084
func (s *MachineSuite) TestSupportedContainersInitiallyUnknown(c *gc.C) {
 
2085
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2086
        c.Assert(err, jc.ErrorIsNil)
 
2087
        assertSupportedContainersUnknown(c, machine)
 
2088
}
 
2089
 
 
2090
func (s *MachineSuite) TestSupportsNoContainers(c *gc.C) {
 
2091
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2092
        c.Assert(err, jc.ErrorIsNil)
 
2093
 
 
2094
        err = machine.SupportsNoContainers()
 
2095
        c.Assert(err, jc.ErrorIsNil)
 
2096
        assertSupportedContainers(c, machine, []instance.ContainerType{})
 
2097
}
 
2098
 
 
2099
func (s *MachineSuite) TestSetSupportedContainerTypeNoneIsError(c *gc.C) {
 
2100
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2101
        c.Assert(err, jc.ErrorIsNil)
 
2102
 
 
2103
        err = machine.SetSupportedContainers([]instance.ContainerType{instance.LXD, instance.NONE})
 
2104
        c.Assert(err, gc.ErrorMatches, `"none" is not a valid container type`)
 
2105
        assertSupportedContainersUnknown(c, machine)
 
2106
        err = machine.Refresh()
 
2107
        c.Assert(err, jc.ErrorIsNil)
 
2108
        assertSupportedContainersUnknown(c, machine)
 
2109
}
 
2110
 
 
2111
func (s *MachineSuite) TestSupportsNoContainersOverwritesExisting(c *gc.C) {
 
2112
        machine := s.addMachineWithSupportedContainer(c, instance.LXD)
 
2113
 
 
2114
        err := machine.SupportsNoContainers()
 
2115
        c.Assert(err, jc.ErrorIsNil)
 
2116
        assertSupportedContainers(c, machine, []instance.ContainerType{})
 
2117
}
 
2118
 
 
2119
func (s *MachineSuite) TestSetSupportedContainersSingle(c *gc.C) {
 
2120
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2121
        c.Assert(err, jc.ErrorIsNil)
 
2122
 
 
2123
        err = machine.SetSupportedContainers([]instance.ContainerType{instance.LXD})
 
2124
        c.Assert(err, jc.ErrorIsNil)
 
2125
        assertSupportedContainers(c, machine, []instance.ContainerType{instance.LXD})
 
2126
}
 
2127
 
 
2128
func (s *MachineSuite) TestSetSupportedContainersSame(c *gc.C) {
 
2129
        machine := s.addMachineWithSupportedContainer(c, instance.LXD)
 
2130
 
 
2131
        err := machine.SetSupportedContainers([]instance.ContainerType{instance.LXD})
 
2132
        c.Assert(err, jc.ErrorIsNil)
 
2133
        assertSupportedContainers(c, machine, []instance.ContainerType{instance.LXD})
 
2134
}
 
2135
 
 
2136
func (s *MachineSuite) TestSetSupportedContainersNew(c *gc.C) {
 
2137
        machine := s.addMachineWithSupportedContainer(c, instance.LXD)
 
2138
 
 
2139
        err := machine.SetSupportedContainers([]instance.ContainerType{instance.LXD, instance.KVM})
 
2140
        c.Assert(err, jc.ErrorIsNil)
 
2141
        assertSupportedContainers(c, machine, []instance.ContainerType{instance.LXD, instance.KVM})
 
2142
}
 
2143
 
 
2144
func (s *MachineSuite) TestSetSupportedContainersMultipeNew(c *gc.C) {
 
2145
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2146
        c.Assert(err, jc.ErrorIsNil)
 
2147
 
 
2148
        err = machine.SetSupportedContainers([]instance.ContainerType{instance.LXD, instance.KVM})
 
2149
        c.Assert(err, jc.ErrorIsNil)
 
2150
        assertSupportedContainers(c, machine, []instance.ContainerType{instance.LXD, instance.KVM})
 
2151
}
 
2152
 
 
2153
func (s *MachineSuite) TestSetSupportedContainersMultipleExisting(c *gc.C) {
 
2154
        machine := s.addMachineWithSupportedContainer(c, instance.LXD)
 
2155
 
 
2156
        err := machine.SetSupportedContainers([]instance.ContainerType{instance.LXD, instance.KVM})
 
2157
        c.Assert(err, jc.ErrorIsNil)
 
2158
        assertSupportedContainers(c, machine, []instance.ContainerType{instance.LXD, instance.KVM})
 
2159
}
 
2160
 
 
2161
func (s *MachineSuite) TestSetSupportedContainersSetsUnknownToError(c *gc.C) {
 
2162
        // Create a machine and add lxd and kvm containers prior to calling SetSupportedContainers
 
2163
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2164
        template := state.MachineTemplate{
 
2165
                Series: "quantal",
 
2166
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
2167
        }
 
2168
        container, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.LXD)
 
2169
        c.Assert(err, jc.ErrorIsNil)
 
2170
        supportedContainer, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.KVM)
 
2171
        c.Assert(err, jc.ErrorIsNil)
 
2172
        err = machine.SetSupportedContainers([]instance.ContainerType{instance.KVM})
 
2173
        c.Assert(err, jc.ErrorIsNil)
 
2174
 
 
2175
        // A supported (kvm) container will have a pending status.
 
2176
        err = supportedContainer.Refresh()
 
2177
        c.Assert(err, jc.ErrorIsNil)
 
2178
        statusInfo, err := supportedContainer.Status()
 
2179
        c.Assert(err, jc.ErrorIsNil)
 
2180
        c.Assert(statusInfo.Status, gc.Equals, status.StatusPending)
 
2181
 
 
2182
        // An unsupported (lxd) container will have an error status.
 
2183
        err = container.Refresh()
 
2184
        c.Assert(err, jc.ErrorIsNil)
 
2185
        statusInfo, err = container.Status()
 
2186
        c.Assert(err, jc.ErrorIsNil)
 
2187
        c.Assert(statusInfo.Status, gc.Equals, status.StatusError)
 
2188
        c.Assert(statusInfo.Message, gc.Equals, "unsupported container")
 
2189
        c.Assert(statusInfo.Data, gc.DeepEquals, map[string]interface{}{"type": "lxd"})
 
2190
}
 
2191
 
 
2192
func (s *MachineSuite) TestSupportsNoContainersSetsAllToError(c *gc.C) {
 
2193
        // Create a machine and add all container types prior to calling SupportsNoContainers
 
2194
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2195
        var containers []*state.Machine
 
2196
        template := state.MachineTemplate{
 
2197
                Series: "quantal",
 
2198
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
2199
        }
 
2200
        for _, containerType := range instance.ContainerTypes {
 
2201
                container, err := s.State.AddMachineInsideMachine(template, machine.Id(), containerType)
 
2202
                c.Assert(err, jc.ErrorIsNil)
 
2203
                containers = append(containers, container)
 
2204
        }
 
2205
 
 
2206
        err = machine.SupportsNoContainers()
 
2207
        c.Assert(err, jc.ErrorIsNil)
 
2208
 
 
2209
        // All containers should be in error state.
 
2210
        for _, container := range containers {
 
2211
                err = container.Refresh()
 
2212
                c.Assert(err, jc.ErrorIsNil)
 
2213
                statusInfo, err := container.Status()
 
2214
                c.Assert(err, jc.ErrorIsNil)
 
2215
                c.Assert(statusInfo.Status, gc.Equals, status.StatusError)
 
2216
                c.Assert(statusInfo.Message, gc.Equals, "unsupported container")
 
2217
                containerType := state.ContainerTypeFromId(container.Id())
 
2218
                c.Assert(statusInfo.Data, gc.DeepEquals, map[string]interface{}{"type": string(containerType)})
 
2219
        }
 
2220
}
 
2221
 
 
2222
func (s *MachineSuite) TestMachineAgentTools(c *gc.C) {
 
2223
        m, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
2224
        c.Assert(err, jc.ErrorIsNil)
 
2225
        testAgentTools(c, m, "machine "+m.Id())
 
2226
}
 
2227
 
 
2228
func (s *MachineSuite) TestMachineValidActions(c *gc.C) {
 
2229
        m, err := s.State.AddMachine("trusty", state.JobHostUnits)
 
2230
        c.Assert(err, jc.ErrorIsNil)
 
2231
 
 
2232
        var tests = []struct {
 
2233
                actionName      string
 
2234
                errString       string
 
2235
                givenPayload    map[string]interface{}
 
2236
                expectedPayload map[string]interface{}
 
2237
        }{
 
2238
                {
 
2239
                        actionName: "juju-run",
 
2240
                        errString:  `validation failed: (root) : "command" property is missing and required, given {}; (root) : "timeout" property is missing and required, given {}`,
 
2241
                },
 
2242
                {
 
2243
                        actionName:      "juju-run",
 
2244
                        givenPayload:    map[string]interface{}{"command": "allyourbasearebelongtous", "timeout": 5.0},
 
2245
                        expectedPayload: map[string]interface{}{"command": "allyourbasearebelongtous", "timeout": 5.0},
 
2246
                },
 
2247
                {
 
2248
                        actionName: "baiku",
 
2249
                        errString:  `cannot add action "baiku" to a machine; only predefined actions allowed`,
 
2250
                },
 
2251
        }
 
2252
 
 
2253
        for i, t := range tests {
 
2254
                c.Logf("running test %d", i)
 
2255
                action, err := m.AddAction(t.actionName, t.givenPayload)
 
2256
                if t.errString != "" {
 
2257
                        c.Assert(err.Error(), gc.Equals, t.errString)
 
2258
                        continue
 
2259
                } else {
 
2260
                        c.Assert(err, jc.ErrorIsNil)
 
2261
                        c.Assert(action.Parameters(), jc.DeepEquals, t.expectedPayload)
 
2262
                }
 
2263
        }
 
2264
}
 
2265
 
 
2266
func (s *MachineSuite) TestMachineAddDifferentAction(c *gc.C) {
 
2267
        m, err := s.State.AddMachine("trusty", state.JobHostUnits)
 
2268
        c.Assert(err, jc.ErrorIsNil)
 
2269
 
 
2270
        _, err = m.AddAction("benchmark", nil)
 
2271
        c.Assert(err, gc.ErrorMatches, `cannot add action "benchmark" to a machine; only predefined actions allowed`)
 
2272
}