File cloud-init-handle-no-carrier.patch of Package cloud-init.4242

--- cloudinit/net/__init__.py.orig
+++ cloudinit/net/__init__.py
@@ -33,10 +33,12 @@ def sys_dev_path(devname, path=""):
 
 
 def read_sys_net(devname, path, translate=None, enoent=None, keyerror=None):
+    dev_path = sys_dev_path(devname, path)
     try:
-        contents = util.load_file(sys_dev_path(devname, path))
+        contents = util.load_file(dev_path)
     except (OSError, IOError) as e:
-        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
+        e_errno = getattr(e, 'errno', None)
+	if e_errno in (errno.ENOENT, errno.ENOTDIR):
             if enoent is not None:
                 return enoent
         raise
@@ -109,24 +111,9 @@ def is_disabled_cfg(cfg):
     return cfg.get('config') == "disabled"
 
 
-def sys_netdev_info(name, field):
-    if not os.path.exists(os.path.join(SYS_CLASS_NET, name)):
-        raise OSError("%s: interface does not exist in %s" %
-                      (name, SYS_CLASS_NET))
-    fname = os.path.join(SYS_CLASS_NET, name, field)
-    if not os.path.exists(fname):
-        raise OSError("%s: could not find sysfs entry: %s" % (name, fname))
-    data = util.load_file(fname)
-    if data[-1] == '\n':
-        data = data[:-1]
-    return data
-
-
 def generate_fallback_config():
     """Determine which attached net dev is most likely to have a connection and
        generate network state to run dhcp on that interface"""
-    # by default use eth0 as primary interface
-    nconf = {'config': [], 'version': 1}
 
     # get list of interfaces that could have connections
     invalid_interfaces = set(['lo'])
@@ -143,28 +130,30 @@ def generate_fallback_config():
             # skip any bridges
             continue
         try:
-            carrier = int(sys_netdev_info(interface, 'carrier'))
+            carrier = read_sys_net(interface, 'carrier', enoent=False)
             if carrier:
+                carrier = int(carrier)
                 connected.append(interface)
                 continue
-        except OSError:
+        except (IOError, OSError, TypeError):
             pass
         # check if nic is dormant or down, as this may make a nick appear to
         # not have a carrier even though it could acquire one when brought
         # online by dhclient
         try:
-            dormant = int(sys_netdev_info(interface, 'dormant'))
+            dormant = read_sys_net(interface, 'dormant', enoent=False)
             if dormant:
+                domant = int(dormant)
                 possibly_connected.append(interface)
                 continue
-        except OSError:
+        except (IOError, OSError, TypeError):
             pass
         try:
-            operstate = sys_netdev_info(interface, 'operstate')
+            operstate = read_sys_net(interface, 'operstate', enoent=False)
             if operstate in ['dormant', 'down', 'lowerlayerdown', 'unknown']:
                 possibly_connected.append(interface)
                 continue
-        except OSError:
+        except (IOError, OSError):
             pass
 
     # don't bother with interfaces that might not be connected if there are
@@ -173,23 +162,29 @@ def generate_fallback_config():
         potential_interfaces = connected
     else:
         potential_interfaces = possibly_connected
-    # if there are no interfaces, give up
-    if not potential_interfaces:
-        return
+
     # if eth0 exists use it above anything else, otherwise get the interface
-    # that looks 'first'
-    if DEFAULT_PRIMARY_INTERFACE in potential_interfaces:
-        name = DEFAULT_PRIMARY_INTERFACE
+    # that we can read 'first' (using the sorted defintion of first).
+    names = [DEFAULT_PRIMARY_INTERFACE]
+    names.extend(sorted(potential_interfaces))
+    target_name = None
+    target_mac = None
+    for name in names:
+        if name not in potential_interfaces:
+            continue
+        mac = read_sys_net(name, 'address', enoent=False)
+	if mac:
+            target_name = name
+	    target_mac = mac
+	    break
+    if target_mac and target_name:
+        nconf = {'config': [], 'version': 1}
+	nconf['config'].append(
+            {'type': 'physical', 'name': target_name,
+	     'mac_address': target_mac, 'subnets': [{'type': 'dhcp'}]})
+	return nconf
     else:
-        name = sorted(potential_interfaces)[0]
-
-    mac = sys_netdev_info(name, 'address')
-    target_name = name
-
-    nconf['config'].append(
-        {'type': 'physical', 'name': target_name,
-         'mac_address': mac, 'subnets': [{'type': 'dhcp'}]})
-    return nconf
+        return None
 
 
 def apply_network_config_names(netcfg, strict_present=True, strict_busy=True):
--- cloudinit/net/cmdline.py.orig
+++ cloudinit/net/cmdline.py
@@ -26,7 +26,7 @@ import sys
 import six
 
 from . import get_devicelist
-from . import sys_netdev_info
+from . import read_sys_net
 
 from cloudinit import util
 
@@ -197,7 +197,10 @@ def read_kernel_cmdline_config(files=Non
         return None
 
     if mac_addrs is None:
-        mac_addrs = dict((k, sys_netdev_info(k, 'address'))
-                         for k in get_devicelist())
+        mac_addrs = {}
+	for k in get_devicelist():
+            mac_addr = read_sys_net(k, 'address', enoent=False)
+	    if mac_addr:
+                mac_addrs[k] = mac_addr
 
     return config_from_klibc_net_cfg(files=files, mac_addrs=mac_addrs)
--- tests/unittests/test_net.py.orig
+++ tests/unittests/test_net.py
@@ -422,7 +422,7 @@ pre-down route del -net 10.0.0.0 netmask
 }
 
 
-def _setup_test(tmp_dir, mock_get_devicelist, mock_sys_netdev_info,
+def _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net,
                 mock_sys_dev_path):
     mock_get_devicelist.return_value = ['eth1000']
     dev_characteristics = {
@@ -435,10 +435,10 @@ def _setup_test(tmp_dir, mock_get_device
         }
     }
 
-    def netdev_info(name, field):
+    def fake_read(devname, path, translate=None, enoent=None, keyerror=None):
         return dev_characteristics[name][field]
 
-    mock_sys_netdev_info.side_effect = netdev_info
+    mock_read_sys_net.side_effect = fake_read
 
     def sys_dev_path(devname, path=""):
         return tmp_dir + devname + "/" + path
@@ -454,15 +454,15 @@ def _setup_test(tmp_dir, mock_get_device
 class TestSysConfigRendering(TestCase):
 
     @mock.patch("cloudinit.net.sys_dev_path")
-    @mock.patch("cloudinit.net.sys_netdev_info")
+    @mock.patch("cloudinit.net.read_sys_net")
     @mock.patch("cloudinit.net.get_devicelist")
     def test_default_generation(self, mock_get_devicelist,
-                                mock_sys_netdev_info,
+                                mock_read_sys_net,
                                 mock_sys_dev_path):
         tmp_dir = tempfile.mkdtemp()
         self.addCleanup(shutil.rmtree, tmp_dir)
         _setup_test(tmp_dir, mock_get_devicelist,
-                    mock_sys_netdev_info, mock_sys_dev_path)
+                    mock_read_sys_net, mock_sys_dev_path)
 
         network_cfg = net.generate_fallback_config()
         ns = network_state.parse_net_config_data(network_cfg,
@@ -511,15 +511,15 @@ USERCTL=no
 class TestEniNetRendering(TestCase):
 
     @mock.patch("cloudinit.net.sys_dev_path")
-    @mock.patch("cloudinit.net.sys_netdev_info")
+    @mock.patch("cloudinit.net.read_sys_net")
     @mock.patch("cloudinit.net.get_devicelist")
     def test_default_generation(self, mock_get_devicelist,
-                                mock_sys_netdev_info,
+                                mock_read_sys_net,
                                 mock_sys_dev_path):
         tmp_dir = tempfile.mkdtemp()
         self.addCleanup(shutil.rmtree, tmp_dir)
         _setup_test(tmp_dir, mock_get_devicelist,
-                    mock_sys_netdev_info, mock_sys_dev_path)
+                    mock_read_sys_net, mock_sys_dev_path)
 
         network_cfg = net.generate_fallback_config()
         ns = network_state.parse_net_config_data(network_cfg,
openSUSE Build Service is sponsored by