~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

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

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package state_test
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "strings"
 
9
 
 
10
        "github.com/juju/errors"
 
11
        jc "github.com/juju/testing/checkers"
 
12
        jujutxn "github.com/juju/txn"
 
13
        gc "gopkg.in/check.v1"
 
14
 
 
15
        "github.com/juju/juju/instance"
 
16
        "github.com/juju/juju/state"
 
17
)
 
18
 
 
19
// linkLayerDevicesStateSuite contains white-box tests for link-layer network
 
20
// devices, which include access to mongo.
 
21
type linkLayerDevicesStateSuite struct {
 
22
        ConnSuite
 
23
 
 
24
        machine          *state.Machine
 
25
        containerMachine *state.Machine
 
26
 
 
27
        otherState        *state.State
 
28
        otherStateMachine *state.Machine
 
29
}
 
30
 
 
31
var _ = gc.Suite(&linkLayerDevicesStateSuite{})
 
32
 
 
33
func (s *linkLayerDevicesStateSuite) SetUpTest(c *gc.C) {
 
34
        s.ConnSuite.SetUpTest(c)
 
35
 
 
36
        var err error
 
37
        s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
 
38
        c.Assert(err, jc.ErrorIsNil)
 
39
 
 
40
        s.otherState = s.NewStateForModelNamed(c, "other-model")
 
41
        s.otherStateMachine, err = s.otherState.AddMachine("quantal", state.JobHostUnits)
 
42
        c.Assert(err, jc.ErrorIsNil)
 
43
}
 
44
 
 
45
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesNoArgs(c *gc.C) {
 
46
        err := s.machine.AddLinkLayerDevices() // takes varargs, which includes none.
 
47
        expectedError := fmt.Sprintf("cannot add link-layer devices to machine %q: no devices to add", s.machine.Id())
 
48
        c.Assert(err, gc.ErrorMatches, expectedError)
 
49
}
 
50
 
 
51
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesEmptyArgs(c *gc.C) {
 
52
        args := state.LinkLayerDeviceArgs{}
 
53
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, "empty Name not valid")
 
54
}
 
55
 
 
56
func (s *linkLayerDevicesStateSuite) assertAddLinkLayerDevicesReturnsNotValidError(c *gc.C, args state.LinkLayerDeviceArgs, errorCauseMatches string) {
 
57
        err := s.assertAddLinkLayerDevicesFailsValidationForArgs(c, args, errorCauseMatches)
 
58
        c.Assert(err, jc.Satisfies, errors.IsNotValid)
 
59
}
 
60
 
 
61
func (s *linkLayerDevicesStateSuite) assertAddLinkLayerDevicesFailsValidationForArgs(c *gc.C, args state.LinkLayerDeviceArgs, errorCauseMatches string) error {
 
62
        expectedError := fmt.Sprintf("invalid device %q: %s", args.Name, errorCauseMatches)
 
63
        return s.assertAddLinkLayerDevicesFailsForArgs(c, args, expectedError)
 
64
}
 
65
 
 
66
func (s *linkLayerDevicesStateSuite) assertAddLinkLayerDevicesFailsForArgs(c *gc.C, args state.LinkLayerDeviceArgs, errorCauseMatches string) error {
 
67
        err := s.machine.AddLinkLayerDevices(args)
 
68
        expectedError := fmt.Sprintf("cannot add link-layer devices to machine %q: %s", s.machine.Id(), errorCauseMatches)
 
69
        c.Assert(err, gc.ErrorMatches, expectedError)
 
70
        return err
 
71
}
 
72
 
 
73
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidName(c *gc.C) {
 
74
        args := state.LinkLayerDeviceArgs{
 
75
                Name: "bad#name",
 
76
        }
 
77
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `Name "bad#name" not valid`)
 
78
}
 
79
 
 
80
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesSameNameAndParentName(c *gc.C) {
 
81
        args := state.LinkLayerDeviceArgs{
 
82
                Name:       "foo",
 
83
                ParentName: "foo",
 
84
        }
 
85
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `Name and ParentName must be different`)
 
86
}
 
87
 
 
88
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidType(c *gc.C) {
 
89
        args := state.LinkLayerDeviceArgs{
 
90
                Name: "bar",
 
91
                Type: "bad type",
 
92
        }
 
93
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `Type "bad type" not valid`)
 
94
}
 
95
 
 
96
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidParentName(c *gc.C) {
 
97
        var wayTooLongName = strings.Repeat("x", 256)
 
98
        args := state.LinkLayerDeviceArgs{
 
99
                Name:       "eth0",
 
100
                ParentName: wayTooLongName,
 
101
        }
 
102
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "x{256}" not valid`)
 
103
}
 
104
 
 
105
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsInvalidGlobalKey(c *gc.C) {
 
106
        args := state.LinkLayerDeviceArgs{
 
107
                Name:       "eth0",
 
108
                ParentName: "x#foo#y#bar", // contains the right amount of # but is invalid otherwise.
 
109
        }
 
110
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "x#foo#y#bar" format not valid`)
 
111
}
 
112
 
 
113
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsGlobalKeyFailsForNonContainerMachine(c *gc.C) {
 
114
        args := state.LinkLayerDeviceArgs{
 
115
                Name:       "eth0",
 
116
                ParentName: "m#42#d#foo", // any non-container ID here will cause the same error.
 
117
        }
 
118
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "m#42#d#foo" for non-container machine "0" not valid`)
 
119
}
 
120
 
 
121
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsGlobalKeyFailsForContainerOnDifferentHost(c *gc.C) {
 
122
        args := state.LinkLayerDeviceArgs{
 
123
                Name:       "eth0",
 
124
                ParentName: "m#42#d#foo", // any ID other than s.containerMachine's parent ID here will cause the same error.
 
125
        }
 
126
        s.addContainerMachine(c)
 
127
        err := s.containerMachine.AddLinkLayerDevices(args)
 
128
        errorPrefix := fmt.Sprintf("cannot add link-layer devices to machine %q: invalid device %q: ", s.containerMachine.Id(), args.Name)
 
129
        c.Assert(err, gc.ErrorMatches, errorPrefix+`ParentName "m#42#d#foo" on non-host machine "42" not valid`)
 
130
        c.Assert(err, jc.Satisfies, errors.IsNotValid)
 
131
}
 
132
 
 
133
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsGlobalKeyFailsForContainerIfParentMissing(c *gc.C) {
 
134
        args := state.LinkLayerDeviceArgs{
 
135
                Name:       "eth0",
 
136
                ParentName: "m#0#d#missing",
 
137
        }
 
138
        s.addContainerMachine(c)
 
139
        err := s.containerMachine.AddLinkLayerDevices(args)
 
140
        c.Assert(err, gc.ErrorMatches, `.*parent device "missing" on host machine "0" not found`)
 
141
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
142
}
 
143
 
 
144
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidMACAddress(c *gc.C) {
 
145
        args := state.LinkLayerDeviceArgs{
 
146
                Name:       "eth0",
 
147
                Type:       state.EthernetDevice,
 
148
                MACAddress: "bad mac",
 
149
        }
 
150
        s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `MACAddress "bad mac" not valid`)
 
151
}
 
152
 
 
153
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWhenMachineNotAliveOrGone(c *gc.C) {
 
154
        err := s.machine.EnsureDead()
 
155
        c.Assert(err, jc.ErrorIsNil)
 
156
 
 
157
        args := state.LinkLayerDeviceArgs{
 
158
                Name: "eth0",
 
159
                Type: state.EthernetDevice,
 
160
        }
 
161
        s.assertAddLinkLayerDevicesFailsForArgs(c, args, "machine not found or not alive")
 
162
 
 
163
        err = s.machine.Remove()
 
164
        c.Assert(err, jc.ErrorIsNil)
 
165
 
 
166
        s.assertAddLinkLayerDevicesFailsForArgs(c, args, "machine not found or not alive")
 
167
}
 
168
 
 
169
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWhenModelNotAlive(c *gc.C) {
 
170
        otherModel, err := s.otherState.Model()
 
171
        c.Assert(err, jc.ErrorIsNil)
 
172
        err = otherModel.Destroy()
 
173
        c.Assert(err, jc.ErrorIsNil)
 
174
 
 
175
        args := state.LinkLayerDeviceArgs{
 
176
                Name: "eth0",
 
177
                Type: state.EthernetDevice,
 
178
        }
 
179
        err = s.otherStateMachine.AddLinkLayerDevices(args)
 
180
        expectedError := fmt.Sprintf(
 
181
                "cannot add link-layer devices to machine %q: model %q is no longer alive",
 
182
                s.otherStateMachine.Id(), otherModel.Name(),
 
183
        )
 
184
        c.Assert(err, gc.ErrorMatches, expectedError)
 
185
}
 
186
 
 
187
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithMissingParent(c *gc.C) {
 
188
        args := state.LinkLayerDeviceArgs{
 
189
                Name:       "eth0",
 
190
                Type:       state.EthernetDevice,
 
191
                ParentName: "br-eth0",
 
192
        }
 
193
        err := s.assertAddLinkLayerDevicesFailsForArgs(c, args, `parent device "br-eth0" of device "eth0" not found`)
 
194
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
195
}
 
196
 
 
197
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesNoParentSuccess(c *gc.C) {
 
198
        args := state.LinkLayerDeviceArgs{
 
199
                Name:        "eth0.42",
 
200
                MTU:         9000,
 
201
                ProviderID:  "eni-42",
 
202
                Type:        state.VLAN_8021QDevice,
 
203
                MACAddress:  "aa:bb:cc:dd:ee:f0",
 
204
                IsAutoStart: true,
 
205
                IsUp:        true,
 
206
        }
 
207
        s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
 
208
}
 
209
 
 
210
func (s *linkLayerDevicesStateSuite) assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(
 
211
        c *gc.C,
 
212
        args state.LinkLayerDeviceArgs,
 
213
) *state.LinkLayerDevice {
 
214
        return s.assertMachineAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, s.machine, args, s.State.ModelUUID())
 
215
}
 
216
 
 
217
func (s *linkLayerDevicesStateSuite) assertMachineAddLinkLayerDevicesSucceedsAndResultMatchesArgs(
 
218
        c *gc.C,
 
219
        machine *state.Machine,
 
220
        args state.LinkLayerDeviceArgs,
 
221
        modelUUID string,
 
222
) *state.LinkLayerDevice {
 
223
        err := machine.AddLinkLayerDevices(args)
 
224
        c.Assert(err, jc.ErrorIsNil)
 
225
        result, err := machine.LinkLayerDevice(args.Name)
 
226
        c.Assert(err, jc.ErrorIsNil)
 
227
        c.Assert(result, gc.NotNil)
 
228
 
 
229
        s.checkAddedDeviceMatchesArgs(c, result, args)
 
230
        s.checkAddedDeviceMatchesMachineIDAndModelUUID(c, result, s.machine.Id(), modelUUID)
 
231
        return result
 
232
}
 
233
 
 
234
func (s *linkLayerDevicesStateSuite) checkAddedDeviceMatchesArgs(c *gc.C, addedDevice *state.LinkLayerDevice, args state.LinkLayerDeviceArgs) {
 
235
        c.Check(addedDevice.Name(), gc.Equals, args.Name)
 
236
        c.Check(addedDevice.MTU(), gc.Equals, args.MTU)
 
237
        c.Check(addedDevice.ProviderID(), gc.Equals, args.ProviderID)
 
238
        c.Check(addedDevice.Type(), gc.Equals, args.Type)
 
239
        c.Check(addedDevice.MACAddress(), gc.Equals, args.MACAddress)
 
240
        c.Check(addedDevice.IsAutoStart(), gc.Equals, args.IsAutoStart)
 
241
        c.Check(addedDevice.IsUp(), gc.Equals, args.IsUp)
 
242
        c.Check(addedDevice.ParentName(), gc.Equals, args.ParentName)
 
243
}
 
244
 
 
245
func (s *linkLayerDevicesStateSuite) checkAddedDeviceMatchesMachineIDAndModelUUID(c *gc.C, addedDevice *state.LinkLayerDevice, machineID, modelUUID string) {
 
246
        globalKey := fmt.Sprintf("m#%s#d#%s", machineID, addedDevice.Name())
 
247
        c.Check(addedDevice.DocID(), gc.Equals, modelUUID+":"+globalKey)
 
248
        c.Check(addedDevice.MachineID(), gc.Equals, machineID)
 
249
}
 
250
 
 
251
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesNoProviderIDSuccess(c *gc.C) {
 
252
        args := state.LinkLayerDeviceArgs{
 
253
                Name: "eno0",
 
254
                Type: state.EthernetDevice,
 
255
        }
 
256
        s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
 
257
}
 
258
 
 
259
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateProviderIDFailsInSameModel(c *gc.C) {
 
260
        args1 := state.LinkLayerDeviceArgs{
 
261
                Name:       "eth0.42",
 
262
                Type:       state.EthernetDevice,
 
263
                ProviderID: "42",
 
264
        }
 
265
        s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args1)
 
266
 
 
267
        args2 := args1
 
268
        args2.Name = "br-eth0"
 
269
        err := s.assertAddLinkLayerDevicesFailsValidationForArgs(c, args2, `ProviderID\(s\) not unique: 42`)
 
270
        c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError)
 
271
}
 
272
 
 
273
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateNameAndProviderIDSucceedsInDifferentModels(c *gc.C) {
 
274
        args := state.LinkLayerDeviceArgs{
 
275
                Name:       "eth0.42",
 
276
                Type:       state.EthernetDevice,
 
277
                ProviderID: "42",
 
278
        }
 
279
        s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
 
280
 
 
281
        s.assertMachineAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, s.otherStateMachine, args, s.otherState.ModelUUID())
 
282
}
 
283
 
 
284
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateNameAndEmptyProviderIDReturnsAlreadyExistsErrorInSameModel(c *gc.C) {
 
285
        args := state.LinkLayerDeviceArgs{
 
286
                Name: "eth0.42",
 
287
                Type: state.EthernetDevice,
 
288
        }
 
289
        s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
 
290
 
 
291
        err := s.assertAddLinkLayerDevicesFailsForArgs(c, args, `device "eth0.42" already exists`)
 
292
        c.Assert(err, jc.Satisfies, errors.IsAlreadyExists)
 
293
}
 
294
 
 
295
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateNameAndProviderIDFailsInSameModel(c *gc.C) {
 
296
        args := state.LinkLayerDeviceArgs{
 
297
                Name:       "foo",
 
298
                Type:       state.EthernetDevice,
 
299
                ProviderID: "42",
 
300
        }
 
301
        s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
 
302
 
 
303
        err := s.assertAddLinkLayerDevicesFailsValidationForArgs(c, args, `ProviderID\(s\) not unique: 42`)
 
304
        c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError)
 
305
}
 
306
 
 
307
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesMultipleArgsWithSameNameFails(c *gc.C) {
 
308
        foo1 := state.LinkLayerDeviceArgs{
 
309
                Name: "foo",
 
310
                Type: state.BridgeDevice,
 
311
        }
 
312
        foo2 := state.LinkLayerDeviceArgs{
 
313
                Name: "foo",
 
314
                Type: state.EthernetDevice,
 
315
        }
 
316
        err := s.machine.AddLinkLayerDevices(foo1, foo2)
 
317
        c.Assert(err, gc.ErrorMatches, `.*invalid device "foo": Name specified more than once`)
 
318
        c.Assert(err, jc.Satisfies, errors.IsNotValid)
 
319
}
 
320
 
 
321
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesRefusesToAddParentAndChildrenInTheSameCall(c *gc.C) {
 
322
        allArgs := []state.LinkLayerDeviceArgs{{
 
323
                Name:       "child1",
 
324
                Type:       state.EthernetDevice,
 
325
                ParentName: "parent1",
 
326
        }, {
 
327
                Name: "parent1",
 
328
                Type: state.BridgeDevice,
 
329
        }}
 
330
 
 
331
        err := s.machine.AddLinkLayerDevices(allArgs...)
 
332
        c.Assert(err, gc.ErrorMatches, `cannot add link-layer devices to machine "0": `+
 
333
                `parent device "parent1" of device "child1" not found`)
 
334
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
335
}
 
336
 
 
337
func (s *linkLayerDevicesStateSuite) addMultipleDevicesSucceedsAndCheckAllAdded(c *gc.C, allArgs []state.LinkLayerDeviceArgs) []*state.LinkLayerDevice {
 
338
        err := s.machine.AddLinkLayerDevices(allArgs...)
 
339
        c.Assert(err, jc.ErrorIsNil)
 
340
 
 
341
        var results []*state.LinkLayerDevice
 
342
        machineID, modelUUID := s.machine.Id(), s.State.ModelUUID()
 
343
        for _, args := range allArgs {
 
344
                device, err := s.machine.LinkLayerDevice(args.Name)
 
345
                c.Check(err, jc.ErrorIsNil)
 
346
                s.checkAddedDeviceMatchesArgs(c, device, args)
 
347
                s.checkAddedDeviceMatchesMachineIDAndModelUUID(c, device, machineID, modelUUID)
 
348
                results = append(results, device)
 
349
        }
 
350
        return results
 
351
}
 
352
 
 
353
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesMultipleChildrenOfExistingParentSucceeds(c *gc.C) {
 
354
        s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "child1", "child2")
 
355
}
 
356
 
 
357
func (s *linkLayerDevicesStateSuite) addNamedParentDeviceWithChildrenAndCheckAllAdded(c *gc.C, parentName string, childrenNames ...string) (
 
358
        parent *state.LinkLayerDevice,
 
359
        children []*state.LinkLayerDevice,
 
360
) {
 
361
        parent = s.addNamedDevice(c, parentName)
 
362
        childrenArgs := make([]state.LinkLayerDeviceArgs, len(childrenNames))
 
363
        for i, childName := range childrenNames {
 
364
                childrenArgs[i] = state.LinkLayerDeviceArgs{
 
365
                        Name:       childName,
 
366
                        Type:       state.EthernetDevice,
 
367
                        ParentName: parentName,
 
368
                }
 
369
        }
 
370
 
 
371
        children = s.addMultipleDevicesSucceedsAndCheckAllAdded(c, childrenArgs)
 
372
        return parent, children
 
373
}
 
374
 
 
375
func (s *linkLayerDevicesStateSuite) addSimpleDevice(c *gc.C) *state.LinkLayerDevice {
 
376
        return s.addNamedDevice(c, "foo")
 
377
}
 
378
 
 
379
func (s *linkLayerDevicesStateSuite) addNamedDevice(c *gc.C, name string) *state.LinkLayerDevice {
 
380
        args := state.LinkLayerDeviceArgs{
 
381
                Name: name,
 
382
                Type: state.EthernetDevice,
 
383
        }
 
384
        err := s.machine.AddLinkLayerDevices(args)
 
385
        c.Assert(err, jc.ErrorIsNil)
 
386
        device, err := s.machine.LinkLayerDevice(name)
 
387
        c.Assert(err, jc.ErrorIsNil)
 
388
        return device
 
389
}
 
390
 
 
391
func (s *linkLayerDevicesStateSuite) TestMachineMethodReturnsNotFoundErrorWhenMissing(c *gc.C) {
 
392
        device := s.addSimpleDevice(c)
 
393
 
 
394
        err := s.machine.EnsureDead()
 
395
        c.Assert(err, jc.ErrorIsNil)
 
396
        err = s.machine.Remove()
 
397
        c.Assert(err, jc.ErrorIsNil)
 
398
 
 
399
        result, err := device.Machine()
 
400
        c.Assert(err, gc.ErrorMatches, "machine 0 not found")
 
401
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
402
        c.Assert(result, gc.IsNil)
 
403
}
 
404
 
 
405
func (s *linkLayerDevicesStateSuite) TestMachineMethodReturnsMachine(c *gc.C) {
 
406
        device := s.addSimpleDevice(c)
 
407
 
 
408
        result, err := device.Machine()
 
409
        c.Assert(err, jc.ErrorIsNil)
 
410
        c.Assert(result, jc.DeepEquals, s.machine)
 
411
}
 
412
 
 
413
func (s *linkLayerDevicesStateSuite) TestParentDeviceReturnsLinkLayerDevice(c *gc.C) {
 
414
        parent, children := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "br-eth0", "eth0")
 
415
 
 
416
        child := children[0]
 
417
        parentCopy, err := child.ParentDevice()
 
418
        c.Assert(err, jc.ErrorIsNil)
 
419
        c.Assert(parentCopy, jc.DeepEquals, parent)
 
420
}
 
421
 
 
422
func (s *linkLayerDevicesStateSuite) TestMachineLinkLayerDeviceReturnsNotFoundErrorWhenMissing(c *gc.C) {
 
423
        result, err := s.machine.LinkLayerDevice("missing")
 
424
        c.Assert(result, gc.IsNil)
 
425
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
426
        c.Assert(err, gc.ErrorMatches, `device "missing" on machine "0" not found`)
 
427
}
 
428
 
 
429
func (s *linkLayerDevicesStateSuite) TestMachineLinkLayerDeviceReturnsLinkLayerDevice(c *gc.C) {
 
430
        existingDevice := s.addSimpleDevice(c)
 
431
 
 
432
        result, err := s.machine.LinkLayerDevice(existingDevice.Name())
 
433
        c.Assert(err, jc.ErrorIsNil)
 
434
        c.Assert(result, jc.DeepEquals, existingDevice)
 
435
}
 
436
 
 
437
func (s *linkLayerDevicesStateSuite) TestMachineAllLinkLayerDevices(c *gc.C) {
 
438
        s.assertNoDevicesOnMachine(c, s.machine)
 
439
        topParent, secondLevelParents := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "br-bond0", "bond0")
 
440
        secondLevelParent := secondLevelParents[0]
 
441
 
 
442
        secondLevelChildrenArgs := []state.LinkLayerDeviceArgs{{
 
443
                Name:       "eth0",
 
444
                Type:       state.EthernetDevice,
 
445
                ParentName: secondLevelParent.Name(),
 
446
        }, {
 
447
                Name:       "eth1",
 
448
                Type:       state.EthernetDevice,
 
449
                ParentName: secondLevelParent.Name(),
 
450
        }}
 
451
        s.addMultipleDevicesSucceedsAndCheckAllAdded(c, secondLevelChildrenArgs)
 
452
 
 
453
        results, err := s.machine.AllLinkLayerDevices()
 
454
        c.Assert(err, jc.ErrorIsNil)
 
455
        c.Assert(results, gc.HasLen, 4)
 
456
        for _, result := range results {
 
457
                c.Check(result, gc.NotNil)
 
458
                c.Check(result.MachineID(), gc.Equals, s.machine.Id())
 
459
                c.Check(result.Name(), gc.Matches, `(br-bond0|bond0|eth0|eth1)`)
 
460
                if result.Name() == topParent.Name() {
 
461
                        c.Check(result.ParentName(), gc.Equals, "")
 
462
                        continue
 
463
                }
 
464
                c.Check(result.ParentName(), gc.Matches, `(br-bond0|bond0)`)
 
465
        }
 
466
}
 
467
 
 
468
func (s *linkLayerDevicesStateSuite) assertNoDevicesOnMachine(c *gc.C, machine *state.Machine) {
 
469
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, machine, 0)
 
470
}
 
471
 
 
472
func (s *linkLayerDevicesStateSuite) assertAllLinkLayerDevicesOnMachineMatchCount(c *gc.C, machine *state.Machine, expectedCount int) {
 
473
        results, err := machine.AllLinkLayerDevices()
 
474
        c.Assert(err, jc.ErrorIsNil)
 
475
        c.Assert(results, gc.HasLen, expectedCount)
 
476
}
 
477
 
 
478
func (s *linkLayerDevicesStateSuite) TestMachineAllLinkLayerDevicesOnlyReturnsSameModelDevices(c *gc.C) {
 
479
        s.assertNoDevicesOnMachine(c, s.machine)
 
480
        s.assertNoDevicesOnMachine(c, s.otherStateMachine)
 
481
 
 
482
        s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "foo.42")
 
483
 
 
484
        results, err := s.machine.AllLinkLayerDevices()
 
485
        c.Assert(err, jc.ErrorIsNil)
 
486
        c.Assert(results, gc.HasLen, 2)
 
487
        c.Assert(results[0].Name(), gc.Equals, "foo")
 
488
        c.Assert(results[1].Name(), gc.Equals, "foo.42")
 
489
 
 
490
        s.assertNoDevicesOnMachine(c, s.otherStateMachine)
 
491
}
 
492
 
 
493
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveFailsWithExistingChildren(c *gc.C) {
 
494
        parent, _ := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "one-child", "another-child")
 
495
 
 
496
        err := parent.Remove()
 
497
        expectedError := fmt.Sprintf(
 
498
                "cannot remove %s: parent device %q has 2 children",
 
499
                parent, parent.Name(),
 
500
        )
 
501
        c.Assert(err, gc.ErrorMatches, expectedError)
 
502
        c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError)
 
503
}
 
504
 
 
505
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveSuccess(c *gc.C) {
 
506
        existingDevice := s.addSimpleDevice(c)
 
507
 
 
508
        s.removeDeviceAndAssertSuccess(c, existingDevice)
 
509
        s.assertNoDevicesOnMachine(c, s.machine)
 
510
}
 
511
 
 
512
func (s *linkLayerDevicesStateSuite) removeDeviceAndAssertSuccess(c *gc.C, givenDevice *state.LinkLayerDevice) {
 
513
        err := givenDevice.Remove()
 
514
        c.Assert(err, jc.ErrorIsNil)
 
515
}
 
516
 
 
517
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveTwiceStillSucceeds(c *gc.C) {
 
518
        existingDevice := s.addSimpleDevice(c)
 
519
 
 
520
        s.removeDeviceAndAssertSuccess(c, existingDevice)
 
521
        s.removeDeviceAndAssertSuccess(c, existingDevice)
 
522
        s.assertNoDevicesOnMachine(c, s.machine)
 
523
}
 
524
 
 
525
func (s *linkLayerDevicesStateSuite) TestMachineRemoveAllLinkLayerDevicesSuccess(c *gc.C) {
 
526
        s.assertNoDevicesOnMachine(c, s.machine)
 
527
        s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "bar")
 
528
 
 
529
        err := s.machine.RemoveAllLinkLayerDevices()
 
530
        c.Assert(err, jc.ErrorIsNil)
 
531
        s.assertNoDevicesOnMachine(c, s.machine)
 
532
}
 
533
 
 
534
func (s *linkLayerDevicesStateSuite) TestMachineRemoveAllLinkLayerDevicesNoErrorIfNoDevicesExist(c *gc.C) {
 
535
        s.assertNoDevicesOnMachine(c, s.machine)
 
536
 
 
537
        err := s.machine.RemoveAllLinkLayerDevices()
 
538
        c.Assert(err, jc.ErrorIsNil)
 
539
}
 
540
 
 
541
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesRollbackWithDuplicateProviderIDs(c *gc.C) {
 
542
        parent := s.addNamedDevice(c, "parent")
 
543
        insertingArgs := []state.LinkLayerDeviceArgs{{
 
544
                Name:       "child1",
 
545
                Type:       state.EthernetDevice,
 
546
                ProviderID: "child1-id",
 
547
                ParentName: parent.Name(),
 
548
        }, {
 
549
                Name:       "child2",
 
550
                Type:       state.BridgeDevice,
 
551
                ProviderID: "child2-id",
 
552
                ParentName: parent.Name(),
 
553
        }}
 
554
 
 
555
        assertThreeExistAndRemoveChildren := func(childrenNames ...string) {
 
556
                s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 3)
 
557
                for _, childName := range childrenNames {
 
558
                        child, err := s.machine.LinkLayerDevice(childName)
 
559
                        c.Check(err, jc.ErrorIsNil)
 
560
                        c.Check(child.Remove(), jc.ErrorIsNil)
 
561
                }
 
562
        }
 
563
 
 
564
        hooks := []jujutxn.TestHook{{
 
565
                Before: func() {
 
566
                        // Add the same devices to trigger ErrAborted in the first attempt.
 
567
                        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // only the parent exists
 
568
                        err := s.machine.AddLinkLayerDevices(insertingArgs...)
 
569
                        c.Assert(err, jc.ErrorIsNil)
 
570
                },
 
571
                After: func() {
 
572
                        assertThreeExistAndRemoveChildren("child1", "child2")
 
573
                },
 
574
        }, {
 
575
                Before: func() {
 
576
                        // Add devices with same ProviderIDs but different names.
 
577
                        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // only the parent exists
 
578
                        insertingAlternateArgs := insertingArgs
 
579
                        insertingAlternateArgs[0].Name = "other-child1"
 
580
                        insertingAlternateArgs[1].Name = "other-child2"
 
581
                        err := s.machine.AddLinkLayerDevices(insertingAlternateArgs...)
 
582
                        c.Assert(err, jc.ErrorIsNil)
 
583
                },
 
584
                After: func() {
 
585
                        assertThreeExistAndRemoveChildren("other-child1", "other-child2")
 
586
                },
 
587
        }}
 
588
        defer state.SetTestHooks(c, s.State, hooks...).Check()
 
589
 
 
590
        err := s.machine.AddLinkLayerDevices(insertingArgs...)
 
591
        c.Assert(err, gc.ErrorMatches, `.*ProviderID\(s\) not unique: child1-id, child2-id`)
 
592
        c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError)
 
593
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // only the parent exists and rollback worked.
 
594
}
 
595
 
 
596
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithLightStateChurn(c *gc.C) {
 
597
        childArgs, churnHook := s.prepareAddLinkLayerDevicesWithStateChurn(c)
 
598
        defer state.SetTestHooks(c, s.State, churnHook).Check()
 
599
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // parent only
 
600
 
 
601
        err := s.machine.AddLinkLayerDevices(childArgs)
 
602
        c.Assert(err, jc.ErrorIsNil)
 
603
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // both parent and child remain
 
604
}
 
605
 
 
606
func (s *linkLayerDevicesStateSuite) prepareAddLinkLayerDevicesWithStateChurn(c *gc.C) (state.LinkLayerDeviceArgs, jujutxn.TestHook) {
 
607
        parent := s.addNamedDevice(c, "parent")
 
608
        childArgs := state.LinkLayerDeviceArgs{
 
609
                Name:       "child",
 
610
                Type:       state.EthernetDevice,
 
611
                ParentName: parent.Name(),
 
612
        }
 
613
 
 
614
        churnHook := jujutxn.TestHook{
 
615
                Before: func() {
 
616
                        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // just the parent
 
617
                        err := s.machine.AddLinkLayerDevices(childArgs)
 
618
                        c.Assert(err, jc.ErrorIsNil)
 
619
                },
 
620
                After: func() {
 
621
                        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // parent and child
 
622
                        child, err := s.machine.LinkLayerDevice("child")
 
623
                        c.Assert(err, jc.ErrorIsNil)
 
624
                        err = child.Remove()
 
625
                        c.Assert(err, jc.ErrorIsNil)
 
626
                },
 
627
        }
 
628
 
 
629
        return childArgs, churnHook
 
630
}
 
631
 
 
632
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithModerateStateChurn(c *gc.C) {
 
633
        childArgs, churnHook := s.prepareAddLinkLayerDevicesWithStateChurn(c)
 
634
        defer state.SetTestHooks(c, s.State, churnHook, churnHook).Check()
 
635
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // parent only
 
636
 
 
637
        err := s.machine.AddLinkLayerDevices(childArgs)
 
638
        c.Assert(err, jc.ErrorIsNil)
 
639
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // both parent and child remain
 
640
}
 
641
 
 
642
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithTooMuchStateChurn(c *gc.C) {
 
643
        childArgs, churnHook := s.prepareAddLinkLayerDevicesWithStateChurn(c)
 
644
        defer state.SetTestHooks(c, s.State, churnHook, churnHook, churnHook).Check()
 
645
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // parent only
 
646
 
 
647
        err := s.machine.AddLinkLayerDevices(childArgs)
 
648
        c.Assert(errors.Cause(err), gc.Equals, jujutxn.ErrExcessiveContention)
 
649
        s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // only the parent remains
 
650
}
 
651
 
 
652
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesRefusesToAddContainerChildDeviceWithNonBridgeParent(c *gc.C) {
 
653
        // Add one device of every type to the host machine, except a BridgeDevice.
 
654
        hostDevicesArgs := []state.LinkLayerDeviceArgs{{
 
655
                Name: "loopback",
 
656
                Type: state.LoopbackDevice,
 
657
        }, {
 
658
                Name: "ethernet",
 
659
                Type: state.EthernetDevice,
 
660
        }, {
 
661
                Name: "vlan",
 
662
                Type: state.VLAN_8021QDevice,
 
663
        }, {
 
664
                Name: "bond",
 
665
                Type: state.BondDevice,
 
666
        }}
 
667
        hostDevices := s.addMultipleDevicesSucceedsAndCheckAllAdded(c, hostDevicesArgs)
 
668
        hostMachineParentDeviceGlobalKeyPrefix := "m#0#d#"
 
669
        s.addContainerMachine(c)
 
670
 
 
671
        // Now try adding an EthernetDevice on the container specifying each of the
 
672
        // hostDevices as parent and expect none of them to succeed, as none of the
 
673
        // hostDevices is a BridgeDevice.
 
674
        for _, hostDevice := range hostDevices {
 
675
                parentDeviceGlobalKey := hostMachineParentDeviceGlobalKeyPrefix + hostDevice.Name()
 
676
                containerDeviceArgs := state.LinkLayerDeviceArgs{
 
677
                        Name:       "eth0",
 
678
                        Type:       state.EthernetDevice,
 
679
                        ParentName: parentDeviceGlobalKey,
 
680
                }
 
681
                err := s.containerMachine.AddLinkLayerDevices(containerDeviceArgs)
 
682
                expectedError := `cannot add .* to machine "0/lxc/0": ` +
 
683
                        `invalid device "eth0": ` +
 
684
                        `parent device ".*" on host machine "0" must be of type "bridge", not type ".*"`
 
685
                c.Check(err, gc.ErrorMatches, expectedError)
 
686
                c.Check(err, jc.Satisfies, errors.IsNotValid)
 
687
        }
 
688
        s.assertNoDevicesOnMachine(c, s.containerMachine)
 
689
}
 
690
 
 
691
func (s *linkLayerDevicesStateSuite) addContainerMachine(c *gc.C) {
 
692
        // Add a container machine with s.machine as its host.
 
693
        containerTemplate := state.MachineTemplate{
 
694
                Series: "quantal",
 
695
                Jobs:   []state.MachineJob{state.JobHostUnits},
 
696
        }
 
697
        container, err := s.State.AddMachineInsideMachine(containerTemplate, s.machine.Id(), instance.LXC)
 
698
        c.Assert(err, jc.ErrorIsNil)
 
699
        s.containerMachine = container
 
700
}
 
701
 
 
702
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesAllowsParentBridgeDeviceForContainerDevice(c *gc.C) {
 
703
        parentDevice, _ := s.addParentBridgeDeviceWithContainerDevicesAsChildren(c, "br-eth1.250", "eth", 1)
 
704
        childDevice, err := s.containerMachine.LinkLayerDevice("eth0")
 
705
        c.Assert(err, jc.ErrorIsNil)
 
706
 
 
707
        c.Check(childDevice.Name(), gc.Equals, "eth0")
 
708
        c.Check(childDevice.ParentName(), gc.Equals, "m#0#d#br-eth1.250")
 
709
        c.Check(childDevice.MachineID(), gc.Equals, s.containerMachine.Id())
 
710
        parentOfChildDevice, err := childDevice.ParentDevice()
 
711
        c.Assert(err, jc.ErrorIsNil)
 
712
        c.Check(parentOfChildDevice, jc.DeepEquals, parentDevice)
 
713
}
 
714
 
 
715
func (s *linkLayerDevicesStateSuite) addParentBridgeDeviceWithContainerDevicesAsChildren(
 
716
        c *gc.C,
 
717
        parentName string,
 
718
        childDevicesNamePrefix string,
 
719
        numChildren int,
 
720
) (parentDevice *state.LinkLayerDevice, childrenDevices []*state.LinkLayerDevice) {
 
721
        parentArgs := state.LinkLayerDeviceArgs{
 
722
                Name: parentName,
 
723
                Type: state.BridgeDevice,
 
724
        }
 
725
        parentDevice = s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, parentArgs)
 
726
        parentDeviceGlobalKey := "m#" + s.machine.Id() + "#d#" + parentName
 
727
 
 
728
        childrenArgsTemplate := state.LinkLayerDeviceArgs{
 
729
                Type:       state.EthernetDevice,
 
730
                ParentName: parentDeviceGlobalKey,
 
731
        }
 
732
        childrenArgs := make([]state.LinkLayerDeviceArgs, numChildren)
 
733
        for i := 0; i < numChildren; i++ {
 
734
                childrenArgs[i] = childrenArgsTemplate
 
735
                childrenArgs[i].Name = fmt.Sprintf("%s%d", childDevicesNamePrefix, i)
 
736
        }
 
737
        s.addContainerMachine(c)
 
738
        err := s.containerMachine.AddLinkLayerDevices(childrenArgs...)
 
739
        c.Assert(err, jc.ErrorIsNil)
 
740
        childrenDevices, err = s.containerMachine.AllLinkLayerDevices()
 
741
        c.Assert(err, jc.ErrorIsNil)
 
742
        return parentDevice, childrenDevices
 
743
}
 
744
 
 
745
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveFailsWithExistingChildrenOnContainerMachine(c *gc.C) {
 
746
        parent, children := s.addParentBridgeDeviceWithContainerDevicesAsChildren(c, "br-eth1", "eth", 2)
 
747
 
 
748
        err := parent.Remove()
 
749
        expectedErrorPrefix := fmt.Sprintf("cannot remove %s: parent device %q has ", parent, parent.Name())
 
750
        c.Assert(err, gc.ErrorMatches, expectedErrorPrefix+"2 children")
 
751
        c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError)
 
752
 
 
753
        err = children[0].Remove()
 
754
        c.Assert(err, jc.ErrorIsNil)
 
755
 
 
756
        err = parent.Remove()
 
757
        c.Assert(err, gc.ErrorMatches, expectedErrorPrefix+"1 children")
 
758
        c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError)
 
759
 
 
760
        err = children[1].Remove()
 
761
        c.Assert(err, jc.ErrorIsNil)
 
762
        err = parent.Remove()
 
763
        c.Assert(err, jc.ErrorIsNil)
 
764
}
 
765
 
 
766
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesToContainerWhenContainerAndHostRemovedBeforehand(c *gc.C) {
 
767
        _, children := s.addParentBridgeDeviceWithContainerDevicesAsChildren(c, "br-eth1", "eth", 1)
 
768
        beforeHook := func() {
 
769
                // Remove both container and host machines.
 
770
                err := s.containerMachine.EnsureDead()
 
771
                c.Assert(err, jc.ErrorIsNil)
 
772
                err = s.containerMachine.Remove()
 
773
                c.Assert(err, jc.ErrorIsNil)
 
774
                err = s.machine.EnsureDead()
 
775
                c.Assert(err, jc.ErrorIsNil)
 
776
                err = s.machine.Remove()
 
777
                c.Assert(err, jc.ErrorIsNil)
 
778
        }
 
779
        defer state.SetBeforeHooks(c, s.State, beforeHook).Check()
 
780
 
 
781
        newChildArgs := state.LinkLayerDeviceArgs{
 
782
                Name:       "eth1",
 
783
                Type:       state.EthernetDevice,
 
784
                ParentName: children[0].ParentName(),
 
785
        }
 
786
        err := s.containerMachine.AddLinkLayerDevices(newChildArgs)
 
787
        c.Assert(err, gc.ErrorMatches, `.*host machine "0" of parent device "br-eth1" not found`)
 
788
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
789
}
 
790
 
 
791
func (s *linkLayerDevicesStateSuite) TestMachineRemoveAlsoRemoveAllLinkLayerDevices(c *gc.C) {
 
792
        s.assertNoDevicesOnMachine(c, s.machine)
 
793
        s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "bar")
 
794
 
 
795
        err := s.machine.EnsureDead()
 
796
        c.Assert(err, jc.ErrorIsNil)
 
797
        err = s.machine.Remove()
 
798
        c.Assert(err, jc.ErrorIsNil)
 
799
 
 
800
        s.assertNoDevicesOnMachine(c, s.machine)
 
801
}