diff --git a/cloud-init-handle-no-carrier.patch b/cloud-init-handle-no-carrier.patch new file mode 100644 index 0000000..7727a72 --- /dev/null +++ b/cloud-init-handle-no-carrier.patch @@ -0,0 +1,210 @@ +--- 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, diff --git a/cloud-init.changes b/cloud-init.changes index c139ab1..6a73f21 100644 --- a/cloud-init.changes +++ b/cloud-init.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Tue Oct 11 15:42:35 UTC 2016 - rjschwei@suse.com + +- Add cloud-init-handle-no-carrier.patch (boo#1003977) + - Handle the exception when attempting to detect if the network + device is up when it is not + ------------------------------------------------------------------- Mon Oct 10 20:28:47 UTC 2016 - rjschwei@suse.com diff --git a/cloud-init.spec b/cloud-init.spec index 3f562c7..e0b6fc0 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -45,6 +45,8 @@ Patch20: cloud-init-python2-sigpipe.patch Patch21: cloud-init-net-eni.patch Patch22: cloud-init-service.patch Patch23: cloud-init-fix-unicode-handling-binarydecode.patch +# From upstream patch +Patch24: cloud-init-handle-no-carrier.patch BuildRequires: fdupes BuildRequires: filesystem BuildRequires: python-devel @@ -149,6 +151,7 @@ Unit tests for the cloud-init tools %patch21 %patch22 %patch23 +%patch24 %if 0%{?suse_version} <= 1130 # disable ecdsa for SLE 11 (not available)