github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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) TestMachineRemoveAllAddressesRemovesProviderIDReferences(c *gc.C) { 244 s.addNamedDevice(c, "foo") 245 addrArgs := state.LinkLayerDeviceAddress{ 246 DeviceName: "foo", 247 ConfigMethod: state.StaticAddress, 248 CIDRAddress: "0.1.2.3/24", 249 ProviderID: "bar", 250 } 251 err := s.machine.SetDevicesAddresses(addrArgs) 252 c.Assert(err, jc.ErrorIsNil) 253 s.removeAllAddressesOnMachineAndAssertNoneRemain(c) 254 255 // Re-adding the same address to a new device should now succeed. 256 err = s.machine.SetDevicesAddresses(addrArgs) 257 c.Assert(err, jc.ErrorIsNil) 258 } 259 260 func (s *ipAddressesStateSuite) addTwoDevicesWithTwoAddressesEach(c *gc.C) []*state.Address { 261 _, device1Addresses := s.addNamedDeviceWithAddresses(c, "eth1", "10.20.0.1/16", "10.20.0.2/16") 262 _, device2Addresses := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.100.2/16", "fc00::/64") 263 s.assertAllAddressesOnMachineMatchCount(c, s.machine, 4) 264 return append(device1Addresses, device2Addresses...) 265 } 266 267 func (s *ipAddressesStateSuite) removeAllAddressesOnMachineAndAssertNoneRemain(c *gc.C) { 268 err := s.machine.RemoveAllAddresses() 269 c.Assert(err, jc.ErrorIsNil) 270 s.assertNoAddressesOnMachine(c, s.machine) 271 } 272 273 func (s *ipAddressesStateSuite) TestMachineRemoveAllAddressesTwiceStillSucceeds(c *gc.C) { 274 s.addTwoDevicesWithTwoAddressesEach(c) 275 s.removeAllAddressesOnMachineAndAssertNoneRemain(c) 276 s.removeAllAddressesOnMachineAndAssertNoneRemain(c) 277 } 278 279 func (s *ipAddressesStateSuite) TestMachineAllAddressesSuccess(c *gc.C) { 280 addedAddresses := s.addTwoDevicesWithTwoAddressesEach(c) 281 282 allAddresses, err := s.machine.AllAddresses() 283 c.Assert(err, jc.ErrorIsNil) 284 c.Assert(allAddresses, jc.DeepEquals, addedAddresses) 285 } 286 287 func (s *ipAddressesStateSuite) TestLinkLayerDeviceRemoveAlsoRemovesDeviceAddresses(c *gc.C) { 288 device, _ := s.addNamedDeviceWithAddresses(c, "eth0", "10.20.30.40/16", "fc00::/64") 289 s.assertAllAddressesOnMachineMatchCount(c, s.machine, 2) 290 291 err := device.Remove() 292 c.Assert(err, jc.ErrorIsNil) 293 s.assertNoAddressesOnMachine(c, s.machine) 294 } 295 296 func (s *ipAddressesStateSuite) TestMachineRemoveAlsoRemoveAllAddresses(c *gc.C) { 297 s.addTwoDevicesWithTwoAddressesEach(c) 298 s.ensureMachineDeadAndRemove(c, s.machine) 299 300 s.assertNoAddressesOnMachine(c, s.machine) 301 } 302 303 func (s *ipAddressesStateSuite) TestSetDevicesAddressesDoesNothingWithEmptyArgs(c *gc.C) { 304 err := s.machine.SetDevicesAddresses() // takes varargs, which includes none. 305 c.Assert(err, jc.ErrorIsNil) 306 } 307 308 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithEmptyCIDRAddress(c *gc.C) { 309 args := state.LinkLayerDeviceAddress{} 310 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "empty CIDRAddress not valid") 311 } 312 313 func (s *ipAddressesStateSuite) assertSetDevicesAddressesFailsValidationForArgs(c *gc.C, args state.LinkLayerDeviceAddress, errorCauseMatches string) { 314 invalidAddressPrefix := fmt.Sprintf("invalid address %q: ", args.CIDRAddress) 315 err := s.assertSetDevicesAddressesFailsForArgs(c, args, invalidAddressPrefix+errorCauseMatches) 316 c.Assert(err, jc.Satisfies, errors.IsNotValid) 317 } 318 319 func (s *ipAddressesStateSuite) assertSetDevicesAddressesFailsForArgs(c *gc.C, args state.LinkLayerDeviceAddress, errorCauseMatches string) error { 320 err := s.machine.SetDevicesAddresses(args) 321 expectedError := fmt.Sprintf("cannot set link-layer device addresses of machine %q: %s", s.machine.Id(), errorCauseMatches) 322 c.Assert(err, gc.ErrorMatches, expectedError) 323 return err 324 } 325 326 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithInvalidCIDRAddress(c *gc.C) { 327 args := state.LinkLayerDeviceAddress{ 328 CIDRAddress: "bad CIDR", 329 } 330 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "CIDRAddress: invalid CIDR address: bad CIDR") 331 } 332 333 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithCIDRAddressWithoutMask(c *gc.C) { 334 args := state.LinkLayerDeviceAddress{ 335 CIDRAddress: "10.10.10.10", 336 } 337 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "CIDRAddress: invalid CIDR address: 10.10.10.10") 338 } 339 340 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithEmptyDeviceName(c *gc.C) { 341 args := state.LinkLayerDeviceAddress{ 342 CIDRAddress: "0.1.2.3/24", 343 } 344 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, "empty DeviceName not valid") 345 } 346 347 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithUnknownDeviceName(c *gc.C) { 348 args := state.LinkLayerDeviceAddress{ 349 CIDRAddress: "0.1.2.3/24", 350 ConfigMethod: state.StaticAddress, 351 DeviceName: "missing", 352 } 353 expectedError := `invalid address "0.1.2.3/24": DeviceName "missing" on machine "0" not found` 354 err := s.assertSetDevicesAddressesFailsForArgs(c, args, expectedError) 355 c.Assert(err, jc.Satisfies, errors.IsNotFound) 356 } 357 358 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithInvalidConfigMethod(c *gc.C) { 359 s.addNamedDevice(c, "eth0") 360 args := state.LinkLayerDeviceAddress{ 361 CIDRAddress: "0.1.2.3/24", 362 DeviceName: "eth0", 363 ConfigMethod: "something else", 364 } 365 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, `ConfigMethod "something else" not valid`) 366 } 367 368 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWithInvalidGatewayAddress(c *gc.C) { 369 s.addNamedDevice(c, "eth0") 370 args := state.LinkLayerDeviceAddress{ 371 CIDRAddress: "0.1.2.3/24", 372 DeviceName: "eth0", 373 ConfigMethod: state.StaticAddress, 374 GatewayAddress: "boo hoo", 375 } 376 s.assertSetDevicesAddressesFailsValidationForArgs(c, args, `GatewayAddress "boo hoo" not valid`) 377 } 378 379 func (s *ipAddressesStateSuite) TestSetDevicesAddressesOKWhenCIDRAddressDoesNotMatchKnownSubnet(c *gc.C) { 380 device := s.addNamedDevice(c, "eth0") 381 args := state.LinkLayerDeviceAddress{ 382 CIDRAddress: "192.168.123.42/16", 383 DeviceName: "eth0", 384 ConfigMethod: state.StaticAddress, 385 } 386 err := s.machine.SetDevicesAddresses(args) 387 c.Assert(err, jc.ErrorIsNil) 388 389 assertDeviceHasOneAddressWithSubnetCIDREquals := func(subnetCIDR string) { 390 addresses, err := device.Addresses() 391 c.Assert(err, jc.ErrorIsNil) 392 c.Assert(addresses, gc.HasLen, 1) 393 c.Assert(addresses[0].SubnetCIDR(), gc.Equals, subnetCIDR) 394 } 395 assertDeviceHasOneAddressWithSubnetCIDREquals("192.168.0.0/16") 396 397 // Add the subnet so it's known and retry setting the same address to verify 398 // SubnetID gets updated. 399 _, err = s.State.AddSubnet(state.SubnetInfo{CIDR: "192.168.0.0/16"}) 400 c.Assert(err, jc.ErrorIsNil) 401 err = s.machine.SetDevicesAddresses(args) 402 c.Assert(err, jc.ErrorIsNil) 403 404 assertDeviceHasOneAddressWithSubnetCIDREquals("192.168.0.0/16") 405 } 406 407 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWhenCIDRAddressMatchesDeadSubnet(c *gc.C) { 408 s.addNamedDevice(c, "eth0") 409 subnetCIDR := "10.20.0.0/16" 410 subnet, err := s.State.Subnet(subnetCIDR) 411 c.Assert(err, jc.ErrorIsNil) 412 err = subnet.EnsureDead() 413 c.Assert(err, jc.ErrorIsNil) 414 415 args := state.LinkLayerDeviceAddress{ 416 CIDRAddress: "10.20.30.40/16", 417 DeviceName: "eth0", 418 ConfigMethod: state.StaticAddress, 419 } 420 expectedError := fmt.Sprintf( 421 "invalid address %q: subnet %q is not alive", 422 args.CIDRAddress, subnetCIDR, 423 ) 424 s.assertSetDevicesAddressesFailsForArgs(c, args, expectedError) 425 } 426 427 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWhenModelNotAlive(c *gc.C) { 428 s.addNamedDeviceForMachine(c, "eth0", s.otherStateMachine) 429 otherModel, err := s.otherState.Model() 430 c.Assert(err, jc.ErrorIsNil) 431 err = otherModel.Destroy() 432 c.Assert(err, jc.ErrorIsNil) 433 434 args := state.LinkLayerDeviceAddress{ 435 CIDRAddress: "10.20.30.40/16", 436 DeviceName: "eth0", 437 ConfigMethod: state.StaticAddress, 438 } 439 err = s.otherStateMachine.SetDevicesAddresses(args) 440 c.Assert(err, gc.ErrorMatches, `.*: model "other-model" is no longer alive`) 441 } 442 443 func (s *ipAddressesStateSuite) TestSetDevicesAddressesFailsWhenMachineNotAliveOrGone(c *gc.C) { 444 s.addNamedDeviceForMachine(c, "eth0", s.otherStateMachine) 445 err := s.otherStateMachine.EnsureDead() 446 c.Assert(err, jc.ErrorIsNil) 447 448 args := state.LinkLayerDeviceAddress{ 449 CIDRAddress: "10.20.30.40/16", 450 DeviceName: "eth0", 451 ConfigMethod: state.StaticAddress, 452 } 453 err = s.otherStateMachine.SetDevicesAddresses(args) 454 c.Assert(err, gc.ErrorMatches, `.*: machine not found or not alive`) 455 456 err = s.otherStateMachine.Remove() 457 c.Assert(err, jc.ErrorIsNil) 458 459 // Check it fails with a different error, as eth0 was removed along with 460 // otherStateMachine above. 461 err = s.otherStateMachine.SetDevicesAddresses(args) 462 c.Assert(err, gc.ErrorMatches, `.*: DeviceName "eth0" on machine "0" not found`) 463 } 464 465 func (s *ipAddressesStateSuite) TestSetDevicesAddressesUpdatesExistingDocs(c *gc.C) { 466 device, initialAddresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24", "10.20.30.42/16") 467 468 setArgs := []state.LinkLayerDeviceAddress{{ 469 // All fields that can be set are included below. 470 DeviceName: "eth0", 471 ConfigMethod: state.ManualAddress, 472 CIDRAddress: "0.1.2.3/24", 473 ProviderID: "id-0123", 474 DNSServers: []string{"ns1.example.com", "ns2.example.org"}, 475 DNSSearchDomains: []string{"example.com", "example.org"}, 476 GatewayAddress: "0.1.2.1", 477 }, { 478 // No changed fields, just the required values are set: CIDRAddress + 479 // DeviceName (and s.machine.Id) are used to construct the DocID. 480 DeviceName: "eth0", 481 ConfigMethod: state.StaticAddress, 482 CIDRAddress: "10.20.30.42/16", 483 }} 484 err := s.machine.SetDevicesAddresses(setArgs...) 485 c.Assert(err, jc.ErrorIsNil) 486 updatedAddresses, err := device.Addresses() 487 c.Assert(err, jc.ErrorIsNil) 488 c.Assert(updatedAddresses, gc.HasLen, len(initialAddresses)) 489 if updatedAddresses[0].Value() != "0.1.2.3" { 490 // Swap the results if they arrive in different order. 491 updatedAddresses[1], updatedAddresses[0] = updatedAddresses[0], updatedAddresses[1] 492 } 493 494 for i, address := range updatedAddresses { 495 s.checkAddressMatchesArgs(c, address, setArgs[i]) 496 } 497 } 498 499 func (s *ipAddressesStateSuite) TestRemoveAddressRemovesProviderID(c *gc.C) { 500 device := s.addNamedDevice(c, "eth0") 501 addrArgs := state.LinkLayerDeviceAddress{ 502 DeviceName: "eth0", 503 ConfigMethod: state.ManualAddress, 504 CIDRAddress: "0.1.2.3/24", 505 ProviderID: "id-0123", 506 } 507 err := s.machine.SetDevicesAddresses(addrArgs) 508 c.Assert(err, jc.ErrorIsNil) 509 addresses, err := device.Addresses() 510 c.Assert(err, jc.ErrorIsNil) 511 c.Assert(addresses, gc.HasLen, 1) 512 addr := addresses[0] 513 err = addr.Remove() 514 c.Assert(err, jc.ErrorIsNil) 515 err = s.machine.SetDevicesAddresses(addrArgs) 516 c.Assert(err, jc.ErrorIsNil) 517 } 518 519 func (s *ipAddressesStateSuite) TestUpdateAddressFailsToChangeProviderID(c *gc.C) { 520 s.addNamedDevice(c, "eth0") 521 addrArgs := state.LinkLayerDeviceAddress{ 522 DeviceName: "eth0", 523 ConfigMethod: state.ManualAddress, 524 CIDRAddress: "0.1.2.3/24", 525 ProviderID: "id-0123", 526 } 527 err := s.machine.SetDevicesAddresses(addrArgs) 528 c.Assert(err, jc.ErrorIsNil) 529 addrArgs.ProviderID = "id-0124" 530 err = s.machine.SetDevicesAddresses(addrArgs) 531 c.Assert(err, gc.ErrorMatches, `.*cannot change ProviderID of link address "0.1.2.3"`) 532 } 533 534 func (s *ipAddressesStateSuite) TestUpdateAddressPreventsDuplicateProviderID(c *gc.C) { 535 s.addNamedDevice(c, "eth0") 536 addrArgs := state.LinkLayerDeviceAddress{ 537 DeviceName: "eth0", 538 ConfigMethod: state.ManualAddress, 539 CIDRAddress: "0.1.2.3/24", 540 } 541 err := s.machine.SetDevicesAddresses(addrArgs) 542 c.Assert(err, jc.ErrorIsNil) 543 544 // Set the provider id through an update. 545 addrArgs.ProviderID = "id-0123" 546 err = s.machine.SetDevicesAddresses(addrArgs) 547 c.Assert(err, jc.ErrorIsNil) 548 549 // Adding a new address with the same provider id should now fail. 550 addrArgs.CIDRAddress = "0.1.2.4/24" 551 err = s.machine.SetDevicesAddresses(addrArgs) 552 c.Assert(err, gc.ErrorMatches, `.*invalid address "0.1.2.4/24": ProviderID\(s\) not unique: id-0123`) 553 } 554 555 func (s *ipAddressesStateSuite) checkAddressMatchesArgs(c *gc.C, address *state.Address, args state.LinkLayerDeviceAddress) { 556 c.Check(address.DeviceName(), gc.Equals, args.DeviceName) 557 c.Check(address.MachineID(), gc.Equals, s.machine.Id()) 558 c.Check(args.CIDRAddress, jc.HasPrefix, address.Value()) 559 c.Check(address.ConfigMethod(), gc.Equals, args.ConfigMethod) 560 c.Check(address.ProviderID(), gc.Equals, args.ProviderID) 561 c.Check(address.DNSServers(), jc.DeepEquals, args.DNSServers) 562 c.Check(address.DNSSearchDomains(), jc.DeepEquals, args.DNSSearchDomains) 563 c.Check(address.GatewayAddress(), gc.Equals, args.GatewayAddress) 564 } 565 566 func (s *ipAddressesStateSuite) TestSetDevicesAddressesWithMultipleUpdatesOfSameDocLastUpdateWins(c *gc.C) { 567 device, initialAddresses := s.addNamedDeviceWithAddresses(c, "eth0", "0.1.2.3/24") 568 569 setArgs := []state.LinkLayerDeviceAddress{{ 570 // No changes - same args as used by addNamedDeviceWithAddresses, so 571 // this is testing a no-op case. 572 DeviceName: "eth0", 573 ConfigMethod: state.StaticAddress, 574 CIDRAddress: "0.1.2.3/24", 575 }, { 576 // Change all fields that can change. 577 DeviceName: "eth0", 578 ConfigMethod: state.ManualAddress, 579 CIDRAddress: "0.1.2.3/24", 580 ProviderID: "id-0123", 581 DNSServers: []string{"ns1.example.com", "ns2.example.org"}, 582 DNSSearchDomains: []string{"example.com", "example.org"}, 583 GatewayAddress: "0.1.2.1", 584 }, { 585 // Test deletes work for DNS settings, also change method, provider id, and gateway. 586 DeviceName: "eth0", 587 ConfigMethod: state.DynamicAddress, 588 CIDRAddress: "0.1.2.3/24", 589 ProviderID: "id-xxxx", // last change wins 590 DNSServers: nil, 591 DNSSearchDomains: nil, 592 GatewayAddress: "0.1.2.2", 593 }} 594 err := s.machine.SetDevicesAddresses(setArgs...) 595 c.Assert(err, jc.ErrorIsNil) 596 updatedAddresses, err := device.Addresses() 597 c.Assert(err, jc.ErrorIsNil) 598 c.Assert(updatedAddresses, gc.HasLen, len(initialAddresses)) 599 600 var lastArgsIndex = len(setArgs) - 1 601 s.checkAddressMatchesArgs(c, updatedAddresses[0], state.LinkLayerDeviceAddress{ 602 DeviceName: setArgs[lastArgsIndex].DeviceName, 603 ConfigMethod: setArgs[lastArgsIndex].ConfigMethod, 604 CIDRAddress: setArgs[lastArgsIndex].CIDRAddress, 605 ProviderID: setArgs[lastArgsIndex].ProviderID, 606 DNSServers: setArgs[lastArgsIndex].DNSServers, 607 DNSSearchDomains: setArgs[lastArgsIndex].DNSSearchDomains, 608 GatewayAddress: setArgs[lastArgsIndex].GatewayAddress, 609 }) 610 } 611 612 func (s *ipAddressesStateSuite) TestSetDevicesAddressesWithDuplicateProviderIDFailsInSameModel(c *gc.C) { 613 _, firstAddressArgs := s.addDeviceWithAddressAndProviderIDForMachine(c, "42", s.machine) 614 secondAddressArgs := firstAddressArgs 615 secondAddressArgs.CIDRAddress = "10.20.30.40/16" 616 617 err := s.machine.SetDevicesAddresses(secondAddressArgs) 618 c.Assert(err, jc.Satisfies, state.IsProviderIDNotUniqueError) 619 c.Assert(err, gc.ErrorMatches, `.*invalid address "10.20.30.40/16": ProviderID\(s\) not unique: 42`) 620 } 621 622 func (s *ipAddressesStateSuite) addDeviceWithAddressAndProviderIDForMachine(c *gc.C, providerID string, machine *state.Machine) ( 623 *state.LinkLayerDevice, 624 state.LinkLayerDeviceAddress, 625 ) { 626 device := s.addNamedDeviceForMachine(c, "eth0", machine) 627 addressArgs := state.LinkLayerDeviceAddress{ 628 DeviceName: "eth0", 629 ConfigMethod: state.StaticAddress, 630 CIDRAddress: "0.1.2.3/24", 631 ProviderID: network.Id(providerID), 632 } 633 err := machine.SetDevicesAddresses(addressArgs) 634 c.Assert(err, jc.ErrorIsNil) 635 return device, addressArgs 636 } 637 638 func (s *ipAddressesStateSuite) TestSetDevicesAddressesWithDuplicateProviderIDSucceedsInDifferentModel(c *gc.C) { 639 _, firstAddressArgs := s.addDeviceWithAddressAndProviderIDForMachine(c, "42", s.otherStateMachine) 640 secondAddressArgs := firstAddressArgs 641 secondAddressArgs.CIDRAddress = "10.20.30.40/16" 642 643 s.addNamedDevice(c, firstAddressArgs.DeviceName) // for s.machine 644 err := s.machine.SetDevicesAddresses(secondAddressArgs) 645 c.Assert(err, jc.ErrorIsNil) 646 } 647 648 func (s *ipAddressesStateSuite) TestMachineSetDevicesAddressesIdempotentlyOnce(c *gc.C) { 649 s.testMachineSetDevicesAddressesIdempotently(c) 650 } 651 652 func (s *ipAddressesStateSuite) TestMachineSetDevicesAddressesIdempotentlyTwice(c *gc.C) { 653 s.testMachineSetDevicesAddressesIdempotently(c) 654 s.testMachineSetDevicesAddressesIdempotently(c) 655 } 656 657 func (s *ipAddressesStateSuite) testMachineSetDevicesAddressesIdempotently(c *gc.C) { 658 err := s.machine.SetParentLinkLayerDevicesBeforeTheirChildren(nestedDevicesArgs) 659 c.Assert(err, jc.ErrorIsNil) 660 661 args := []state.LinkLayerDeviceAddress{{ 662 DeviceName: "lo", 663 CIDRAddress: "127.0.0.1/8", 664 ConfigMethod: state.LoopbackAddress, 665 }, { 666 DeviceName: "br-bond0", 667 CIDRAddress: "10.20.0.100/16", 668 ConfigMethod: state.StaticAddress, 669 ProviderID: "200", 670 }, { 671 DeviceName: "br-bond0.12", 672 CIDRAddress: "0.1.2.112/24", 673 ConfigMethod: state.StaticAddress, 674 ProviderID: "201", 675 }, { 676 DeviceName: "br-bond0.34", 677 CIDRAddress: "0.1.2.134/24", 678 ConfigMethod: state.StaticAddress, 679 ProviderID: "202", 680 }} 681 err = s.machine.SetDevicesAddressesIdempotently(args) 682 c.Assert(err, jc.ErrorIsNil) 683 allAddresses, err := s.machine.AllAddresses() 684 c.Assert(err, jc.ErrorIsNil) 685 c.Assert(allAddresses, gc.HasLen, len(args)) 686 for _, address := range allAddresses { 687 if address.ConfigMethod() != state.LoopbackAddress && address.ConfigMethod() != state.ManualAddress { 688 c.Check(address.ProviderID(), gc.Not(gc.Equals), network.Id("")) 689 } 690 } 691 }