← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~smoser/cloud-init:fix/smartos-container-nics-have-own-mac into cloud-init:master

 

Scott Moser has proposed merging ~smoser/cloud-init:fix/smartos-container-nics-have-own-mac into cloud-init:master.

Commit message:
SmartOS: fix get_interfaces for nics that do not have addr_assign_type.

When attempting to apply network configuration for SmartOS's container
platform, cloud-init would not identify nics.  The nics on provided
in this container service do not have 'addr_assign_type'.  That
was being interpreted as being a "stolen" mac, and would be filtered
out by get_interfaces.

Requested reviews:
  Mike Gerdts (mgerdts)
  cloud-init commiters (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/343739

see commit message
-- 
Your team cloud-init commiters is requested to review the proposed merge of ~smoser/cloud-init:fix/smartos-container-nics-have-own-mac into cloud-init:master.
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index 8005454..7a54051 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -335,7 +335,7 @@ def interface_has_own_mac(ifname, strict=False):
     assign_type = read_sys_net_int(ifname, "addr_assign_type")
     if strict and assign_type is None:
         raise ValueError("%s had no addr_assign_type.")
-    return assign_type in (0, 1, 3)
+    return assign_type in (0, 1, 3, None)
 
 
 def _get_current_rename_info(check_downable=True):
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index 5364398..b2637af 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -69,8 +69,12 @@ P_DSID_CFG = "etc/cloud/ds-identify.cfg"
 IBM_PROVISIONING_CHECK_PATH = "/root/provisioningConfiguration.cfg"
 IBM_CONFIG_UUID = "9796-932E"
 
+MOCK_VIRT_IS_CONTAINER_OTHER = {'name': 'detect_virt',
+                                'RET': 'container-other', 'ret': 0}
 MOCK_VIRT_IS_KVM = {'name': 'detect_virt', 'RET': 'kvm', 'ret': 0}
 MOCK_VIRT_IS_VMWARE = {'name': 'detect_virt', 'RET': 'vmware', 'ret': 0}
+# currenty' SmartOS hypervisor "bhyve" is unknown by systemd-detect-virt.
+MOCK_VIRT_IS_VM_OTHER = {'name': 'detect_virt', 'RET': 'vm-other', 'ret': 0}
 MOCK_VIRT_IS_XEN = {'name': 'detect_virt', 'RET': 'xen', 'ret': 0}
 MOCK_UNAME_IS_PPC64 = {'name': 'uname', 'out': UNAME_PPC64EL, 'ret': 0}
 
@@ -445,6 +449,14 @@ class TestDsIdentify(CiTestCase):
         """Hetzner cloud is identified in sys_vendor."""
         self._test_ds_found('Hetzner')
 
+    def test_smartos_bhyve(self):
+        """SmartOS cloud identified by SmartDC in dmi."""
+        self._test_ds_found('SmartOS-bhyve')
+
+    def test_smartos_lxbrand(self):
+        """SmartOS cloud identified on lxbrand container."""
+        self._test_ds_found('SmartOS-lxbrand')
+
 
 def blkid_out(disks=None):
     """Convert a list of disk dictionaries into blkid content."""
@@ -677,6 +689,31 @@ VALID_CFG = {
              },
         ],
     },
+    'SmartOS-bhyve': {
+        'ds': 'SmartOS',
+        'mocks': [
+            MOCK_VIRT_IS_VM_OTHER,
+            {'name': 'blkid', 'ret': 0,
+             'out': blkid_out(
+                 [{'DEVNAME': 'vda1', 'TYPE': 'ext4',
+                   'PARTUUID': '49ec635a-01'},
+                  {'DEVNAME': 'vda2', 'TYPE': 'swap',
+                   'LABEL': 'cloudimg-swap', 'PARTUUID': '49ec635a-02'}]),
+             },
+        ],
+        'files': {P_PRODUCT_NAME: 'SmartDC HVM\n'},
+    },
+    'SmartOS-lxbrand': {
+        'ds': 'SmartOS',
+        'mocks': [
+            MOCK_VIRT_IS_CONTAINER_OTHER,
+            {'name': 'uname', 'ret': 0,
+             'out': ("Linux d43da87a-daca-60e8-e6d4-d2ed372662a3 4.3.0 "
+                     "BrandZ virtual linux x86_64 GNU/Linux")},
+            {'name': 'blkid', 'ret': 2, 'out': ''},
+        ],
+    }
+
 }
 
 # vi: ts=4 expandtab
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index c12a487..6ef4b88 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -2,12 +2,9 @@
 
 from cloudinit import net
 from cloudinit.net import cmdline
-from cloudinit.net import eni
-from cloudinit.net import natural_sort_key
-from cloudinit.net import netplan
-from cloudinit.net import network_state
-from cloudinit.net import renderers
-from cloudinit.net import sysconfig
+from cloudinit.net import (
+    eni, interface_has_own_mac, natural_sort_key, netplan, network_state,
+    renderers, sysconfig)
 from cloudinit.sources.helpers import openstack
 from cloudinit import temp_utils
 from cloudinit import util
@@ -2569,6 +2566,43 @@ class TestGetInterfaces(CiTestCase):
             any_order=True)
 
 
+class TestInterfaceHasOwnMac(CiTestCase):
+    """Test interface_has_own_mac.  This is admittedly a bit whitebox."""
+
+    @mock.patch('cloudinit.net.read_sys_net_int', return_value=None)
+    def test_non_strict_with_no_addr_assign_type(self, m_read_sys_net_int):
+        """If nic does not have addr_assign_type, it is not "stolen".
+
+        SmartOS containers do not provide the addr_assign_type in /sys.
+
+            $ ( cd /sys/class/net/eth0/ && grep -r . *)
+            address:90:b8:d0:20:e1:b0
+            addr_len:6
+            flags:0x1043
+            ifindex:2
+            mtu:1500
+            tx_queue_len:1
+            type:1
+        """
+        self.assertTrue(interface_has_own_mac("eth0"))
+
+    @mock.patch('cloudinit.net.read_sys_net_int', return_value=None)
+    def test_strict_with_no_addr_assign_type_raises(self, m_read_sys_net_int):
+        with self.assertRaises(ValueError):
+            interface_has_own_mac("eth0", True)
+
+    @mock.patch('cloudinit.net.read_sys_net_int')
+    def test_expected_values(self, m_read_sys_net_int):
+        msg = "address_assign_type=%d said to not have own mac"
+        for address_assign_type in (0, 1, 3):
+            m_read_sys_net_int.return_value = address_assign_type
+            self.assertTrue(
+                interface_has_own_mac("eth0", msg % address_assign_type))
+
+        m_read_sys_net_int.return_value = 2
+        self.assertFalse(interface_has_own_mac("eth0"))
+
+
 class TestGetInterfacesByMac(CiTestCase):
     _data = {'bonds': ['bond1'],
              'bridges': ['bridge1'],
diff --git a/tools/ds-identify b/tools/ds-identify
index 9a2db5c..58f6d72 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -258,7 +258,7 @@ read_virt() {
 
 is_container() {
     case "${DI_VIRT}" in
-        lxc|lxc-libvirt|systemd-nspawn|docker|rkt) return 0;;
+        container-other|lxc|lxc-libvirt|systemd-nspawn|docker|rkt) return 0;;
         *) return 1;;
     esac
 }
@@ -974,8 +974,8 @@ dscheck_SmartOS() {
     local smartdc_kver="BrandZ virtual linux"
     dmi_product_name_matches "SmartDC*" && return $DS_FOUND
     if [ "${DI_UNAME_KERNEL_VERSION}" = "${smartdc_kver}" ] &&
-       [ "${DI_VIRT}" = "container-other" ]; then
-       return ${DS_FOUND}
+        [ "${DI_VIRT}" = "container-other" ]; then
+        return ${DS_FOUND}
     fi
     return ${DS_NOT_FOUND}
 }