From 8c94a0fd5df6469855affb053d13dcc84dd79991 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 10 Jan 2017 12:34:25 -0500 Subject: ConfigDrive: when interfaces provided, bounce interfaces. When ConfigDrive provides a /etc/network/interfaces file, cloud-init would place that file into /etc/network/interfaces and the call 'ifup -a'. That is problematic as there is a race on built-in configuration versus the newly provided config. To fix that, before writing the new config, bring down all interfaces. There is still a potential race with hotplug between bringing down the interface and the new file getting written. Additionally, if an interfaces file is provided, remove one written by the image build process in Ubuntu (/etc/network/interfaces.d/eth0.cfg). if it had known-content LP: #1315501 diff --git a/debian/patches/lp-1315501-openstack-interfaces-bounce.patch b/debian/patches/lp-1315501-openstack-interfaces-bounce.patch new file mode 100644 index 0000000..22d6c15 --- /dev/null +++ b/debian/patches/lp-1315501-openstack-interfaces-bounce.patch @@ -0,0 +1,72 @@ +Author: Scott Moser +Bug: https://bugs.launchpad.net/bugs/1315501 +Applied-Upstream: yes +Description: ConfigDrive: when interfaces provided, bounce interfaces. + When ConfigDrive provides a /etc/network/interfaces file, cloud-init + would place that file into /etc/network/interfaces and the call 'ifup -a'. + That is problematic as there is a race on built-in configuration versus + the newly provided config. + . + To fix that, before writing the new config, bring down all interfaces. + There is still a potential race with hotplug between bringing down the + interface and the new file getting written. + . + Additionally, if an interfaces file is provided, remove one written by + the image build process in Ubuntu (/etc/network/interfaces.d/eth0.cfg). + if it had known-content +--- a/cloudinit/sources/DataSourceConfigDrive.py ++++ b/cloudinit/sources/DataSourceConfigDrive.py +@@ -201,6 +201,15 @@ def on_first_boot(data, distro=None): + net_conf = data.get("network_config", '') + if net_conf and distro: + LOG.debug("Updating network interfaces from config drive") ++ if util.which('ifdown'): ++ try: ++ util.subp(['ifdown', '--all', '--exclude=lo']) ++ except util.ProcessExecutionError as e: ++ util.logexc(LOG, ++ "Failed to bring interfaces down in preparation " ++ "for applying network.") ++ _maybe_remove_legacy_eth0() ++ + distro.apply_network(net_conf) + files = data.get('files', {}) + if files: +@@ -262,6 +271,37 @@ def find_candidate_devs(probe_optical=Tr + return devices + + ++def _maybe_remove_legacy_eth0(path="/etc/network/interfaces.d/eth0.cfg"): ++ """Ubuntu cloud images previously included a 'eth0.cfg' that had ++ hard coded content. That file would interfere with the rendered ++ configuration if it was present. ++ ++ if the file does not exist do nothing. ++ If the file exists: ++ - with known content, remove it and warn ++ - with unknown content, leave it and warn ++ """ ++ ++ if not os.path.exists(path): ++ return ++ ++ bmsg = "Dynamic networking config may not apply." ++ try: ++ contents = util.load_file(path) ++ known_contents = ["auto eth0", "iface eth0 inet dhcp"] ++ lines = [f.strip() for f in contents.splitlines() ++ if not f.startswith("#")] ++ if lines == known_contents: ++ util.del_file(path) ++ msg = "removed %s with known contents" % path ++ else: ++ msg = (bmsg + " '%s' exists with user configured content." % path) ++ except Exception: ++ msg = bmsg + " %s exists, but could not be read." % path ++ ++ LOG.warn(msg) ++ ++ + # Used to match classes to dependencies + datasources = [ + (DataSourceConfigDrive, (sources.DEP_FILESYSTEM, )), diff --git a/debian/patches/series b/debian/patches/series index d20f78b..dbf0eba 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -24,3 +24,4 @@ lp-1551419-azure-handle-flipped-uuid-endianness.patch lp-1553158-bigstep.patch lp-1581200-gce-metadatafqdn.patch lp-1603222-fix-ephemeral-disk-fstab.patch +lp-1315501-openstack-interfaces-bounce.patch -- cgit v0.10.2