1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
10
"github.com/juju/errors"
11
jc "github.com/juju/testing/checkers"
12
jujutxn "github.com/juju/txn"
13
gc "gopkg.in/check.v1"
15
"github.com/juju/juju/instance"
16
"github.com/juju/juju/state"
19
// linkLayerDevicesStateSuite contains white-box tests for link-layer network
20
// devices, which include access to mongo.
21
type linkLayerDevicesStateSuite struct {
24
machine *state.Machine
25
containerMachine *state.Machine
27
otherState *state.State
28
otherStateMachine *state.Machine
31
var _ = gc.Suite(&linkLayerDevicesStateSuite{})
33
func (s *linkLayerDevicesStateSuite) SetUpTest(c *gc.C) {
34
s.ConnSuite.SetUpTest(c)
37
s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
38
c.Assert(err, jc.ErrorIsNil)
40
s.otherState = s.NewStateForModelNamed(c, "other-model")
41
s.otherStateMachine, err = s.otherState.AddMachine("quantal", state.JobHostUnits)
42
c.Assert(err, jc.ErrorIsNil)
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)
51
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesEmptyArgs(c *gc.C) {
52
args := state.LinkLayerDeviceArgs{}
53
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, "empty Name not valid")
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)
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)
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)
73
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidName(c *gc.C) {
74
args := state.LinkLayerDeviceArgs{
77
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `Name "bad#name" not valid`)
80
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesSameNameAndParentName(c *gc.C) {
81
args := state.LinkLayerDeviceArgs{
85
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `Name and ParentName must be different`)
88
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidType(c *gc.C) {
89
args := state.LinkLayerDeviceArgs{
93
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `Type "bad type" not valid`)
96
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidParentName(c *gc.C) {
97
var wayTooLongName = strings.Repeat("x", 256)
98
args := state.LinkLayerDeviceArgs{
100
ParentName: wayTooLongName,
102
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "x{256}" not valid`)
105
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsInvalidGlobalKey(c *gc.C) {
106
args := state.LinkLayerDeviceArgs{
108
ParentName: "x#foo#y#bar", // contains the right amount of # but is invalid otherwise.
110
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "x#foo#y#bar" format not valid`)
113
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsGlobalKeyFailsForNonContainerMachine(c *gc.C) {
114
args := state.LinkLayerDeviceArgs{
116
ParentName: "m#42#d#foo", // any non-container ID here will cause the same error.
118
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "m#42#d#foo" for non-container machine "0" not valid`)
121
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsGlobalKeyFailsForContainerOnDifferentHost(c *gc.C) {
122
args := state.LinkLayerDeviceArgs{
124
ParentName: "m#42#d#foo", // any ID other than s.containerMachine's parent ID here will cause the same error.
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)
133
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesParentNameAsGlobalKeyFailsForContainerIfParentMissing(c *gc.C) {
134
args := state.LinkLayerDeviceArgs{
136
ParentName: "m#0#d#missing",
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)
144
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesInvalidMACAddress(c *gc.C) {
145
args := state.LinkLayerDeviceArgs{
147
Type: state.EthernetDevice,
148
MACAddress: "bad mac",
150
s.assertAddLinkLayerDevicesReturnsNotValidError(c, args, `MACAddress "bad mac" not valid`)
153
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWhenMachineNotAliveOrGone(c *gc.C) {
154
err := s.machine.EnsureDead()
155
c.Assert(err, jc.ErrorIsNil)
157
args := state.LinkLayerDeviceArgs{
159
Type: state.EthernetDevice,
161
s.assertAddLinkLayerDevicesFailsForArgs(c, args, "machine not found or not alive")
163
err = s.machine.Remove()
164
c.Assert(err, jc.ErrorIsNil)
166
s.assertAddLinkLayerDevicesFailsForArgs(c, args, "machine not found or not alive")
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)
175
args := state.LinkLayerDeviceArgs{
177
Type: state.EthernetDevice,
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(),
184
c.Assert(err, gc.ErrorMatches, expectedError)
187
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithMissingParent(c *gc.C) {
188
args := state.LinkLayerDeviceArgs{
190
Type: state.EthernetDevice,
191
ParentName: "br-eth0",
193
err := s.assertAddLinkLayerDevicesFailsForArgs(c, args, `parent device "br-eth0" of device "eth0" not found`)
194
c.Assert(err, jc.Satisfies, errors.IsNotFound)
197
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesNoParentSuccess(c *gc.C) {
198
args := state.LinkLayerDeviceArgs{
201
ProviderID: "eni-42",
202
Type: state.VLAN_8021QDevice,
203
MACAddress: "aa:bb:cc:dd:ee:f0",
207
s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
210
func (s *linkLayerDevicesStateSuite) assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(
212
args state.LinkLayerDeviceArgs,
213
) *state.LinkLayerDevice {
214
return s.assertMachineAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, s.machine, args, s.State.ModelUUID())
217
func (s *linkLayerDevicesStateSuite) assertMachineAddLinkLayerDevicesSucceedsAndResultMatchesArgs(
219
machine *state.Machine,
220
args state.LinkLayerDeviceArgs,
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)
229
s.checkAddedDeviceMatchesArgs(c, result, args)
230
s.checkAddedDeviceMatchesMachineIDAndModelUUID(c, result, s.machine.Id(), modelUUID)
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)
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)
251
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesNoProviderIDSuccess(c *gc.C) {
252
args := state.LinkLayerDeviceArgs{
254
Type: state.EthernetDevice,
256
s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
259
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateProviderIDFailsInSameModel(c *gc.C) {
260
args1 := state.LinkLayerDeviceArgs{
262
Type: state.EthernetDevice,
265
s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, 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)
273
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateNameAndProviderIDSucceedsInDifferentModels(c *gc.C) {
274
args := state.LinkLayerDeviceArgs{
276
Type: state.EthernetDevice,
279
s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
281
s.assertMachineAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, s.otherStateMachine, args, s.otherState.ModelUUID())
284
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateNameAndEmptyProviderIDReturnsAlreadyExistsErrorInSameModel(c *gc.C) {
285
args := state.LinkLayerDeviceArgs{
287
Type: state.EthernetDevice,
289
s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
291
err := s.assertAddLinkLayerDevicesFailsForArgs(c, args, `device "eth0.42" already exists`)
292
c.Assert(err, jc.Satisfies, errors.IsAlreadyExists)
295
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesWithDuplicateNameAndProviderIDFailsInSameModel(c *gc.C) {
296
args := state.LinkLayerDeviceArgs{
298
Type: state.EthernetDevice,
301
s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args)
303
err := s.assertAddLinkLayerDevicesFailsValidationForArgs(c, args, `ProviderID\(s\) not unique: 42`)
304
c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError)
307
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesMultipleArgsWithSameNameFails(c *gc.C) {
308
foo1 := state.LinkLayerDeviceArgs{
310
Type: state.BridgeDevice,
312
foo2 := state.LinkLayerDeviceArgs{
314
Type: state.EthernetDevice,
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)
321
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesRefusesToAddParentAndChildrenInTheSameCall(c *gc.C) {
322
allArgs := []state.LinkLayerDeviceArgs{{
324
Type: state.EthernetDevice,
325
ParentName: "parent1",
328
Type: state.BridgeDevice,
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)
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)
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)
353
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesMultipleChildrenOfExistingParentSucceeds(c *gc.C) {
354
s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "child1", "child2")
357
func (s *linkLayerDevicesStateSuite) addNamedParentDeviceWithChildrenAndCheckAllAdded(c *gc.C, parentName string, childrenNames ...string) (
358
parent *state.LinkLayerDevice,
359
children []*state.LinkLayerDevice,
361
parent = s.addNamedDevice(c, parentName)
362
childrenArgs := make([]state.LinkLayerDeviceArgs, len(childrenNames))
363
for i, childName := range childrenNames {
364
childrenArgs[i] = state.LinkLayerDeviceArgs{
366
Type: state.EthernetDevice,
367
ParentName: parentName,
371
children = s.addMultipleDevicesSucceedsAndCheckAllAdded(c, childrenArgs)
372
return parent, children
375
func (s *linkLayerDevicesStateSuite) addSimpleDevice(c *gc.C) *state.LinkLayerDevice {
376
return s.addNamedDevice(c, "foo")
379
func (s *linkLayerDevicesStateSuite) addNamedDevice(c *gc.C, name string) *state.LinkLayerDevice {
380
args := state.LinkLayerDeviceArgs{
382
Type: state.EthernetDevice,
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)
391
func (s *linkLayerDevicesStateSuite) TestMachineMethodReturnsNotFoundErrorWhenMissing(c *gc.C) {
392
device := s.addSimpleDevice(c)
394
err := s.machine.EnsureDead()
395
c.Assert(err, jc.ErrorIsNil)
396
err = s.machine.Remove()
397
c.Assert(err, jc.ErrorIsNil)
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)
405
func (s *linkLayerDevicesStateSuite) TestMachineMethodReturnsMachine(c *gc.C) {
406
device := s.addSimpleDevice(c)
408
result, err := device.Machine()
409
c.Assert(err, jc.ErrorIsNil)
410
c.Assert(result, jc.DeepEquals, s.machine)
413
func (s *linkLayerDevicesStateSuite) TestParentDeviceReturnsLinkLayerDevice(c *gc.C) {
414
parent, children := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "br-eth0", "eth0")
417
parentCopy, err := child.ParentDevice()
418
c.Assert(err, jc.ErrorIsNil)
419
c.Assert(parentCopy, jc.DeepEquals, parent)
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`)
429
func (s *linkLayerDevicesStateSuite) TestMachineLinkLayerDeviceReturnsLinkLayerDevice(c *gc.C) {
430
existingDevice := s.addSimpleDevice(c)
432
result, err := s.machine.LinkLayerDevice(existingDevice.Name())
433
c.Assert(err, jc.ErrorIsNil)
434
c.Assert(result, jc.DeepEquals, existingDevice)
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]
442
secondLevelChildrenArgs := []state.LinkLayerDeviceArgs{{
444
Type: state.EthernetDevice,
445
ParentName: secondLevelParent.Name(),
448
Type: state.EthernetDevice,
449
ParentName: secondLevelParent.Name(),
451
s.addMultipleDevicesSucceedsAndCheckAllAdded(c, secondLevelChildrenArgs)
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, "")
464
c.Check(result.ParentName(), gc.Matches, `(br-bond0|bond0)`)
468
func (s *linkLayerDevicesStateSuite) assertNoDevicesOnMachine(c *gc.C, machine *state.Machine) {
469
s.assertAllLinkLayerDevicesOnMachineMatchCount(c, machine, 0)
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)
478
func (s *linkLayerDevicesStateSuite) TestMachineAllLinkLayerDevicesOnlyReturnsSameModelDevices(c *gc.C) {
479
s.assertNoDevicesOnMachine(c, s.machine)
480
s.assertNoDevicesOnMachine(c, s.otherStateMachine)
482
s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "foo.42")
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")
490
s.assertNoDevicesOnMachine(c, s.otherStateMachine)
493
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveFailsWithExistingChildren(c *gc.C) {
494
parent, _ := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "one-child", "another-child")
496
err := parent.Remove()
497
expectedError := fmt.Sprintf(
498
"cannot remove %s: parent device %q has 2 children",
499
parent, parent.Name(),
501
c.Assert(err, gc.ErrorMatches, expectedError)
502
c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError)
505
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveSuccess(c *gc.C) {
506
existingDevice := s.addSimpleDevice(c)
508
s.removeDeviceAndAssertSuccess(c, existingDevice)
509
s.assertNoDevicesOnMachine(c, s.machine)
512
func (s *linkLayerDevicesStateSuite) removeDeviceAndAssertSuccess(c *gc.C, givenDevice *state.LinkLayerDevice) {
513
err := givenDevice.Remove()
514
c.Assert(err, jc.ErrorIsNil)
517
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveTwiceStillSucceeds(c *gc.C) {
518
existingDevice := s.addSimpleDevice(c)
520
s.removeDeviceAndAssertSuccess(c, existingDevice)
521
s.removeDeviceAndAssertSuccess(c, existingDevice)
522
s.assertNoDevicesOnMachine(c, s.machine)
525
func (s *linkLayerDevicesStateSuite) TestMachineRemoveAllLinkLayerDevicesSuccess(c *gc.C) {
526
s.assertNoDevicesOnMachine(c, s.machine)
527
s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "bar")
529
err := s.machine.RemoveAllLinkLayerDevices()
530
c.Assert(err, jc.ErrorIsNil)
531
s.assertNoDevicesOnMachine(c, s.machine)
534
func (s *linkLayerDevicesStateSuite) TestMachineRemoveAllLinkLayerDevicesNoErrorIfNoDevicesExist(c *gc.C) {
535
s.assertNoDevicesOnMachine(c, s.machine)
537
err := s.machine.RemoveAllLinkLayerDevices()
538
c.Assert(err, jc.ErrorIsNil)
541
func (s *linkLayerDevicesStateSuite) TestAddLinkLayerDevicesRollbackWithDuplicateProviderIDs(c *gc.C) {
542
parent := s.addNamedDevice(c, "parent")
543
insertingArgs := []state.LinkLayerDeviceArgs{{
545
Type: state.EthernetDevice,
546
ProviderID: "child1-id",
547
ParentName: parent.Name(),
550
Type: state.BridgeDevice,
551
ProviderID: "child2-id",
552
ParentName: parent.Name(),
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)
564
hooks := []jujutxn.TestHook{{
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)
572
assertThreeExistAndRemoveChildren("child1", "child2")
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)
585
assertThreeExistAndRemoveChildren("other-child1", "other-child2")
588
defer state.SetTestHooks(c, s.State, hooks...).Check()
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.
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
601
err := s.machine.AddLinkLayerDevices(childArgs)
602
c.Assert(err, jc.ErrorIsNil)
603
s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // both parent and child remain
606
func (s *linkLayerDevicesStateSuite) prepareAddLinkLayerDevicesWithStateChurn(c *gc.C) (state.LinkLayerDeviceArgs, jujutxn.TestHook) {
607
parent := s.addNamedDevice(c, "parent")
608
childArgs := state.LinkLayerDeviceArgs{
610
Type: state.EthernetDevice,
611
ParentName: parent.Name(),
614
churnHook := jujutxn.TestHook{
616
s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // just the parent
617
err := s.machine.AddLinkLayerDevices(childArgs)
618
c.Assert(err, jc.ErrorIsNil)
621
s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // parent and child
622
child, err := s.machine.LinkLayerDevice("child")
623
c.Assert(err, jc.ErrorIsNil)
625
c.Assert(err, jc.ErrorIsNil)
629
return childArgs, churnHook
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
637
err := s.machine.AddLinkLayerDevices(childArgs)
638
c.Assert(err, jc.ErrorIsNil)
639
s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // both parent and child remain
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
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
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{{
656
Type: state.LoopbackDevice,
659
Type: state.EthernetDevice,
662
Type: state.VLAN_8021QDevice,
665
Type: state.BondDevice,
667
hostDevices := s.addMultipleDevicesSucceedsAndCheckAllAdded(c, hostDevicesArgs)
668
hostMachineParentDeviceGlobalKeyPrefix := "m#0#d#"
669
s.addContainerMachine(c)
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{
678
Type: state.EthernetDevice,
679
ParentName: parentDeviceGlobalKey,
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)
688
s.assertNoDevicesOnMachine(c, s.containerMachine)
691
func (s *linkLayerDevicesStateSuite) addContainerMachine(c *gc.C) {
692
// Add a container machine with s.machine as its host.
693
containerTemplate := state.MachineTemplate{
695
Jobs: []state.MachineJob{state.JobHostUnits},
697
container, err := s.State.AddMachineInsideMachine(containerTemplate, s.machine.Id(), instance.LXC)
698
c.Assert(err, jc.ErrorIsNil)
699
s.containerMachine = container
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)
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)
715
func (s *linkLayerDevicesStateSuite) addParentBridgeDeviceWithContainerDevicesAsChildren(
718
childDevicesNamePrefix string,
720
) (parentDevice *state.LinkLayerDevice, childrenDevices []*state.LinkLayerDevice) {
721
parentArgs := state.LinkLayerDeviceArgs{
723
Type: state.BridgeDevice,
725
parentDevice = s.assertAddLinkLayerDevicesSucceedsAndResultMatchesArgs(c, parentArgs)
726
parentDeviceGlobalKey := "m#" + s.machine.Id() + "#d#" + parentName
728
childrenArgsTemplate := state.LinkLayerDeviceArgs{
729
Type: state.EthernetDevice,
730
ParentName: parentDeviceGlobalKey,
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)
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
745
func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveFailsWithExistingChildrenOnContainerMachine(c *gc.C) {
746
parent, children := s.addParentBridgeDeviceWithContainerDevicesAsChildren(c, "br-eth1", "eth", 2)
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)
753
err = children[0].Remove()
754
c.Assert(err, jc.ErrorIsNil)
756
err = parent.Remove()
757
c.Assert(err, gc.ErrorMatches, expectedErrorPrefix+"1 children")
758
c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError)
760
err = children[1].Remove()
761
c.Assert(err, jc.ErrorIsNil)
762
err = parent.Remove()
763
c.Assert(err, jc.ErrorIsNil)
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)
779
defer state.SetBeforeHooks(c, s.State, beforeHook).Check()
781
newChildArgs := state.LinkLayerDeviceArgs{
783
Type: state.EthernetDevice,
784
ParentName: children[0].ParentName(),
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)
791
func (s *linkLayerDevicesStateSuite) TestMachineRemoveAlsoRemoveAllLinkLayerDevices(c *gc.C) {
792
s.assertNoDevicesOnMachine(c, s.machine)
793
s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "bar")
795
err := s.machine.EnsureDead()
796
c.Assert(err, jc.ErrorIsNil)
797
err = s.machine.Remove()
798
c.Assert(err, jc.ErrorIsNil)
800
s.assertNoDevicesOnMachine(c, s.machine)