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  }