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 }