github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/linklayerdevices_test.go (about) 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 "strconv" 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/network" 17 "github.com/juju/juju/state" 18 ) 19 20 // linkLayerDevicesStateSuite contains white-box tests for link-layer network 21 // devices, which include access to mongo. 22 type linkLayerDevicesStateSuite struct { 23 ConnSuite 24 25 machine *state.Machine 26 containerMachine *state.Machine 27 28 otherState *state.State 29 otherStateMachine *state.Machine 30 } 31 32 var _ = gc.Suite(&linkLayerDevicesStateSuite{}) 33 34 func (s *linkLayerDevicesStateSuite) SetUpTest(c *gc.C) { 35 s.ConnSuite.SetUpTest(c) 36 37 var err error 38 s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) 39 c.Assert(err, jc.ErrorIsNil) 40 41 s.otherState = s.NewStateForModelNamed(c, "other-model") 42 s.otherStateMachine, err = s.otherState.AddMachine("quantal", state.JobHostUnits) 43 c.Assert(err, jc.ErrorIsNil) 44 } 45 46 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesNoArgs(c *gc.C) { 47 err := s.machine.SetLinkLayerDevices() // takes varargs, which includes none. 48 c.Assert(err, jc.ErrorIsNil) 49 } 50 51 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesEmptyArgs(c *gc.C) { 52 args := state.LinkLayerDeviceArgs{} 53 s.assertSetLinkLayerDevicesReturnsNotValidError(c, args, "empty Name not valid") 54 } 55 56 func (s *linkLayerDevicesStateSuite) assertSetLinkLayerDevicesReturnsNotValidError(c *gc.C, args state.LinkLayerDeviceArgs, errorCauseMatches string) { 57 err := s.assertSetLinkLayerDevicesFailsValidationForArgs(c, args, errorCauseMatches) 58 c.Assert(err, jc.Satisfies, errors.IsNotValid) 59 } 60 61 func (s *linkLayerDevicesStateSuite) assertSetLinkLayerDevicesFailsValidationForArgs(c *gc.C, args state.LinkLayerDeviceArgs, errorCauseMatches string) error { 62 expectedError := fmt.Sprintf("invalid device %q: %s", args.Name, errorCauseMatches) 63 return s.assertSetLinkLayerDevicesFailsForArgs(c, args, expectedError) 64 } 65 66 func (s *linkLayerDevicesStateSuite) assertSetLinkLayerDevicesFailsForArgs(c *gc.C, args state.LinkLayerDeviceArgs, errorCauseMatches string) error { 67 err := s.machine.SetLinkLayerDevices(args) 68 expectedError := fmt.Sprintf("cannot set 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) TestSetLinkLayerDevicesSameNameAndParentName(c *gc.C) { 74 args := state.LinkLayerDeviceArgs{ 75 Name: "foo", 76 ParentName: "foo", 77 } 78 s.assertSetLinkLayerDevicesReturnsNotValidError(c, args, `Name and ParentName must be different`) 79 } 80 81 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesInvalidType(c *gc.C) { 82 args := state.LinkLayerDeviceArgs{ 83 Name: "bar", 84 Type: "bad type", 85 } 86 s.assertSetLinkLayerDevicesReturnsNotValidError(c, args, `Type "bad type" not valid`) 87 } 88 89 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesParentNameAsInvalidGlobalKey(c *gc.C) { 90 args := state.LinkLayerDeviceArgs{ 91 Name: "eth0", 92 ParentName: "x#foo#y#bar", // contains the right amount of # but is invalid otherwise. 93 } 94 s.assertSetLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "x#foo#y#bar" format not valid`) 95 } 96 97 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesParentNameAsGlobalKeyFailsForNonContainerMachine(c *gc.C) { 98 args := state.LinkLayerDeviceArgs{ 99 Name: "eth0", 100 ParentName: "m#42#d#foo", // any non-container ID here will cause the same error. 101 } 102 s.assertSetLinkLayerDevicesReturnsNotValidError(c, args, `ParentName "m#42#d#foo" for non-container machine "0" not valid`) 103 } 104 105 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesParentNameAsGlobalKeyFailsForContainerOnDifferentHost(c *gc.C) { 106 args := state.LinkLayerDeviceArgs{ 107 Name: "eth0", 108 ParentName: "m#42#d#foo", // any ID other than s.containerMachine's parent ID here will cause the same error. 109 } 110 s.addContainerMachine(c) 111 err := s.containerMachine.SetLinkLayerDevices(args) 112 errorPrefix := fmt.Sprintf("cannot set link-layer devices to machine %q: invalid device %q: ", s.containerMachine.Id(), args.Name) 113 c.Assert(err, gc.ErrorMatches, errorPrefix+`ParentName "m#42#d#foo" on non-host machine "42" not valid`) 114 c.Assert(err, jc.Satisfies, errors.IsNotValid) 115 } 116 117 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesParentNameAsGlobalKeyFailsForContainerIfParentMissing(c *gc.C) { 118 args := state.LinkLayerDeviceArgs{ 119 Name: "eth0", 120 ParentName: "m#0#d#missing", 121 } 122 s.addContainerMachine(c) 123 err := s.containerMachine.SetLinkLayerDevices(args) 124 c.Assert(err, gc.ErrorMatches, `.*parent device "missing" on host machine "0" not found`) 125 c.Assert(err, jc.Satisfies, errors.IsNotFound) 126 } 127 128 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesInvalidMACAddress(c *gc.C) { 129 args := state.LinkLayerDeviceArgs{ 130 Name: "eth0", 131 Type: state.EthernetDevice, 132 MACAddress: "bad mac", 133 } 134 s.assertSetLinkLayerDevicesReturnsNotValidError(c, args, `MACAddress "bad mac" not valid`) 135 } 136 137 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWhenMachineNotAliveOrGone(c *gc.C) { 138 err := s.machine.EnsureDead() 139 c.Assert(err, jc.ErrorIsNil) 140 141 args := state.LinkLayerDeviceArgs{ 142 Name: "eth0", 143 Type: state.EthernetDevice, 144 } 145 s.assertSetLinkLayerDevicesFailsForArgs(c, args, "machine not found or not alive") 146 147 err = s.machine.Remove() 148 c.Assert(err, jc.ErrorIsNil) 149 150 s.assertSetLinkLayerDevicesFailsForArgs(c, args, "machine not found or not alive") 151 } 152 153 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWhenModelNotAlive(c *gc.C) { 154 otherModel, err := s.otherState.Model() 155 c.Assert(err, jc.ErrorIsNil) 156 err = otherModel.Destroy() 157 c.Assert(err, jc.ErrorIsNil) 158 159 args := state.LinkLayerDeviceArgs{ 160 Name: "eth0", 161 Type: state.EthernetDevice, 162 } 163 err = s.otherStateMachine.SetLinkLayerDevices(args) 164 expectedError := fmt.Sprintf( 165 "cannot set link-layer devices to machine %q: model %q is no longer alive", 166 s.otherStateMachine.Id(), otherModel.Name(), 167 ) 168 c.Assert(err, gc.ErrorMatches, expectedError) 169 } 170 171 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWithMissingParentSameMachine(c *gc.C) { 172 args := state.LinkLayerDeviceArgs{ 173 Name: "eth0", 174 Type: state.EthernetDevice, 175 ParentName: "br-eth0", 176 } 177 s.assertSetLinkLayerDevicesReturnsNotValidError(c, args, `ParentName not valid: device "br-eth0" on machine "0" not found`) 178 } 179 180 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesNoParentSuccess(c *gc.C) { 181 args := state.LinkLayerDeviceArgs{ 182 Name: "eth0.42", 183 MTU: 9000, 184 ProviderID: "eni-42", 185 Type: state.VLAN_8021QDevice, 186 MACAddress: "aa:bb:cc:dd:ee:f0", 187 IsAutoStart: true, 188 IsUp: true, 189 } 190 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args) 191 } 192 193 func (s *linkLayerDevicesStateSuite) assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs( 194 c *gc.C, 195 args state.LinkLayerDeviceArgs, 196 ) *state.LinkLayerDevice { 197 return s.assertMachineSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, s.machine, args, s.State.ModelUUID()) 198 } 199 200 func (s *linkLayerDevicesStateSuite) assertMachineSetLinkLayerDevicesSucceedsAndResultMatchesArgs( 201 c *gc.C, 202 machine *state.Machine, 203 args state.LinkLayerDeviceArgs, 204 modelUUID string, 205 ) *state.LinkLayerDevice { 206 err := machine.SetLinkLayerDevices(args) 207 c.Assert(err, jc.ErrorIsNil) 208 result, err := machine.LinkLayerDevice(args.Name) 209 c.Assert(err, jc.ErrorIsNil) 210 c.Assert(result, gc.NotNil) 211 212 s.checkSetDeviceMatchesArgs(c, result, args) 213 s.checkSetDeviceMatchesMachineIDAndModelUUID(c, result, s.machine.Id(), modelUUID) 214 return result 215 } 216 217 func (s *linkLayerDevicesStateSuite) checkSetDeviceMatchesArgs(c *gc.C, setDevice *state.LinkLayerDevice, args state.LinkLayerDeviceArgs) { 218 c.Check(setDevice.Name(), gc.Equals, args.Name) 219 c.Check(setDevice.MTU(), gc.Equals, args.MTU) 220 c.Check(setDevice.ProviderID(), gc.Equals, args.ProviderID) 221 c.Check(setDevice.Type(), gc.Equals, args.Type) 222 c.Check(setDevice.MACAddress(), gc.Equals, args.MACAddress) 223 c.Check(setDevice.IsAutoStart(), gc.Equals, args.IsAutoStart) 224 c.Check(setDevice.IsUp(), gc.Equals, args.IsUp) 225 c.Check(setDevice.ParentName(), gc.Equals, args.ParentName) 226 } 227 228 func (s *linkLayerDevicesStateSuite) checkSetDeviceMatchesMachineIDAndModelUUID(c *gc.C, setDevice *state.LinkLayerDevice, machineID, modelUUID string) { 229 globalKey := fmt.Sprintf("m#%s#d#%s", machineID, setDevice.Name()) 230 c.Check(setDevice.DocID(), gc.Equals, modelUUID+":"+globalKey) 231 c.Check(setDevice.MachineID(), gc.Equals, machineID) 232 } 233 234 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesNoProviderIDSuccess(c *gc.C) { 235 args := state.LinkLayerDeviceArgs{ 236 Name: "eno0", 237 Type: state.EthernetDevice, 238 } 239 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args) 240 } 241 242 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWithDuplicateProviderIDFailsInSameModel(c *gc.C) { 243 args1 := state.LinkLayerDeviceArgs{ 244 Name: "eth0.42", 245 Type: state.EthernetDevice, 246 ProviderID: "42", 247 } 248 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args1) 249 250 args2 := args1 251 args2.Name = "br-eth0" 252 err := s.assertSetLinkLayerDevicesFailsValidationForArgs(c, args2, `ProviderID\(s\) not unique: 42`) 253 c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError) 254 } 255 256 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWithDuplicateNameAndProviderIDSucceedsInDifferentModels(c *gc.C) { 257 args := state.LinkLayerDeviceArgs{ 258 Name: "eth0.42", 259 Type: state.EthernetDevice, 260 ProviderID: "42", 261 } 262 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args) 263 264 s.assertMachineSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, s.otherStateMachine, args, s.otherState.ModelUUID()) 265 } 266 267 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWithDuplicateNameAndProviderIDFailsInSameModel(c *gc.C) { 268 args := state.LinkLayerDeviceArgs{ 269 Name: "foo", 270 Type: state.EthernetDevice, 271 ProviderID: "42", 272 } 273 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args) 274 275 err := s.assertSetLinkLayerDevicesFailsValidationForArgs(c, args, `ProviderID\(s\) not unique: 42`) 276 c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError) 277 } 278 279 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesUpdatesProviderIDWhenNotSetOriginally(c *gc.C) { 280 args := state.LinkLayerDeviceArgs{ 281 Name: "foo", 282 Type: state.EthernetDevice, 283 } 284 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args) 285 286 args.ProviderID = "42" 287 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args) 288 } 289 290 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesDoesNotClearProviderIDOnceSet(c *gc.C) { 291 args := state.LinkLayerDeviceArgs{ 292 Name: "foo", 293 Type: state.EthernetDevice, 294 ProviderID: "42", 295 } 296 s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, args) 297 298 args.ProviderID = "" 299 err := s.machine.SetLinkLayerDevices(args) 300 c.Assert(err, jc.ErrorIsNil) 301 device, err := s.machine.LinkLayerDevice(args.Name) 302 c.Assert(err, jc.ErrorIsNil) 303 c.Assert(device.ProviderID(), gc.Equals, network.Id("42")) 304 } 305 306 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesMultipleArgsWithSameNameFails(c *gc.C) { 307 foo1 := state.LinkLayerDeviceArgs{ 308 Name: "foo", 309 Type: state.BridgeDevice, 310 } 311 foo2 := state.LinkLayerDeviceArgs{ 312 Name: "foo", 313 Type: state.EthernetDevice, 314 } 315 err := s.machine.SetLinkLayerDevices(foo1, foo2) 316 c.Assert(err, gc.ErrorMatches, `.*invalid device "foo": Name specified more than once`) 317 c.Assert(err, jc.Satisfies, errors.IsNotValid) 318 } 319 320 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesRefusesToAddParentAndChildrenInTheSameCall(c *gc.C) { 321 allArgs := []state.LinkLayerDeviceArgs{{ 322 Name: "child1", 323 Type: state.EthernetDevice, 324 ParentName: "parent1", 325 }, { 326 Name: "parent1", 327 Type: state.BridgeDevice, 328 }} 329 330 err := s.machine.SetLinkLayerDevices(allArgs...) 331 c.Assert(err, gc.ErrorMatches, `cannot set link-layer devices to machine "0": `+ 332 `invalid device "child1": `+ 333 `ParentName not valid: `+ 334 `device "parent1" on machine "0" not found`, 335 ) 336 c.Assert(err, jc.Satisfies, errors.IsNotValid) 337 } 338 339 func (s *linkLayerDevicesStateSuite) setMultipleDevicesSucceedsAndCheckAllAdded(c *gc.C, allArgs []state.LinkLayerDeviceArgs) []*state.LinkLayerDevice { 340 err := s.machine.SetLinkLayerDevices(allArgs...) 341 c.Assert(err, jc.ErrorIsNil) 342 343 var results []*state.LinkLayerDevice 344 machineID, modelUUID := s.machine.Id(), s.State.ModelUUID() 345 for _, args := range allArgs { 346 device, err := s.machine.LinkLayerDevice(args.Name) 347 c.Check(err, jc.ErrorIsNil) 348 s.checkSetDeviceMatchesArgs(c, device, args) 349 s.checkSetDeviceMatchesMachineIDAndModelUUID(c, device, machineID, modelUUID) 350 results = append(results, device) 351 } 352 return results 353 } 354 355 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesMultipleChildrenOfExistingParentSucceeds(c *gc.C) { 356 s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "child1", "child2") 357 } 358 359 func (s *linkLayerDevicesStateSuite) addNamedParentDeviceWithChildrenAndCheckAllAdded(c *gc.C, parentName string, childrenNames ...string) ( 360 parent *state.LinkLayerDevice, 361 children []*state.LinkLayerDevice, 362 ) { 363 parent = s.addNamedDevice(c, parentName) 364 childrenArgs := make([]state.LinkLayerDeviceArgs, len(childrenNames)) 365 for i, childName := range childrenNames { 366 childrenArgs[i] = state.LinkLayerDeviceArgs{ 367 Name: childName, 368 Type: state.EthernetDevice, 369 ParentName: parentName, 370 } 371 } 372 373 children = s.setMultipleDevicesSucceedsAndCheckAllAdded(c, childrenArgs) 374 return parent, children 375 } 376 377 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesMultipleChildrenOfExistingParentIdempotent(c *gc.C) { 378 s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "child1", "child2") 379 s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "child1", "child2") 380 } 381 382 func (s *linkLayerDevicesStateSuite) addSimpleDevice(c *gc.C) *state.LinkLayerDevice { 383 return s.addNamedDevice(c, "foo") 384 } 385 386 func (s *linkLayerDevicesStateSuite) addNamedDevice(c *gc.C, name string) *state.LinkLayerDevice { 387 args := state.LinkLayerDeviceArgs{ 388 Name: name, 389 Type: state.EthernetDevice, 390 } 391 err := s.machine.SetLinkLayerDevices(args) 392 c.Assert(err, jc.ErrorIsNil) 393 device, err := s.machine.LinkLayerDevice(name) 394 c.Assert(err, jc.ErrorIsNil) 395 return device 396 } 397 398 func (s *linkLayerDevicesStateSuite) TestMachineMethodReturnsNotFoundErrorWhenMissing(c *gc.C) { 399 device := s.addSimpleDevice(c) 400 401 err := s.machine.EnsureDead() 402 c.Assert(err, jc.ErrorIsNil) 403 err = s.machine.Remove() 404 c.Assert(err, jc.ErrorIsNil) 405 406 result, err := device.Machine() 407 c.Assert(err, gc.ErrorMatches, "machine 0 not found") 408 c.Assert(err, jc.Satisfies, errors.IsNotFound) 409 c.Assert(result, gc.IsNil) 410 } 411 412 func (s *linkLayerDevicesStateSuite) TestMachineMethodReturnsMachine(c *gc.C) { 413 device := s.addSimpleDevice(c) 414 415 result, err := device.Machine() 416 c.Assert(err, jc.ErrorIsNil) 417 c.Assert(result, jc.DeepEquals, s.machine) 418 } 419 420 func (s *linkLayerDevicesStateSuite) TestParentDeviceReturnsLinkLayerDevice(c *gc.C) { 421 parent, children := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "br-eth0", "eth0") 422 423 child := children[0] 424 parentCopy, err := child.ParentDevice() 425 c.Assert(err, jc.ErrorIsNil) 426 c.Assert(parentCopy, jc.DeepEquals, parent) 427 } 428 429 func (s *linkLayerDevicesStateSuite) TestMachineLinkLayerDeviceReturnsNotFoundErrorWhenMissing(c *gc.C) { 430 result, err := s.machine.LinkLayerDevice("missing") 431 c.Assert(result, gc.IsNil) 432 c.Assert(err, jc.Satisfies, errors.IsNotFound) 433 c.Assert(err, gc.ErrorMatches, `device "missing" on machine "0" not found`) 434 } 435 436 func (s *linkLayerDevicesStateSuite) TestMachineLinkLayerDeviceReturnsLinkLayerDevice(c *gc.C) { 437 existingDevice := s.addSimpleDevice(c) 438 439 result, err := s.machine.LinkLayerDevice(existingDevice.Name()) 440 c.Assert(err, jc.ErrorIsNil) 441 c.Assert(result, jc.DeepEquals, existingDevice) 442 } 443 444 func (s *linkLayerDevicesStateSuite) TestMachineAllLinkLayerDevices(c *gc.C) { 445 s.assertNoDevicesOnMachine(c, s.machine) 446 topParent, secondLevelParents := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "br-bond0", "bond0") 447 secondLevelParent := secondLevelParents[0] 448 449 secondLevelChildrenArgs := []state.LinkLayerDeviceArgs{{ 450 Name: "eth0", 451 Type: state.EthernetDevice, 452 ParentName: secondLevelParent.Name(), 453 }, { 454 Name: "eth1", 455 Type: state.EthernetDevice, 456 ParentName: secondLevelParent.Name(), 457 }} 458 s.setMultipleDevicesSucceedsAndCheckAllAdded(c, secondLevelChildrenArgs) 459 460 results, err := s.machine.AllLinkLayerDevices() 461 c.Assert(err, jc.ErrorIsNil) 462 c.Assert(results, gc.HasLen, 4) 463 for _, result := range results { 464 c.Check(result, gc.NotNil) 465 c.Check(result.MachineID(), gc.Equals, s.machine.Id()) 466 c.Check(result.Name(), gc.Matches, `(br-bond0|bond0|eth0|eth1)`) 467 if result.Name() == topParent.Name() { 468 c.Check(result.ParentName(), gc.Equals, "") 469 continue 470 } 471 c.Check(result.ParentName(), gc.Matches, `(br-bond0|bond0)`) 472 } 473 } 474 475 func (s *linkLayerDevicesStateSuite) assertNoDevicesOnMachine(c *gc.C, machine *state.Machine) { 476 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, machine, 0) 477 } 478 479 func (s *linkLayerDevicesStateSuite) assertAllLinkLayerDevicesOnMachineMatchCount(c *gc.C, machine *state.Machine, expectedCount int) { 480 results, err := machine.AllLinkLayerDevices() 481 c.Assert(err, jc.ErrorIsNil) 482 c.Assert(results, gc.HasLen, expectedCount) 483 } 484 485 func (s *linkLayerDevicesStateSuite) TestMachineAllLinkLayerDevicesOnlyReturnsSameModelDevices(c *gc.C) { 486 s.assertNoDevicesOnMachine(c, s.machine) 487 s.assertNoDevicesOnMachine(c, s.otherStateMachine) 488 489 s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "foo.42") 490 491 results, err := s.machine.AllLinkLayerDevices() 492 c.Assert(err, jc.ErrorIsNil) 493 c.Assert(results, gc.HasLen, 2) 494 c.Assert(results[0].Name(), gc.Equals, "foo") 495 c.Assert(results[1].Name(), gc.Equals, "foo.42") 496 497 s.assertNoDevicesOnMachine(c, s.otherStateMachine) 498 } 499 500 func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveFailsWithExistingChildren(c *gc.C) { 501 parent, _ := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "one-child", "another-child") 502 503 err := parent.Remove() 504 expectedError := fmt.Sprintf( 505 "cannot remove %s: parent device %q has 2 children", 506 parent, parent.Name(), 507 ) 508 c.Assert(err, gc.ErrorMatches, expectedError) 509 c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError) 510 } 511 512 func (s *linkLayerDevicesStateSuite) TestLinkLayerParentRemoveOKAfterChangingChildrensToNewParent(c *gc.C) { 513 originalParent, children := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "one-child", "another-child") 514 newParent := s.addNamedDevice(c, "new-parent") 515 516 updateArgs := []state.LinkLayerDeviceArgs{{ 517 Name: children[0].Name(), 518 Type: children[0].Type(), 519 ParentName: newParent.Name(), 520 }, { 521 Name: children[1].Name(), 522 Type: children[1].Type(), 523 ParentName: newParent.Name(), 524 }} 525 err := s.machine.SetLinkLayerDevices(updateArgs...) 526 c.Assert(err, jc.ErrorIsNil) 527 528 err = originalParent.Remove() 529 c.Assert(err, jc.ErrorIsNil) 530 531 err = newParent.Remove() 532 expectedError := fmt.Sprintf( 533 "cannot remove %s: parent device %q has 2 children", 534 newParent, newParent.Name(), 535 ) 536 c.Assert(err, gc.ErrorMatches, expectedError) 537 c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError) 538 } 539 540 func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveSuccess(c *gc.C) { 541 existingDevice := s.addSimpleDevice(c) 542 543 s.removeDeviceAndAssertSuccess(c, existingDevice) 544 s.assertNoDevicesOnMachine(c, s.machine) 545 } 546 547 func (s *linkLayerDevicesStateSuite) removeDeviceAndAssertSuccess(c *gc.C, givenDevice *state.LinkLayerDevice) { 548 err := givenDevice.Remove() 549 c.Assert(err, jc.ErrorIsNil) 550 } 551 552 func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveTwiceStillSucceeds(c *gc.C) { 553 existingDevice := s.addSimpleDevice(c) 554 555 s.removeDeviceAndAssertSuccess(c, existingDevice) 556 s.removeDeviceAndAssertSuccess(c, existingDevice) 557 s.assertNoDevicesOnMachine(c, s.machine) 558 } 559 560 func (s *linkLayerDevicesStateSuite) TestMachineRemoveAllLinkLayerDevicesSuccess(c *gc.C) { 561 s.assertNoDevicesOnMachine(c, s.machine) 562 s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "bar") 563 564 err := s.machine.RemoveAllLinkLayerDevices() 565 c.Assert(err, jc.ErrorIsNil) 566 s.assertNoDevicesOnMachine(c, s.machine) 567 } 568 569 func (s *linkLayerDevicesStateSuite) TestMachineRemoveAllLinkLayerDevicesNoErrorIfNoDevicesExist(c *gc.C) { 570 s.assertNoDevicesOnMachine(c, s.machine) 571 572 err := s.machine.RemoveAllLinkLayerDevices() 573 c.Assert(err, jc.ErrorIsNil) 574 } 575 576 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWithLightStateChurn(c *gc.C) { 577 childArgs, churnHook := s.prepareSetLinkLayerDevicesWithStateChurn(c) 578 defer state.SetTestHooks(c, s.State, churnHook).Check() 579 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // parent only 580 581 err := s.machine.SetLinkLayerDevices(childArgs) 582 c.Assert(err, jc.ErrorIsNil) 583 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // both parent and child remain 584 } 585 586 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesUpdatesExistingDocs(c *gc.C) { 587 s.assertNoDevicesOnMachine(c, s.machine) 588 parent, children := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "bar") 589 590 // Change everything that's possible to change for both existing devices, 591 // except for ProviderID and ParentName (tested separately). 592 updateArgs := []state.LinkLayerDeviceArgs{{ 593 Name: parent.Name(), 594 Type: state.BondDevice, 595 MTU: 1234, 596 MACAddress: "aa:bb:cc:dd:ee:f0", 597 IsAutoStart: true, 598 IsUp: true, 599 }, { 600 Name: children[0].Name(), 601 Type: state.VLAN_8021QDevice, 602 MTU: 4321, 603 MACAddress: "aa:bb:cc:dd:ee:f1", 604 IsAutoStart: true, 605 IsUp: true, 606 ParentName: parent.Name(), 607 }} 608 err := s.machine.SetLinkLayerDevices(updateArgs...) 609 c.Assert(err, jc.ErrorIsNil) 610 611 allDevices, err := s.machine.AllLinkLayerDevices() 612 c.Assert(err, jc.ErrorIsNil) 613 c.Assert(allDevices, gc.HasLen, 2) 614 615 for _, device := range allDevices { 616 if device.Name() == parent.Name() { 617 s.checkSetDeviceMatchesArgs(c, device, updateArgs[0]) 618 } else { 619 s.checkSetDeviceMatchesArgs(c, device, updateArgs[1]) 620 } 621 s.checkSetDeviceMatchesMachineIDAndModelUUID(c, device, s.machine.Id(), s.State.ModelUUID()) 622 } 623 } 624 625 func (s *linkLayerDevicesStateSuite) prepareSetLinkLayerDevicesWithStateChurn(c *gc.C) (state.LinkLayerDeviceArgs, jujutxn.TestHook) { 626 parent := s.addNamedDevice(c, "parent") 627 childArgs := state.LinkLayerDeviceArgs{ 628 Name: "child", 629 Type: state.EthernetDevice, 630 ParentName: parent.Name(), 631 } 632 633 churnHook := jujutxn.TestHook{ 634 Before: func() { 635 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // just the parent 636 err := s.machine.SetLinkLayerDevices(childArgs) 637 c.Assert(err, jc.ErrorIsNil) 638 }, 639 After: func() { 640 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // parent and child 641 child, err := s.machine.LinkLayerDevice("child") 642 c.Assert(err, jc.ErrorIsNil) 643 err = child.Remove() 644 c.Assert(err, jc.ErrorIsNil) 645 }, 646 } 647 648 return childArgs, churnHook 649 } 650 651 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWithModerateStateChurn(c *gc.C) { 652 childArgs, churnHook := s.prepareSetLinkLayerDevicesWithStateChurn(c) 653 defer state.SetTestHooks(c, s.State, churnHook, churnHook).Check() 654 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // parent only 655 656 err := s.machine.SetLinkLayerDevices(childArgs) 657 c.Assert(err, jc.ErrorIsNil) 658 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 2) // both parent and child remain 659 } 660 661 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesWithTooMuchStateChurn(c *gc.C) { 662 childArgs, churnHook := s.prepareSetLinkLayerDevicesWithStateChurn(c) 663 defer state.SetTestHooks(c, s.State, churnHook, churnHook, churnHook).Check() 664 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // parent only 665 666 err := s.machine.SetLinkLayerDevices(childArgs) 667 c.Assert(errors.Cause(err), gc.Equals, jujutxn.ErrExcessiveContention) 668 s.assertAllLinkLayerDevicesOnMachineMatchCount(c, s.machine, 1) // only the parent remains 669 } 670 671 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesRefusesToAddContainerChildDeviceWithNonBridgeParent(c *gc.C) { 672 // Add one device of every type to the host machine, except a BridgeDevice. 673 hostDevicesArgs := []state.LinkLayerDeviceArgs{{ 674 Name: "loopback", 675 Type: state.LoopbackDevice, 676 }, { 677 Name: "ethernet", 678 Type: state.EthernetDevice, 679 }, { 680 Name: "vlan", 681 Type: state.VLAN_8021QDevice, 682 }, { 683 Name: "bond", 684 Type: state.BondDevice, 685 }} 686 hostDevices := s.setMultipleDevicesSucceedsAndCheckAllAdded(c, hostDevicesArgs) 687 hostMachineParentDeviceGlobalKeyPrefix := "m#0#d#" 688 s.addContainerMachine(c) 689 690 // Now try setting an EthernetDevice on the container specifying each of the 691 // hostDevices as parent and expect none of them to succeed, as none of the 692 // hostDevices is a BridgeDevice. 693 for _, hostDevice := range hostDevices { 694 parentDeviceGlobalKey := hostMachineParentDeviceGlobalKeyPrefix + hostDevice.Name() 695 containerDeviceArgs := state.LinkLayerDeviceArgs{ 696 Name: "eth0", 697 Type: state.EthernetDevice, 698 ParentName: parentDeviceGlobalKey, 699 } 700 err := s.containerMachine.SetLinkLayerDevices(containerDeviceArgs) 701 expectedError := `cannot set .* to machine "0/lxc/0": ` + 702 `invalid device "eth0": ` + 703 `parent device ".*" on host machine "0" must be of type "bridge", not type ".*"` 704 c.Check(err, gc.ErrorMatches, expectedError) 705 c.Check(err, jc.Satisfies, errors.IsNotValid) 706 } 707 s.assertNoDevicesOnMachine(c, s.containerMachine) 708 } 709 710 func (s *linkLayerDevicesStateSuite) addContainerMachine(c *gc.C) { 711 // Add a container machine with s.machine as its host. 712 containerTemplate := state.MachineTemplate{ 713 Series: "quantal", 714 Jobs: []state.MachineJob{state.JobHostUnits}, 715 } 716 container, err := s.State.AddMachineInsideMachine(containerTemplate, s.machine.Id(), instance.LXC) 717 c.Assert(err, jc.ErrorIsNil) 718 s.containerMachine = container 719 } 720 721 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesAllowsParentBridgeDeviceForContainerDevice(c *gc.C) { 722 parentDevice, _ := s.addParentBridgeDeviceWithContainerDevicesAsChildren(c, "br-eth1.250", "eth", 1) 723 childDevice, err := s.containerMachine.LinkLayerDevice("eth0") 724 c.Assert(err, jc.ErrorIsNil) 725 726 c.Check(childDevice.Name(), gc.Equals, "eth0") 727 c.Check(childDevice.ParentName(), gc.Equals, "m#0#d#br-eth1.250") 728 c.Check(childDevice.MachineID(), gc.Equals, s.containerMachine.Id()) 729 parentOfChildDevice, err := childDevice.ParentDevice() 730 c.Assert(err, jc.ErrorIsNil) 731 c.Check(parentOfChildDevice, jc.DeepEquals, parentDevice) 732 } 733 734 func (s *linkLayerDevicesStateSuite) addParentBridgeDeviceWithContainerDevicesAsChildren( 735 c *gc.C, 736 parentName string, 737 childDevicesNamePrefix string, 738 numChildren int, 739 ) (parentDevice *state.LinkLayerDevice, childrenDevices []*state.LinkLayerDevice) { 740 parentArgs := state.LinkLayerDeviceArgs{ 741 Name: parentName, 742 Type: state.BridgeDevice, 743 } 744 parentDevice = s.assertSetLinkLayerDevicesSucceedsAndResultMatchesArgs(c, parentArgs) 745 parentDeviceGlobalKey := "m#" + s.machine.Id() + "#d#" + parentName 746 747 childrenArgsTemplate := state.LinkLayerDeviceArgs{ 748 Type: state.EthernetDevice, 749 ParentName: parentDeviceGlobalKey, 750 } 751 childrenArgs := make([]state.LinkLayerDeviceArgs, numChildren) 752 for i := 0; i < numChildren; i++ { 753 childrenArgs[i] = childrenArgsTemplate 754 childrenArgs[i].Name = fmt.Sprintf("%s%d", childDevicesNamePrefix, i) 755 } 756 s.addContainerMachine(c) 757 err := s.containerMachine.SetLinkLayerDevices(childrenArgs...) 758 c.Assert(err, jc.ErrorIsNil) 759 childrenDevices, err = s.containerMachine.AllLinkLayerDevices() 760 c.Assert(err, jc.ErrorIsNil) 761 return parentDevice, childrenDevices 762 } 763 764 func (s *linkLayerDevicesStateSuite) TestLinkLayerDeviceRemoveFailsWithExistingChildrenOnContainerMachine(c *gc.C) { 765 parent, children := s.addParentBridgeDeviceWithContainerDevicesAsChildren(c, "br-eth1", "eth", 2) 766 767 err := parent.Remove() 768 expectedErrorPrefix := fmt.Sprintf("cannot remove %s: parent device %q has ", parent, parent.Name()) 769 c.Assert(err, gc.ErrorMatches, expectedErrorPrefix+"2 children") 770 c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError) 771 772 err = children[0].Remove() 773 c.Assert(err, jc.ErrorIsNil) 774 775 err = parent.Remove() 776 c.Assert(err, gc.ErrorMatches, expectedErrorPrefix+"1 children") 777 c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError) 778 779 err = children[1].Remove() 780 c.Assert(err, jc.ErrorIsNil) 781 err = parent.Remove() 782 c.Assert(err, jc.ErrorIsNil) 783 } 784 785 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesUpdatesBothExistingAndNewParents(c *gc.C) { 786 parent1, children1 := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent1", "child1", "child2") 787 parent2, children2 := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent2", "child3", "child4") 788 789 // Swap the parents of all children. 790 updateArgs := make([]state.LinkLayerDeviceArgs, 0, len(children1)+len(children2)) 791 for _, child := range children1 { 792 updateArgs = append(updateArgs, state.LinkLayerDeviceArgs{ 793 Name: child.Name(), 794 Type: child.Type(), 795 ParentName: parent2.Name(), 796 }) 797 } 798 for _, child := range children2 { 799 updateArgs = append(updateArgs, state.LinkLayerDeviceArgs{ 800 Name: child.Name(), 801 Type: child.Type(), 802 ParentName: parent1.Name(), 803 }) 804 } 805 err := s.machine.SetLinkLayerDevices(updateArgs...) 806 c.Assert(err, jc.ErrorIsNil) 807 808 allDevices, err := s.machine.AllLinkLayerDevices() 809 c.Assert(err, jc.ErrorIsNil) 810 c.Assert(allDevices, gc.HasLen, len(updateArgs)+2) // 4 children updated and 2 parents unchanged. 811 812 for _, device := range allDevices { 813 switch device.Name() { 814 case children1[0].Name(), children1[1].Name(): 815 c.Check(device.ParentName(), gc.Equals, parent2.Name()) 816 case children2[0].Name(), children2[1].Name(): 817 c.Check(device.ParentName(), gc.Equals, parent1.Name()) 818 } 819 } 820 } 821 822 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesUpdatesParentWhenNotSet(c *gc.C) { 823 parent := s.addNamedDevice(c, "parent") 824 child := s.addNamedDevice(c, "child") 825 826 updateArgs := state.LinkLayerDeviceArgs{ 827 Name: child.Name(), 828 Type: child.Type(), 829 ParentName: parent.Name(), // make "child" a child of "parent" 830 } 831 err := s.machine.SetLinkLayerDevices(updateArgs) 832 c.Assert(err, jc.ErrorIsNil) 833 834 err = parent.Remove() 835 c.Assert(err, gc.ErrorMatches, 836 `cannot remove ethernet device "parent" on machine "0": parent device "parent" has 1 children`, 837 ) 838 c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError) 839 } 840 841 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesUpdatesParentWhenSet(c *gc.C) { 842 parent, children := s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "parent", "child") 843 err := parent.Remove() 844 c.Assert(err, jc.Satisfies, state.IsParentDeviceHasChildrenError) 845 846 updateArgs := state.LinkLayerDeviceArgs{ 847 Name: children[0].Name(), 848 Type: children[0].Type(), 849 // make "child" no longer a child of "parent" 850 } 851 err = s.machine.SetLinkLayerDevices(updateArgs) 852 c.Assert(err, jc.ErrorIsNil) 853 854 err = parent.Remove() 855 c.Assert(err, jc.ErrorIsNil) 856 } 857 858 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesToContainerWhenContainerDeadBeforehand(c *gc.C) { 859 beforeHook := func() { 860 // Make the container Dead but keep it around. 861 err := s.containerMachine.EnsureDead() 862 c.Assert(err, jc.ErrorIsNil) 863 } 864 865 s.assertSetLinkLayerDevicesToContainerFailsWithBeforeHook(c, beforeHook, `.*machine not found or not alive`) 866 } 867 868 func (s *linkLayerDevicesStateSuite) assertSetLinkLayerDevicesToContainerFailsWithBeforeHook(c *gc.C, beforeHook func(), expectedError string) { 869 _, children := s.addParentBridgeDeviceWithContainerDevicesAsChildren(c, "br-eth1", "eth", 1) 870 defer state.SetBeforeHooks(c, s.State, beforeHook).Check() 871 872 newChildArgs := state.LinkLayerDeviceArgs{ 873 Name: "eth1", 874 Type: state.EthernetDevice, 875 ParentName: children[0].ParentName(), 876 } 877 err := s.containerMachine.SetLinkLayerDevices(newChildArgs) 878 c.Assert(err, gc.ErrorMatches, expectedError) 879 } 880 881 func (s *linkLayerDevicesStateSuite) TestSetLinkLayerDevicesToContainerWhenContainerAndHostRemovedBeforehand(c *gc.C) { 882 beforeHook := func() { 883 // Remove both container and host machines. 884 err := s.containerMachine.EnsureDead() 885 c.Assert(err, jc.ErrorIsNil) 886 err = s.containerMachine.Remove() 887 c.Assert(err, jc.ErrorIsNil) 888 err = s.machine.EnsureDead() 889 c.Assert(err, jc.ErrorIsNil) 890 err = s.machine.Remove() 891 c.Assert(err, jc.ErrorIsNil) 892 } 893 894 s.assertSetLinkLayerDevicesToContainerFailsWithBeforeHook(c, beforeHook, 895 `.*host machine "0" of parent device "br-eth1" not found or not alive`, 896 ) 897 } 898 899 func (s *linkLayerDevicesStateSuite) TestMachineRemoveAlsoRemoveAllLinkLayerDevices(c *gc.C) { 900 s.assertNoDevicesOnMachine(c, s.machine) 901 s.addNamedParentDeviceWithChildrenAndCheckAllAdded(c, "foo", "bar") 902 903 err := s.machine.EnsureDead() 904 c.Assert(err, jc.ErrorIsNil) 905 err = s.machine.Remove() 906 c.Assert(err, jc.ErrorIsNil) 907 908 s.assertNoDevicesOnMachine(c, s.machine) 909 } 910 911 func (s *linkLayerDevicesStateSuite) TestMachineSetParentLinkLayerDevicesBeforeTheirChildrenUnchangedProviderIDsOK(c *gc.C) { 912 s.testMachineSetParentLinkLayerDevicesBeforeTheirChildren(c) 913 } 914 915 func (s *linkLayerDevicesStateSuite) TestMachineSetParentLinkLayerDevicesBeforeTheirChildrenIdempotent(c *gc.C) { 916 s.testMachineSetParentLinkLayerDevicesBeforeTheirChildren(c) 917 s.testMachineSetParentLinkLayerDevicesBeforeTheirChildren(c) 918 } 919 920 var nestedDevicesArgs = []state.LinkLayerDeviceArgs{{ 921 Name: "lo", 922 Type: state.LoopbackDevice, 923 }, { 924 Name: "br-bond0", 925 Type: state.BridgeDevice, 926 }, { 927 Name: "br-bond0.12", 928 Type: state.BridgeDevice, 929 ParentName: "br-bond0", 930 }, { 931 Name: "br-bond0.34", 932 Type: state.BridgeDevice, 933 ParentName: "br-bond0", 934 }, { 935 Name: "bond0", 936 Type: state.BondDevice, 937 ParentName: "br-bond0", 938 ProviderID: "100", 939 }, { 940 Name: "bond0.12", 941 Type: state.VLAN_8021QDevice, 942 ParentName: "bond0", 943 ProviderID: "101", 944 }, { 945 Name: "bond0.34", 946 Type: state.VLAN_8021QDevice, 947 ParentName: "bond0", 948 ProviderID: "102", 949 }, { 950 Name: "eth0", 951 Type: state.EthernetDevice, 952 ParentName: "bond0", 953 ProviderID: "103", 954 }, { 955 Name: "eth1", 956 Type: state.EthernetDevice, 957 ParentName: "bond0", 958 ProviderID: "104", 959 }} 960 961 func (s *linkLayerDevicesStateSuite) testMachineSetParentLinkLayerDevicesBeforeTheirChildren(c *gc.C) { 962 err := s.machine.SetParentLinkLayerDevicesBeforeTheirChildren(nestedDevicesArgs) 963 c.Assert(err, jc.ErrorIsNil) 964 allDevices, err := s.machine.AllLinkLayerDevices() 965 c.Assert(err, jc.ErrorIsNil) 966 c.Assert(allDevices, gc.HasLen, len(nestedDevicesArgs)) 967 for _, device := range allDevices { 968 if device.Type() != state.LoopbackDevice && device.Type() != state.BridgeDevice { 969 c.Check(device.ProviderID(), gc.Not(gc.Equals), network.Id("")) 970 } 971 } 972 } 973 974 func (s *linkLayerDevicesStateSuite) TestSetContainerLinkLayerDevices(c *gc.C) { 975 err := s.machine.SetParentLinkLayerDevicesBeforeTheirChildren(nestedDevicesArgs) 976 c.Assert(err, jc.ErrorIsNil) 977 s.addContainerMachine(c) 978 s.assertNoDevicesOnMachine(c, s.containerMachine) 979 980 err = s.machine.SetContainerLinkLayerDevices(s.containerMachine) 981 c.Assert(err, jc.ErrorIsNil) 982 983 containerDevices, err := s.containerMachine.AllLinkLayerDevices() 984 c.Assert(err, jc.ErrorIsNil) 985 c.Assert(containerDevices, gc.HasLen, 3) 986 987 for i, containerDevice := range containerDevices { 988 c.Check(containerDevice.Name(), gc.Matches, "eth"+strconv.Itoa(i)) 989 c.Check(containerDevice.Type(), gc.Equals, state.EthernetDevice) 990 c.Check(containerDevice.MTU(), gc.Equals, uint(0)) // inherited from the parent device. 991 c.Check(containerDevice.MACAddress(), gc.Matches, "00:16:3e(:[0-9a-f]{2}){3}") 992 c.Check(containerDevice.IsUp(), jc.IsTrue) 993 c.Check(containerDevice.IsAutoStart(), jc.IsTrue) 994 c.Check(containerDevice.ParentName(), gc.Matches, `m#0#d#br-bond0(|\.12|\.34)`) 995 } 996 }