github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/network/containerizer/linklayerdevicesforspaces_test.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package containerizer
     5  
     6  import (
     7  	"github.com/juju/testing"
     8  	jc "github.com/juju/testing/checkers"
     9  	"go.uber.org/mock/gomock"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/core/network"
    13  )
    14  
    15  type linkLayerDevForSpacesSuite struct {
    16  	testing.IsolationSuite
    17  
    18  	machine *MockContainer
    19  
    20  	devices   []LinkLayerDevice
    21  	addresses []Address
    22  }
    23  
    24  var _ = gc.Suite(&linkLayerDevForSpacesSuite{})
    25  
    26  func (s *linkLayerDevForSpacesSuite) SetUpTest(c *gc.C) {
    27  	s.IsolationSuite.SetUpTest(c)
    28  
    29  	s.devices = make([]LinkLayerDevice, 0)
    30  	s.addresses = make([]Address, 0)
    31  }
    32  
    33  // TODO(jam): 2017-01-31 Make sure KVM guests default to virbr0, and LXD guests use lxdbr0
    34  // Add tests for UseLocal = True, but we have named spaces
    35  // Add tests for UseLocal = True, but the host device is bridged
    36  
    37  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpaces(c *gc.C) {
    38  	ctrl := s.setupMocks(c)
    39  	defer ctrl.Finish()
    40  
    41  	s.expectNICAndBridgeWithIP(ctrl, "eth0", "br-eth0", "1")
    42  	s.expectMachineAddressesDevices()
    43  
    44  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: "1"}})
    45  	c.Assert(err, jc.ErrorIsNil)
    46  	c.Assert(res, gc.HasLen, 1)
    47  
    48  	devices, ok := res["1"]
    49  	c.Assert(ok, jc.IsTrue)
    50  	c.Check(devices, gc.HasLen, 1)
    51  	c.Check(devices[0].Name(), gc.Equals, "br-eth0")
    52  	c.Check(devices[0].Type(), gc.Equals, network.BridgeDevice)
    53  }
    54  
    55  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesNoSuchSpace(c *gc.C) {
    56  	ctrl := s.setupMocks(c)
    57  	defer ctrl.Finish()
    58  
    59  	s.expectNICAndBridgeWithIP(ctrl, "eth0", "br-eth0", "1")
    60  	s.expectMachineAddressesDevices()
    61  
    62  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: "2"}})
    63  	c.Assert(err, jc.ErrorIsNil)
    64  	c.Check(res, gc.HasLen, 0)
    65  }
    66  
    67  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesNoBridge(c *gc.C) {
    68  	//	s.setupMachineWithOneNIC(c):
    69  	//	           s.setupTwoSpaces(c)
    70  	//             In the default space
    71  	//             s.createNICWithIP(c, s.machine, "eth0", "10.0.0.20/24")
    72  
    73  	ctrl := s.setupMocks(c)
    74  	defer ctrl.Finish()
    75  
    76  	s.expectNICWithIP(ctrl, "eth0", "1")
    77  	s.expectMachineAddressesDevices()
    78  
    79  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: "1"}})
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	c.Assert(res, gc.HasLen, 1)
    82  
    83  	devices, ok := res["1"]
    84  	c.Assert(ok, jc.IsTrue)
    85  	c.Check(devices, gc.HasLen, 1)
    86  	c.Check(devices[0].Name(), gc.Equals, "eth0")
    87  	c.Check(devices[0].Type(), gc.Equals, network.EthernetDevice)
    88  }
    89  
    90  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesMultipleSpaces(c *gc.C) {
    91  	ctrl := s.setupMocks(c)
    92  	defer ctrl.Finish()
    93  
    94  	// Is put into the 'somespace' space
    95  	s.expectNICAndBridgeWithIP(ctrl, "eth0", "br-eth0", "1")
    96  	// Now add a NIC in the dmz space, but without a bridge
    97  	s.expectNICWithIP(ctrl, "eth1", "2")
    98  	s.expectMachineAddressesDevices()
    99  
   100  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: "1"}, {ID: "2"}})
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	c.Check(res, gc.HasLen, 2)
   103  
   104  	somespaceDevices, ok := res["1"]
   105  	c.Check(ok, jc.IsTrue)
   106  	c.Check(somespaceDevices, gc.HasLen, 1)
   107  	c.Check(somespaceDevices[0].Name(), gc.Equals, "br-eth0")
   108  	dmzDevices, ok := res["2"]
   109  	c.Check(ok, jc.IsTrue)
   110  	c.Check(dmzDevices, gc.HasLen, 1)
   111  	c.Check(dmzDevices[0].Name(), gc.Equals, "eth1")
   112  }
   113  
   114  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesWithExtraAddresses(c *gc.C) {
   115  	ctrl := s.setupMocks(c)
   116  	defer ctrl.Finish()
   117  
   118  	s.expectNICAndBridgeWithIP(ctrl, "eth0", "br-eth0", "1")
   119  	// When we poll the machine, we include any IP addresses that we
   120  	// find. One of them is always the loopback, but we could find any
   121  	// other addresses that someone created on the machine that we
   122  	// don't know what they are.
   123  	s.expectNICWithIP(ctrl, "lo", network.AlphaSpaceId)
   124  	s.expectNICWithIP(ctrl, "ens5", network.AlphaSpaceId)
   125  	s.expectMachineAddressesDevices()
   126  
   127  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: "1"}})
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	c.Check(res, gc.HasLen, 1)
   130  
   131  	defaultDevices, ok := res["1"]
   132  	c.Check(ok, jc.IsTrue)
   133  	c.Check(defaultDevices, gc.HasLen, 1)
   134  	c.Check(defaultDevices[0].Name(), gc.Equals, "br-eth0")
   135  }
   136  
   137  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesInDefaultSpace(c *gc.C) {
   138  	ctrl := s.setupMocks(c)
   139  	defer ctrl.Finish()
   140  
   141  	s.expectNICWithIP(ctrl, "ens4", network.AlphaSpaceId)
   142  	s.expectNICWithIP(ctrl, "ens5", network.AlphaSpaceId)
   143  	s.expectMachineAddressesDevices()
   144  
   145  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: network.AlphaSpaceId}})
   146  	c.Assert(err, jc.ErrorIsNil)
   147  	c.Assert(res, gc.HasLen, 1)
   148  
   149  	devices, ok := res[network.AlphaSpaceId]
   150  	c.Assert(ok, jc.IsTrue)
   151  	c.Assert(devices, gc.HasLen, 2)
   152  	c.Check(devices[0].Name(), gc.Equals, "ens4")
   153  	c.Check(devices[0].Type(), gc.Equals, network.EthernetDevice)
   154  	c.Check(devices[1].Name(), gc.Equals, "ens5")
   155  	c.Check(devices[1].Type(), gc.Equals, network.EthernetDevice)
   156  }
   157  
   158  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesWithUnknown(c *gc.C) {
   159  	ctrl := s.setupMocks(c)
   160  	defer ctrl.Finish()
   161  
   162  	s.expectNICAndBridgeWithIP(ctrl, "ens4", "br-ens4", "1")
   163  	s.expectNICWithIP(ctrl, "ens5", network.AlphaSpaceId)
   164  	s.expectLoopbackNIC(ctrl)
   165  	s.expectMachineAddressesDevices()
   166  
   167  	spaces := network.SpaceInfos{{ID: network.AlphaSpaceId}, {ID: "1"}}
   168  	res, err := linkLayerDevicesForSpaces(s.machine, spaces)
   169  	c.Assert(err, jc.ErrorIsNil)
   170  	c.Assert(res, gc.HasLen, 2)
   171  
   172  	devices, ok := res[network.AlphaSpaceId]
   173  	c.Assert(ok, jc.IsTrue)
   174  	c.Assert(devices, gc.HasLen, 1)
   175  	c.Check(devices[0].Name(), gc.Equals, "ens5")
   176  	c.Check(devices[0].Type(), gc.Equals, network.EthernetDevice)
   177  
   178  	devices, ok = res["1"]
   179  	c.Assert(ok, jc.IsTrue)
   180  	c.Assert(devices, gc.HasLen, 1)
   181  	c.Check(devices[0].Name(), gc.Equals, "br-ens4")
   182  	c.Check(devices[0].Type(), gc.Equals, network.BridgeDevice)
   183  }
   184  
   185  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesWithNoAddress(c *gc.C) {
   186  	ctrl := s.setupMocks(c)
   187  	defer ctrl.Finish()
   188  
   189  	// We create a record for the 'lxdbr0' bridge, but it doesn't have an
   190  	// address yet (which is the case when we first show up on a machine.)
   191  	s.expectBridgeDevice(ctrl, "lxdbr0")
   192  
   193  	s.expectNICWithIP(ctrl, "ens5", network.AlphaSpaceId)
   194  	s.expectMachineAddressesDevices()
   195  
   196  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: network.AlphaSpaceId}})
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	c.Assert(res, gc.HasLen, 1)
   199  
   200  	devices, ok := res[network.AlphaSpaceId]
   201  	c.Assert(ok, jc.IsTrue)
   202  	c.Assert(devices, gc.HasLen, 1)
   203  	names := make([]string, len(devices))
   204  	for i, dev := range devices {
   205  		names[i] = dev.Name()
   206  	}
   207  	c.Check(names, gc.DeepEquals, []string{"ens5"})
   208  }
   209  
   210  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesUnknownIgnoresLoopAndExcludesKnownBridges(c *gc.C) {
   211  	// TODO(jam): 2016-12-28 arguably we should also be aware of Docker
   212  	// devices, possibly the better plan is to look at whether there are
   213  	// routes from the given bridge out into the rest of the world.
   214  	ctrl := s.setupMocks(c)
   215  	defer ctrl.Finish()
   216  
   217  	s.expectNICWithIP(ctrl, "ens3", network.AlphaSpaceId)
   218  	s.expectNICAndBridgeWithIP(ctrl, "ens4", "br-ens4", network.AlphaSpaceId)
   219  	s.expectLoopbackNIC(ctrl)
   220  	s.expectBridgeDevice(ctrl, "lxcbr0")
   221  	s.expectBridgeDevice(ctrl, "lxdbr0")
   222  	s.expectBridgeDevice(ctrl, "virbr0")
   223  	s.expectMachineAddressesDevices()
   224  
   225  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: network.AlphaSpaceId}})
   226  	c.Assert(err, jc.ErrorIsNil)
   227  	c.Assert(res, gc.HasLen, 1)
   228  	devices, ok := res[network.AlphaSpaceId]
   229  	c.Assert(ok, jc.IsTrue)
   230  	names := make([]string, len(devices))
   231  	for i, dev := range devices {
   232  		names[i] = dev.Name()
   233  	}
   234  	c.Check(names, gc.DeepEquals, []string{"br-ens4", "ens3"})
   235  }
   236  
   237  func (s *linkLayerDevForSpacesSuite) TestLinkLayerDevicesForSpacesSortOrder(c *gc.C) {
   238  	ctrl := s.setupMocks(c)
   239  	defer ctrl.Finish()
   240  
   241  	s.expectNICAndBridgeWithIP(ctrl, "eth0", "br-eth0", network.AlphaSpaceId)
   242  	s.setupForNaturalSort(ctrl)
   243  	s.expectMachineAddressesDevices()
   244  
   245  	res, err := linkLayerDevicesForSpaces(s.machine, network.SpaceInfos{{ID: network.AlphaSpaceId}})
   246  	c.Assert(err, jc.ErrorIsNil)
   247  	c.Check(res, gc.HasLen, 1)
   248  	defaultDevices, ok := res[network.AlphaSpaceId]
   249  	c.Check(ok, jc.IsTrue)
   250  	names := make([]string, 0, len(defaultDevices))
   251  	for _, dev := range defaultDevices {
   252  		names = append(names, dev.Name())
   253  	}
   254  	c.Check(names, gc.DeepEquals, []string{
   255  		"br-eth0", "br-eth1", "br-eth1.1", "br-eth1:1", "br-eth10", "br-eth10.2",
   256  	})
   257  }
   258  
   259  type testDev struct {
   260  	name   string
   261  	parent string
   262  }
   263  
   264  func (s *linkLayerDevForSpacesSuite) setupForNaturalSort(ctrl *gomock.Controller) {
   265  	// Add more devices to the "default" space, to make sure the result comes
   266  	// back in NaturallySorted order
   267  	subnet := NewMockSubnet(ctrl)
   268  	sExp := subnet.EXPECT()
   269  	sExp.SpaceID().Return(network.AlphaSpaceId).AnyTimes()
   270  
   271  	testDevs := []testDev{
   272  		{"eth1", "br-eth1"},
   273  		{"eth1.1", "br-eth1.1"},
   274  		{"eth1:1", "br-eth1:1"},
   275  		{"eth10", "br-eth10"},
   276  		{"eth10.2", "br-eth10.2"},
   277  		{"eth2", ""},
   278  		{"eth20", ""},
   279  		{"eth3", ""},
   280  	}
   281  
   282  	for _, d := range testDevs {
   283  		s.expectDevice(ctrl, d.name, d.parent, network.EthernetDevice)
   284  		if d.parent == "" {
   285  			continue
   286  		}
   287  		s.expectBridgeDevice(ctrl, d.parent)
   288  
   289  		address := NewMockAddress(ctrl)
   290  		aExp := address.EXPECT()
   291  		aExp.Subnet().Return(subnet, nil).AnyTimes()
   292  		aExp.DeviceName().Return(d.parent).AnyTimes()
   293  
   294  		s.addresses = append(s.addresses, address)
   295  	}
   296  }
   297  
   298  func (s *linkLayerDevForSpacesSuite) setupMocks(c *gc.C) *gomock.Controller {
   299  	ctrl := gomock.NewController(c)
   300  	s.machine = NewMockContainer(ctrl)
   301  
   302  	return ctrl
   303  }
   304  
   305  func (s *linkLayerDevForSpacesSuite) expectMachineAddressesDevices() {
   306  	mExp := s.machine.EXPECT()
   307  	mExp.AllLinkLayerDevices().Return(s.devices, nil).AnyTimes()
   308  	mExp.AllDeviceAddresses().Return(s.addresses, nil).AnyTimes()
   309  }
   310  
   311  func (s *linkLayerDevForSpacesSuite) expectNICAndBridgeWithIP(ctrl *gomock.Controller, dev, parent, spaceID string) {
   312  	s.expectDevice(ctrl, dev, parent, network.EthernetDevice)
   313  	s.expectBridgeDevice(ctrl, parent)
   314  
   315  	subnet := NewMockSubnet(ctrl)
   316  	sExp := subnet.EXPECT()
   317  	sExp.SpaceID().Return(spaceID).AnyTimes()
   318  
   319  	address := NewMockAddress(ctrl)
   320  	aExp := address.EXPECT()
   321  	aExp.Subnet().Return(subnet, nil).AnyTimes()
   322  	aExp.DeviceName().Return(parent).AnyTimes()
   323  
   324  	s.addresses = append(s.addresses, address)
   325  }
   326  
   327  func (s *linkLayerDevForSpacesSuite) expectNICWithIP(ctrl *gomock.Controller, dev, spaceID string) {
   328  	s.expectDevice(ctrl, dev, "", network.EthernetDevice)
   329  
   330  	subnet := NewMockSubnet(ctrl)
   331  	sExp := subnet.EXPECT()
   332  	sExp.SpaceID().Return(spaceID).AnyTimes()
   333  
   334  	address := NewMockAddress(ctrl)
   335  	aExp := address.EXPECT()
   336  	aExp.Subnet().Return(subnet, nil).AnyTimes()
   337  	aExp.DeviceName().Return(dev).AnyTimes()
   338  
   339  	s.addresses = append(s.addresses, address)
   340  }
   341  
   342  func (s *linkLayerDevForSpacesSuite) expectLoopbackNIC(ctrl *gomock.Controller) {
   343  	s.expectDevice(ctrl, "lo", "", network.LoopbackDevice)
   344  
   345  	address := NewMockAddress(ctrl)
   346  	aExp := address.EXPECT()
   347  	aExp.DeviceName().Return("lo").AnyTimes()
   348  
   349  	s.addresses = append(s.addresses, address)
   350  }
   351  
   352  func (s *linkLayerDevForSpacesSuite) expectBridgeDevice(ctrl *gomock.Controller, dev string) {
   353  	s.expectDevice(ctrl, dev, "", network.BridgeDevice)
   354  }
   355  
   356  func (s *linkLayerDevForSpacesSuite) expectDevice(ctrl *gomock.Controller, dev, parent string, devType network.LinkLayerDeviceType) {
   357  	bridgeDevice := NewMockLinkLayerDevice(ctrl)
   358  	bEXP := bridgeDevice.EXPECT()
   359  	bEXP.Name().Return(dev).AnyTimes()
   360  	bEXP.Type().Return(devType).AnyTimes()
   361  	bEXP.ParentName().Return(parent).AnyTimes()
   362  	s.devices = append(s.devices, bridgeDevice)
   363  }