github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/ipaddresses_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 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/network" 14 "github.com/juju/juju/state" 15 ) 16 17 // ipAddressesStateSuite contains white-box tests for IP addresses of link-layer 18 // devices, which include access to mongo. 19 type ipAddressesStateSuite struct { 20 ConnSuite 21 22 machine *state.Machine 23 24 otherState *state.State 25 otherStateMachine *state.Machine 26 } 27 28 var _ = gc.Suite(&ipAddressesStateSuite{}) 29 30 func (s *ipAddressesStateSuite) SetUpTest(c *gc.C) { 31 s.ConnSuite.SetUpTest(c) 32 33 var err error 34 s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) 35 c.Assert(err, jc.ErrorIsNil) 36 37 s.otherState = s.NewStateForModelNamed(c, "other-model") 38 s.otherStateMachine, err = s.otherState.AddMachine("quantal", state.JobHostUnits) 39 c.Assert(err, jc.ErrorIsNil) 40 41 // Add the few subnets used by the tests into both models. 42 subnetInfos := []state.SubnetInfo{{ 43 CIDR: "0.1.2.0/24", 44 }, { 45 CIDR: "fc00::/64", 46 }, { 47 CIDR: "10.20.0.0/16", 48 }} 49 for _, info := range subnetInfos { 50 _, err = s.State.AddSubnet(info) 51 c.Check(err, jc.ErrorIsNil) 52 _, err = s.otherState.AddSubnet(info) 53 c.Check(err, jc.ErrorIsNil) 54 } 55 } 56 57 func (s *ipAddressesStateSuite) TestMachineMethodReturnsMachine(c *gc.C) { 58 _, addresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 59 60 result, err := addresses[0].Machine() 61 c.Assert(err, jc.ErrorIsNil) 62 c.Assert(result, jc.DeepEquals, s.machine) 63 } 64 65 func (s *ipAddressesStateSuite) addNamedDeviceWithAddresses(c *gc.C, name string, addresses ...string) (*state.LinkLayerDevice, []*state.Address) { 66 device := s.addNamedDevice(c, name) 67 68 addressesArgs := make([]state.LinkLayerDeviceAddress, len(addresses)) 69 for i, address := range addresses { 70 addressesArgs[i] = state.LinkLayerDeviceAddress{ 71 DeviceName: name, 72 ConfigMethod: state.StaticAddress, 73 CIDRAddress: address, 74 } 75 } 76 err := s.machine.SetDevicesAddresses(addressesArgs...) 77 c.Assert(err, jc.ErrorIsNil) 78 deviceAddresses, err := device.Addresses() 79 c.Assert(err, jc.ErrorIsNil) 80 c.Assert(deviceAddresses, gc.HasLen, len(addresses)) 81 return device, deviceAddresses 82 } 83 84 func (s *ipAddressesStateSuite) addNamedDevice(c *gc.C, name string) *state.LinkLayerDevice { 85 return s.addNamedDeviceForMachine(c, name, s.machine) 86 } 87 88 func (s *ipAddressesStateSuite) addNamedDeviceForMachine(c *gc.C, name string, machine *state.Machine) *state.LinkLayerDevice { 89 deviceArgs := state.LinkLayerDeviceArgs{ 90 Name: name, 91 Type: state.EthernetDevice, 92 } 93 err := machine.SetLinkLayerDevices(deviceArgs) 94 c.Assert(err, jc.ErrorIsNil) 95 device, err := machine.LinkLayerDevice(name) 96 c.Assert(err, jc.ErrorIsNil) 97 return device 98 } 99 100 func (s *ipAddressesStateSuite) TestMachineMethodReturnsNotFoundErrorWhenMissing(c *gc.C) { 101 _, addresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 102 s.ensureMachineDeadAndRemove(c, s.machine) 103 104 result, err := addresses[0].Machine() 105 c.Assert(err, gc.ErrorMatches, "machine 0 not found") 106 c.Assert(err, jc.Satisfies, errors.IsNotFound) 107 c.Assert(result, gc.IsNil) 108 } 109 110 func (s *ipAddressesStateSuite) ensureMachineDeadAndRemove(c *gc.C, machine *state.Machine) { 111 s.ensureEntityDeadAndRemoved(c, machine) 112 } 113 114 type ensureDeaderRemover interface { 115 state.EnsureDeader 116 state.Remover 117 } 118 119 func (s *ipAddressesStateSuite) ensureEntityDeadAndRemoved(c *gc.C, entity ensureDeaderRemover) { 120 err := entity.EnsureDead() 121 c.Assert(err, jc.ErrorIsNil) 122 err = entity.Remove() 123 c.Assert(err, jc.ErrorIsNil) 124 } 125 126 func (s *ipAddressesStateSuite) TestDeviceMethodReturnsLinkLayerDevice(c *gc.C) { 127 addedDevice, addresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 128 129 returnedDevice, err := addresses[0].Device() 130 c.Assert(err, jc.ErrorIsNil) 131 c.Assert(returnedDevice, jc.DeepEquals, addedDevice) 132 } 133 134 func (s *ipAddressesStateSuite) TestDeviceMethodReturnsNotFoundErrorWhenMissing(c *gc.C) { 135 device, addresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 136 err := device.Remove() 137 c.Assert(err, jc.ErrorIsNil) 138 139 result, err := addresses[0].Device() 140 c.Assert(result, gc.IsNil) 141 c.Assert(err, jc.Satisfies, errors.IsNotFound) 142 c.Assert(err, gc.ErrorMatches, `device "eth0" on machine "0" not found`) 143 } 144 145 func (s *ipAddressesStateSuite) TestSubnetMethodReturnsSubnet(c *gc.C) { 146 _, addresses := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.30.41/16") 147 148 result, err := addresses[0].Subnet() 149 c.Assert(err, jc.ErrorIsNil) 150 c.Assert(result.CIDR(), gc.Equals, "10.20.0.0/16") 151 } 152 153 func (s *ipAddressesStateSuite) TestSubnetMethodReturnsNotFoundErrorWhenMissing(c *gc.C) { 154 _, addresses := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.30.41/16") 155 subnet, err := s.State.Subnet("10.20.0.0/16") 156 c.Assert(err, jc.ErrorIsNil) 157 s.ensureEntityDeadAndRemoved(c, subnet) 158 159 result, err := addresses[0].Subnet() 160 c.Assert(err, jc.Satisfies, errors.IsNotFound) 161 c.Assert(err, gc.ErrorMatches, `subnet "10.20.0.0/16" not found`) 162 c.Assert(result, gc.IsNil) 163 } 164 165 func (s *ipAddressesStateSuite) TestSubnetMethodReturnsNotFoundErrorWithUnknownOrLocalSubnet(c *gc.C) { 166 cidrs := []string{"127.0.0.0/8", "::1/128", "8.8.0.0/16"} 167 _, addresses := s.addNamedDeviceWithAddresses(c, "eth0", cidrs...) 168 169 for i, address := range addresses { 170 result, err := address.Subnet() 171 c.Check(result, gc.IsNil) 172 c.Check(err, jc.Satisfies, errors.IsNotFound) 173 expectedError := fmt.Sprintf("subnet %q not found", cidrs[i]) 174 c.Check(err, gc.ErrorMatches, expectedError) 175 } 176 } 177 178 func (s *ipAddressesStateSuite) TestRemoveSuccess(c *gc.C) { 179 _, existingAddresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 180 181 s.removeAddressAndAssertSuccess(c, existingAddresses[0]) 182 s.assertNoAddressesOnMachine(c, s.machine) 183 } 184 185 func (s *ipAddressesStateSuite) removeAddressAndAssertSuccess(c *gc.C, givenAddress *state.Address) { 186 err := givenAddress.Remove() 187 c.Assert(err, jc.ErrorIsNil) 188 } 189 190 func (s *ipAddressesStateSuite) assertNoAddressesOnMachine(c *gc.C, machine *state.Machine) { 191 s.assertAllAddressesOnMachineMatchCount(c, machine, 0) 192 } 193 194 func (s *ipAddressesStateSuite) assertAllAddressesOnMachineMatchCount(c *gc.C, machine *state.Machine, expectedCount int) { 195 results, err := machine.AllAddresses() 196 c.Assert(err, jc.ErrorIsNil) 197 c.Assert(results, gc.HasLen, expectedCount, gc.Commentf("expected %d, got %d: %+v", expectedCount, len(results), results)) 198 } 199 200 func (s *ipAddressesStateSuite) TestRemoveTwiceStillSucceeds(c *gc.C) { 201 _, existingAddresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 202 203 s.removeAddressAndAssertSuccess(c, existingAddresses[0]) 204 s.removeAddressAndAssertSuccess(c, existingAddresses[0]) 205 s.assertNoAddressesOnMachine(c, s.machine) 206 } 207 208 func (s *ipAddressesStateSuite) TestLinkLayerDeviceAddressesReturnsAllDeviceAddresses(c *gc.C) { 209 device, addedAddresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24", "10.20.30.40/16", "fc00::/64") 210 s.assertAllAddressesOnMachineMatchCount(c, s.machine, 3) 211 212 resultAddresses, err := device.Addresses() 213 c.Assert(err, jc.ErrorIsNil) 214 c.Assert(resultAddresses, jc.DeepEquals, addedAddresses) 215 } 216 217 func (s *ipAddressesStateSuite) TestLinkLayerDeviceRemoveAddressesSuccess(c *gc.C) { 218 device, _ := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.30.40/16", "fc00::/64") 219 s.assertAllAddressesOnMachineMatchCount(c, s.machine, 2) 220 221 s.removeDeviceAddressesAndAssertNoneRemainOnMacine(c, device) 222 } 223 224 func (s *ipAddressesStateSuite) removeDeviceAddressesAndAssertNoneRemainOnMacine(c *gc.C, device *state.LinkLayerDevice) { 225 err := device.RemoveAddresses() 226 c.Assert(err, jc.ErrorIsNil) 227 s.assertNoAddressesOnMachine(c, s.machine) 228 } 229 230 func (s *ipAddressesStateSuite) TestLinkLayerDeviceRemoveAddressesTwiceStillSucceeds(c *gc.C) { 231 device, _ := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.30.40/16", "fc00::/64") 232 s.assertAllAddressesOnMachineMatchCount(c, s.machine, 2) 233 234 s.removeDeviceAddressesAndAssertNoneRemainOnMacine(c, device) 235 s.removeDeviceAddressesAndAssertNoneRemainOnMacine(c, device) 236 } 237 238 func (s *ipAddressesStateSuite) TestMachineRemoveAllAddressesSuccess(c *gc.C) { 239 s.addTwoDevicesWithTwoAddressesEach(c) 240 s.removeAllAddressesOnMachineAndAssertNoneRemain(c) 241 } 242 243 func (s *ipAddressesStateSuite) addTwoDevicesWithTwoAddressesEach(c *gc.C) []*state.Address { 244 _, device1Addresses := s.addNamedDeviceWithAddresses(c, "eth1", "10.20.0.1/16", "10.20.0.2/16") 245 _, device2Addresses := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.100.2/16", "fc00::/64") 246 s.assertAllAddressesOnMachineMatchCount(c, s.machine, 4) 247 return append(device1Addresses, device2Addresses...) 248 } 249 250 func (s *ipAddressesStateSuite) removeAllAddressesOnMachineAndAssertNoneRemain(c *gc.C) { 251 err := s.machine.RemoveAllAddresses() 252 c.Assert(err, jc.ErrorIsNil) 253 s.assertNoAddressesOnMachine(c, s.machine) 254 } 255 256 func (s *ipAddressesStateSuite) TestMachineRemoveAllAddressesTwiceStillSucceeds(c *gc.C) { 257 s.addTwoDevicesWithTwoAddressesEach(c) 258 s.removeAllAddressesOnMachineAndAssertNoneRemain(c) 259 s.removeAllAddressesOnMachineAndAssertNoneRemain(c) 260 } 261 262 func (s *ipAddressesStateSuite) TestMachineAllAddressesSuccess(c *gc.C) { 263 addedAddresses := s.addTwoDevicesWithTwoAddressesEach(c) 264 265 allAddresses, err := s.machine.AllAddresses() 266 c.Assert(err, jc.ErrorIsNil) 267 c.Assert(allAddresses, jc.DeepEquals, addedAddresses) 268 } 269 270 func (s *ipAddressesStateSuite) TestLinkLayerDeviceRemoveAlsoRemovesDeviceAddresses(c *gc.C) { 271 device, _ := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.30.40/16", "fc00::/64") 272 s.assertAllAddressesOnMachineMatchCount(c, s.machine, 2) 273 274 err := device.Remove() 275 c.Assert(err, jc.ErrorIsNil) 276 s.assertNoAddressesOnMachine(c, s.machine) 277 } 278 279 func (s *ipAddressesStateSuite) TestMachineRemoveAlsoRemoveAllAddresses(c *gc.C) { 280 s.addTwoDevicesWithTwoAddressesEach(c) 281 s.ensureMachineDeadAndRemove(c, s.machine) 282 283 s.assertNoAddressesOnMachine(c, s.machine) 284 } 285 286 func (s *ipAddressesStateSuite) TestSetDevicesAddressesDoesNothingWithEmptyArgs(c *gc.C) { 287 err := s.machine.SetDevicesAddresses() // takes varargs, which includes none. 288 c.Assert(err, jc.ErrorIsNil) 289 } 290 291 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithEmptyCIDRAddress(c *gc.C) { 292 args := state.LinkLayerDeviceAddress{} 293 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "empty CIDRAddress not valid") 294 } 295 296 func (s *ipAddressesStateSuite) assertSetDevicesAddressesFailsValidationForArgs(c *gc.C, args state.LinkLayerDeviceAddress, errorCauseMatches string) { 297 invalidAddressPrefix := fmt.Sprintf("invalid address %q: ", args.CIDRAddress) 298 err := s.assertSetDevicesAddressesFailsForArgs(c, args, invalidAddressPrefix+errorCauseMatches) 299 c.Assert(err, jc.Satisfies, errors.IsNotValid) 300 } 301 302 func (s *ipAddressesStateSuite) assertSetDevicesAddressesFailsForArgs(c *gc.C, args state.LinkLayerDeviceAddress, errorCauseMatches string) error { 303 err := s.machine.SetDevicesAddresses(args) 304 expectedError := fmt.Sprintf("cannot set link-layer device addresses of machine %q: %s", s.machine.Id(), errorCauseMatches) 305 c.Assert(err, gc.ErrorMatches, expectedError) 306 return err 307 } 308 309 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithInvalidCIDRAddress(c *gc.C) { 310 args := state.LinkLayerDeviceAddress{ 311 CIDRAddress: "bad CIDR", 312 } 313 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "CIDRAddress: invalid CIDR address: bad CIDR") 314 } 315 316 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithCIDRAddressWithoutMask(c *gc.C) { 317 args := state.LinkLayerDeviceAddress{ 318 CIDRAddress: "10.10.10.10", 319 } 320 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "CIDRAddress: invalid CIDR address: 10.10.10.10") 321 } 322 323 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithEmptyDeviceName(c *gc.C) { 324 args := state.LinkLayerDeviceAddress{ 325 CIDRAddress: "0.1.2.3/24", 326 } 327 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "empty DeviceName not valid") 328 } 329 330 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithUnknownDeviceName(c *gc.C) { 331 args := state.LinkLayerDeviceAddress{ 332 CIDRAddress: "0.1.2.3/24", 333 ConfigMethod: state.StaticAddress, 334 DeviceName: "missing", 335 } 336 expectedError := `invalid address "0.1.2.3/24": DeviceName "missing" on machine "0" not found` 337 err := s.assertSetDevicesAddressesFailsForArgs(c, args, expectedError) 338 c.Assert(err, jc.Satisfies, errors.IsNotFound) 339 } 340 341 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithInvalidConfigMethod(c *gc.C) { 342 s.addNamedDevice(c, "eth0") 343 args := state.LinkLayerDeviceAddress{ 344 CIDRAddress: "0.1.2.3/24", 345 DeviceName: "eth0", 346 ConfigMethod: "something else", 347 } 348 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, `ConfigMethod "something else" not valid`) 349 } 350 351 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithInvalidGatewayAddress(c *gc.C) { 352 s.addNamedDevice(c, "eth0") 353 args := state.LinkLayerDeviceAddress{ 354 CIDRAddress: "0.1.2.3/24", 355 DeviceName: "eth0", 356 ConfigMethod: state.StaticAddress, 357 GatewayAddress: "boo hoo", 358 } 359 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, `GatewayAddress "boo hoo" not valid`) 360 } 361 362 func (s *ipAddressesStateSuite) TestSetDevicesAddressesOKWhenCIDRAddressDoesNotMatchKnownSubnet(c *gc.C) { 363 device := s.addNamedDevice(c, "eth0") 364 args := state.LinkLayerDeviceAddress{ 365 CIDRAddress: "192.168.123.42/16", 366 DeviceName: "eth0", 367 ConfigMethod: state.StaticAddress, 368 } 369 err := s.machine.SetDevicesAddresses(args) 370 c.Assert(err, jc.ErrorIsNil) 371 372 assertDeviceHasOneAddressWithSubnetCIDREquals := func(subnetCIDR string) { 373 addresses, err := device.Addresses() 374 c.Assert(err, jc.ErrorIsNil) 375 c.Assert(addresses, gc.HasLen, 1) 376 c.Assert(addresses[0].SubnetCIDR(), gc.Equals, subnetCIDR) 377 } 378 assertDeviceHasOneAddressWithSubnetCIDREquals("192.168.0.0/16") 379 380 // Add the subnet so it's known and retry setting the same address to verify 381 // SubnetID gets updated. 382 _, err = s.State.AddSubnet(state.SubnetInfo{CIDR: "192.168.0.0/16"}) 383 c.Assert(err, jc.ErrorIsNil) 384 err = s.machine.SetDevicesAddresses(args) 385 c.Assert(err, jc.ErrorIsNil) 386 387 assertDeviceHasOneAddressWithSubnetCIDREquals("192.168.0.0/16") 388 } 389 390 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWhenCIDRAddressMatchesDeadSubnet(c *gc.C) { 391 s.addNamedDevice(c, "eth0") 392 subnetCIDR := "10.20.0.0/16" 393 subnet, err := s.State.Subnet(subnetCIDR) 394 c.Assert(err, jc.ErrorIsNil) 395 err = subnet.EnsureDead() 396 c.Assert(err, jc.ErrorIsNil) 397 398 args := state.LinkLayerDeviceAddress{ 399 CIDRAddress: "10.20.30.40/16", 400 DeviceName: "eth0", 401 ConfigMethod: state.StaticAddress, 402 } 403 expectedError := fmt.Sprintf( 404 "invalid address %q: subnet %q is not alive", 405 args.CIDRAddress, subnetCIDR, 406 ) 407 s.assertSetDevicesAddressesFailsForArgs(c, args, expectedError) 408 } 409 410 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWhenModelNotAlive(c *gc.C) { 411 s.addNamedDeviceForMachine(c, "eth0", s.otherStateMachine) 412 otherModel, err := s.otherState.Model() 413 c.Assert(err, jc.ErrorIsNil) 414 err = otherModel.Destroy() 415 c.Assert(err, jc.ErrorIsNil) 416 417 args := state.LinkLayerDeviceAddress{ 418 CIDRAddress: "10.20.30.40/16", 419 DeviceName: "eth0", 420 ConfigMethod: state.StaticAddress, 421 } 422 err = s.otherStateMachine.SetDevicesAddresses(args) 423 c.Assert(err, gc.ErrorMatches, `.*: model "other-model" is no longer alive`) 424 } 425 426 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWhenMachineNotAliveOrGone(c *gc.C) { 427 s.addNamedDeviceForMachine(c, "eth0", s.otherStateMachine) 428 err := s.otherStateMachine.EnsureDead() 429 c.Assert(err, jc.ErrorIsNil) 430 431 args := state.LinkLayerDeviceAddress{ 432 CIDRAddress: "10.20.30.40/16", 433 DeviceName: "eth0", 434 ConfigMethod: state.StaticAddress, 435 } 436 err = s.otherStateMachine.SetDevicesAddresses(args) 437 c.Assert(err, gc.ErrorMatches, `.*: machine not found or not alive`) 438 439 err = s.otherStateMachine.Remove() 440 c.Assert(err, jc.ErrorIsNil) 441 442 // Check it fails with a different error, as eth0 was removed along with 443 // otherStateMachine above. 444 err = s.otherStateMachine.SetDevicesAddresses(args) 445 c.Assert(err, gc.ErrorMatches, `.*: DeviceName "eth0" on machine "0" not found`) 446 } 447 448 func (s *ipAddressesStateSuite) TestSetDevicesAddressesUpdatesExistingDocs(c *gc.C) { 449 device, initialAddresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24", "10.20.30.42/16") 450 451 setArgs := []state.LinkLayerDeviceAddress{{ 452 // All fields that can be set are included below. 453 DeviceName: "eth0", 454 ConfigMethod: state.ManualAddress, 455 CIDRAddress: "0.1.2.3/24", 456 ProviderID: "id-0123", 457 DNSServers: []string{"ns1.example.com", "ns2.example.org"}, 458 DNSSearchDomains: []string{"example.com", "example.org"}, 459 GatewayAddress: "0.1.2.1", 460 }, { 461 // No changed fields, just the required values are set: CIDRAddress + 462 // DeviceName (and s.machine.Id) are used to construct the DocID. 463 DeviceName: "eth0", 464 ConfigMethod: state.StaticAddress, 465 CIDRAddress: "10.20.30.42/16", 466 }} 467 err := s.machine.SetDevicesAddresses(setArgs...) 468 c.Assert(err, jc.ErrorIsNil) 469 updatedAddresses, err := device.Addresses() 470 c.Assert(err, jc.ErrorIsNil) 471 c.Assert(updatedAddresses, gc.HasLen, len(initialAddresses)) 472 if updatedAddresses[0].Value() != "0.1.2.3" { 473 // Swap the results if they arrive in different order. 474 updatedAddresses[1], updatedAddresses[0] = updatedAddresses[0], updatedAddresses[1] 475 } 476 477 for i, address := range updatedAddresses { 478 s.checkAddressMatchesArgs(c, address, setArgs[i]) 479 } 480 } 481 482 func (s *ipAddressesStateSuite) checkAddressMatchesArgs(c *gc.C, address *state.Address, args state.LinkLayerDeviceAddress) { 483 c.Check(address.DeviceName(), gc.Equals, args.DeviceName) 484 c.Check(address.MachineID(), gc.Equals, s.machine.Id()) 485 c.Check(args.CIDRAddress, jc.HasPrefix, address.Value()) 486 c.Check(address.ConfigMethod(), gc.Equals, args.ConfigMethod) 487 c.Check(address.ProviderID(), gc.Equals, args.ProviderID) 488 c.Check(address.DNSServers(), jc.DeepEquals, args.DNSServers) 489 c.Check(address.DNSSearchDomains(), jc.DeepEquals, args.DNSSearchDomains) 490 c.Check(address.GatewayAddress(), gc.Equals, args.GatewayAddress) 491 } 492 493 func (s *ipAddressesStateSuite) TestSetDevicesAddressesWithMultipleUpdatesOfSameDocLastUpdateWins(c *gc.C) { 494 device, initialAddresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 495 496 setArgs := []state.LinkLayerDeviceAddress{{ 497 // No changes - same args as used by addNamedDeviceWithAddresses, so 498 // this is testing a no-op case. 499 DeviceName: "eth0", 500 ConfigMethod: state.StaticAddress, 501 CIDRAddress: "0.1.2.3/24", 502 }, { 503 // Change all fields that can change. 504 DeviceName: "eth0", 505 ConfigMethod: state.ManualAddress, 506 CIDRAddress: "0.1.2.3/24", 507 ProviderID: "id-0123", 508 DNSServers: []string{"ns1.example.com", "ns2.example.org"}, 509 DNSSearchDomains: []string{"example.com", "example.org"}, 510 GatewayAddress: "0.1.2.1", 511 }, { 512 // Test deletes work for DNS settings, also change method, provider id, and gateway. 513 DeviceName: "eth0", 514 ConfigMethod: state.DynamicAddress, 515 CIDRAddress: "0.1.2.3/24", 516 ProviderID: "id-xxxx", // last change wins 517 DNSServers: nil, 518 DNSSearchDomains: nil, 519 GatewayAddress: "0.1.2.2", 520 }} 521 err := s.machine.SetDevicesAddresses(setArgs...) 522 c.Assert(err, jc.ErrorIsNil) 523 updatedAddresses, err := device.Addresses() 524 c.Assert(err, jc.ErrorIsNil) 525 c.Assert(updatedAddresses, gc.HasLen, len(initialAddresses)) 526 527 var lastArgsIndex = len(setArgs) - 1 528 s.checkAddressMatchesArgs(c, updatedAddresses[0], state.LinkLayerDeviceAddress{ 529 DeviceName: setArgs[lastArgsIndex].DeviceName, 530 ConfigMethod: setArgs[lastArgsIndex].ConfigMethod, 531 CIDRAddress: setArgs[lastArgsIndex].CIDRAddress, 532 ProviderID: setArgs[lastArgsIndex].ProviderID, 533 DNSServers: setArgs[lastArgsIndex].DNSServers, 534 DNSSearchDomains: setArgs[lastArgsIndex].DNSSearchDomains, 535 GatewayAddress: setArgs[lastArgsIndex].GatewayAddress, 536 }) 537 } 538 539 func (s *ipAddressesStateSuite) TestSetDevicesAddressesWithDuplicateProviderIDFailsInSameModel(c *gc.C) { 540 _, firstAddressArgs := s.addDeviceWithAddressAndProviderIDForMachine(c, "42", s.machine) 541 secondAddressArgs := firstAddressArgs 542 secondAddressArgs.CIDRAddress = "10.20.30.40/16" 543 544 err := s.machine.SetDevicesAddresses(secondAddressArgs) 545 c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError) 546 c.Assert(err, gc.ErrorMatches, `.*invalid address "10.20.30.40/16": ProviderID\(s\) not unique: 42`) 547 } 548 549 func (s *ipAddressesStateSuite) addDeviceWithAddressAndProviderIDForMachine(c *gc.C, providerID string, machine *state.Machine) ( 550 *state.LinkLayerDevice, 551 state.LinkLayerDeviceAddress, 552 ) { 553 device := s.addNamedDeviceForMachine(c, "eth0", machine) 554 addressArgs := state.LinkLayerDeviceAddress{ 555 DeviceName: "eth0", 556 ConfigMethod: state.StaticAddress, 557 CIDRAddress: "0.1.2.3/24", 558 ProviderID: network.Id(providerID), 559 } 560 err := machine.SetDevicesAddresses(addressArgs) 561 c.Assert(err, jc.ErrorIsNil) 562 return device, addressArgs 563 } 564 565 func (s *ipAddressesStateSuite) TestSetDevicesAddressesWithDuplicateProviderIDSucceedsInDifferentModel(c *gc.C) { 566 _, firstAddressArgs := s.addDeviceWithAddressAndProviderIDForMachine(c, "42", s.otherStateMachine) 567 secondAddressArgs := firstAddressArgs 568 secondAddressArgs.CIDRAddress = "10.20.30.40/16" 569 570 s.addNamedDevice(c, firstAddressArgs.DeviceName) // for s.machine 571 err := s.machine.SetDevicesAddresses(secondAddressArgs) 572 c.Assert(err, jc.ErrorIsNil) 573 } 574 575 func (s *ipAddressesStateSuite) TestMachineSetDevicesAddressesIdempotentlyOnce(c *gc.C) { 576 s.testMachineSetDevicesAddressesIdempotently(c) 577 } 578 579 func (s *ipAddressesStateSuite) TestMachineSetDevicesAddressesIdempotentlyTwice(c *gc.C) { 580 s.testMachineSetDevicesAddressesIdempotently(c) 581 s.testMachineSetDevicesAddressesIdempotently(c) 582 } 583 584 func (s *ipAddressesStateSuite) testMachineSetDevicesAddressesIdempotently(c *gc.C) { 585 err := s.machine.SetParentLinkLayerDevicesBeforeTheirChildren(nestedDevicesArgs) 586 c.Assert(err, jc.ErrorIsNil) 587 588 args := []state.LinkLayerDeviceAddress{{ 589 DeviceName: "lo", 590 CIDRAddress: "127.0.0.1/8", 591 ConfigMethod: state.LoopbackAddress, 592 }, { 593 DeviceName: "br-bond0", 594 CIDRAddress: "10.20.0.100/16", 595 ConfigMethod: state.StaticAddress, 596 ProviderID: "200", 597 }, { 598 DeviceName: "br-bond0.12", 599 CIDRAddress: "0.1.2.112/24", 600 ConfigMethod: state.StaticAddress, 601 ProviderID: "201", 602 }, { 603 DeviceName: "br-bond0.34", 604 CIDRAddress: "0.1.2.134/24", 605 ConfigMethod: state.StaticAddress, 606 ProviderID: "202", 607 }} 608 err = s.machine.SetDevicesAddressesIdempotently(args) 609 c.Assert(err, jc.ErrorIsNil) 610 allAddresses, err := s.machine.AllAddresses() 611 c.Assert(err, jc.ErrorIsNil) 612 c.Assert(allAddresses, gc.HasLen, len(args)) 613 for _, address := range allAddresses { 614 if address.ConfigMethod() != state.LoopbackAddress && address.ConfigMethod() != state.ManualAddress { 615 c.Check(address.ProviderID(), gc.Not(gc.Equals), network.Id("")) 616 } 617 } 618 }