// SetContainerLinkLayerDevices sets the link-layer devices of the given // containerMachine, setting each device linked to the corresponding // BridgeDevice of the host machine m. func (m *Machine) SetContainerLinkLayerDevices(containerMachine *Machine) error { allDevices, err := m.AllLinkLayerDevices() if err != nil { return errors.Annotate(err, "cannot get host machine devices") } bridgeDevicesByName := make(map[string]*LinkLayerDevice) bridgeDeviceNames := make([]string, 0, len(allDevices)) for _, hostDevice := range allDevices { deviceType, name := hostDevice.Type(), hostDevice.Name() // Since the default bridges (for each container type) are // machine-local, and there's neither a way (at least not yet) nor any // point in allocating addresses from the (machine-local) subnets // configured on those bridges, we need to ignore them below. if deviceType == BridgeDevice { switch name { case container.DefaultLxdBridge, container.DefaultKvmBridge: logger.Debugf("skipping host bridge %q", name) continue } bridgeDevicesByName[name] = hostDevice bridgeDeviceNames = append(bridgeDeviceNames, name) } } sortedBridgeDeviceNames := network.NaturallySortDeviceNames(bridgeDeviceNames...) logger.Debugf("using host machine %q bridge devices: %v", m.Id(), sortedBridgeDeviceNames) containerDevicesArgs := make([]LinkLayerDeviceArgs, len(bridgeDeviceNames)) for i, hostBridgeName := range sortedBridgeDeviceNames { hostBridge := bridgeDevicesByName[hostBridgeName] containerDevicesArgs[i] = LinkLayerDeviceArgs{ Name: fmt.Sprintf("eth%d", i), Type: EthernetDevice, MACAddress: generateMACAddress(), MTU: hostBridge.MTU(), IsUp: true, IsAutoStart: true, ParentName: hostBridge.globalKey(), } } logger.Debugf("prepared container %q network config: %+v", containerMachine.Id(), containerDevicesArgs) if err := containerMachine.SetLinkLayerDevices(containerDevicesArgs...); err != nil { return errors.Trace(err) } logger.Debugf("container %q network config set", containerMachine.Id()) return nil }
func (*DeviceNamesSuite) TestNaturallySortDeviceNames(c *gc.C) { for i, test := range []struct { message string input []string expected []string }{{ message: "empty input, empty output", input: []string{}, expected: []string{}, }, { message: "nil input, nil output", }, { message: "one input", input: []string{"a"}, expected: []string{"a"}, }, { message: "two values, no numbers", input: []string{"b", "a"}, expected: []string{"a", "b"}, }, { message: "two values, mixed content", input: []string{"b1", "a1"}, expected: []string{"a1", "b1"}, }, { message: "identical values, numbers only", input: []string{"1", "1", "1", "1"}, expected: []string{"1", "1", "1", "1"}, }, { message: "identical values, mixed content", input: []string{"a1", "a1", "a1", "a1"}, expected: []string{"a1", "a1", "a1", "a1"}, }, { message: "reversed input", input: []string{"a10", "a9", "a8", "a7", "a6", "a5", "a4", "a3", "a2", "a1", "a0"}, expected: []string{"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10"}, }, { message: "multiple numbers per value", input: []string{"a10.11", "a10.10", "a10.1"}, expected: []string{"a10.1", "a10.10", "a10.11"}, }, { message: "value with leading zero", input: []string{"a50", "a51.", "a50.31", "a50.4", "a5.034e1", "a50.300"}, expected: []string{"a5.034e1", "a50", "a50.4", "a50.31", "a50.300", "a51."}, }, { message: "value with multiple leading zeros", input: []string{"a50", "a51.", "a0050.31", "a50.4", "a5.034e1", "a00050.300"}, expected: []string{"a00050.300", "a0050.31", "a5.034e1", "a50", "a50.4", "a51."}, }, { message: "strings with numbers in ascending order", input: []string{"a2", "a5", "a9", "a1", "a4", "a10", "a6"}, expected: []string{"a1", "a2", "a4", "a5", "a6", "a9", "a10"}, }, { message: "values that look like version numbers", input: []string{"1.9.9a", "1.11", "1.9.9b", "1.11.4", "1.10.1"}, expected: []string{"1.9.9a", "1.9.9b", "1.10.1", "1.11", "1.11.4"}, }, { message: "bridge device names", input: []string{"br-eth10", "br-eth2", "br-eth1"}, expected: []string{"br-eth1", "br-eth2", "br-eth10"}, }, { message: "bridge device names with VLAN numbers", input: []string{"br-eth10.10", "br-eth2.10", "br-eth200", "br-eth1.100", "br-eth1.10"}, expected: []string{"br-eth1.10", "br-eth1.100", "br-eth2.10", "br-eth10.10", "br-eth200"}, }, { message: "bridge device names with leading zero", input: []string{"br-eth0", "br-eth10.10", "br-eth2.10", "br-eth1.100", "br-eth1.10", "br-eth10"}, expected: []string{"br-eth0", "br-eth1.10", "br-eth1.100", "br-eth2.10", "br-eth10", "br-eth10.10"}, }} { c.Logf("%v: %s", i, test.message) result := network.NaturallySortDeviceNames(test.input...) c.Assert(result, gc.HasLen, len(test.input)) c.Assert(result, gc.DeepEquals, test.expected) } }