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  }