From 152b453122b44aa18144f52ada816aa46c7265ddcb845430cc976e216a43b539 Mon Sep 17 00:00:00 2001 From: Robert Schweikert Date: Thu, 16 Jan 2020 12:06:38 +0000 Subject: [PATCH 1/3] =?UTF-8?q?-=20Update=20to=20version=2019.4=20=20=20+?= =?UTF-8?q?=20Remove=20patches=20included=20upstream:=20=20=20=20=20-=20cl?= =?UTF-8?q?oud-init-after-wicked.patch=20=20=20=20=20-=20cloud-init-noreso?= =?UTF-8?q?lv-merge-no-dns-data.diff=20=20=20=20=20-=20cloud-init-renderer?= =?UTF-8?q?-detect.patch=20=20=20=20=20-=20cloud-init-trigger-udev.patch?= =?UTF-8?q?=20=20=20+=20Removed=20patches=20merged=20with=20cloud-init-mix?= =?UTF-8?q?-static-dhcp.patch=20=20=20=20=20-=20cloud-init-proper-ipv6-set?= =?UTF-8?q?ting.patch=20=20=20=20=20-=20cloud-init-static-net.patch=20=20?= =?UTF-8?q?=20+=20Added=20cloud-init-mix-static-dhcp.patch=20(bsc#1157894)?= =?UTF-8?q?=20=20=20+=20Forward=20port=20cloud-init-sysconf-path.patch=20?= =?UTF-8?q?=20=20+=20doc:=20specify=20=5F=20over=20-=20in=20cloud=20config?= =?UTF-8?q?=20modules=20=20=20+=20[Joshua=20Powers]=20(LP:=20#1293254)=20?= =?UTF-8?q?=20=20+=20tools:=20Detect=20python=20to=20use=20via=20env=20in?= =?UTF-8?q?=20migrate-lp-user-to-github=20=20=20+=20[Adam=20Dobrawy]=20=20?= =?UTF-8?q?=20+=20Partially=20revert=20"fix=20unlocking=20method=20on=20Fr?= =?UTF-8?q?eeBSD"=20(#116)=20=20=20+=20tests:=20mock=20uid=20when=20runnin?= =?UTF-8?q?g=20as=20root=20(#113)=20=20=20+=20[Joshua=20Powers]=20(LP:=20#?= =?UTF-8?q?1856096)=20=20=20+=20cloudinit/netinfo:=20remove=20unused=20get?= =?UTF-8?q?gateway=20(#111)=20=20=20+=20docs:=20clear=20up=20apt=20config?= =?UTF-8?q?=20sections=20(#107)=20[Joshua=20Powers]=20(LP:=20#1832823)=20?= =?UTF-8?q?=20=20+=20doc:=20add=20kernel=20command=20line=20option=20to=20?= =?UTF-8?q?user=20data=20(#105)=20=20=20+=20[Joshua=20Powers]=20(LP:=20#18?= =?UTF-8?q?46524)=20=20=20+=20config/cloud.cfg.d:=20update=20README=20[Jos?= =?UTF-8?q?hua=20Powers]=20(LP:=20#1855006)=20=20=20+=20azure:=20avoid=20r?= =?UTF-8?q?e-running=20cloud-init=20when=20instance-id=20is=20byte-swapped?= =?UTF-8?q?=20=20=20+=20(#84)=20[AOhassan]=20=20=20+=20fix=20unlocking=20m?= =?UTF-8?q?ethod=20on=20FreeBSD=20[Igor=20Gali=C4=87]=20(LP:=20#1854594)?= =?UTF-8?q?=20=20=20+=20debian:=20add=20reference=20to=20the=20manpages=20?= =?UTF-8?q?[Joshua=20Powers]=20=20=20+=20ds=5Fidentify:=20if=20/sys=20is?= =?UTF-8?q?=20not=20available=20use=20dmidecode=20(#42)=20=20=20+=20[Igor?= =?UTF-8?q?=20Gali=C4=87]=20(LP:=20#1852442)=20=20=20+=20docs:=20add=20clo?= =?UTF-8?q?ud-id=20manpage=20[Joshua=20Powers]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OBS-URL: https://build.opensuse.org/package/show/Cloud:Tools/cloud-init?expand=0&rev=158 --- cloud-init-19.2.tar.gz | 3 - cloud-init-19.4.tar.gz | 3 + cloud-init-after-wicked.patch | 13 - cloud-init-mix-static-dhcp.patch | 1660 ++++++++++++++++++++ cloud-init-noresolv-merge-no-dns-data.diff | 68 - cloud-init-proper-ipv6-setting.patch | 10 - cloud-init-renderer-detect.patch | 20 - cloud-init-static-net.patch | 12 - cloud-init-sysconf-path.patch | 8 +- cloud-init-trigger-udev.patch | 36 - cloud-init.changes | 189 +++ cloud-init.spec | 45 +- 12 files changed, 1873 insertions(+), 194 deletions(-) delete mode 100644 cloud-init-19.2.tar.gz create mode 100644 cloud-init-19.4.tar.gz delete mode 100644 cloud-init-after-wicked.patch create mode 100644 cloud-init-mix-static-dhcp.patch delete mode 100644 cloud-init-noresolv-merge-no-dns-data.diff delete mode 100644 cloud-init-proper-ipv6-setting.patch delete mode 100644 cloud-init-renderer-detect.patch delete mode 100644 cloud-init-static-net.patch delete mode 100644 cloud-init-trigger-udev.patch diff --git a/cloud-init-19.2.tar.gz b/cloud-init-19.2.tar.gz deleted file mode 100644 index c349620..0000000 --- a/cloud-init-19.2.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5ead1b3c782c159669f8f8779c45d16a986c7405425d75f915ec55301d83a07 -size 1028832 diff --git a/cloud-init-19.4.tar.gz b/cloud-init-19.4.tar.gz new file mode 100644 index 0000000..b560ef2 --- /dev/null +++ b/cloud-init-19.4.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2c1f318cbfb28c13b41bbb0de5ab9b21d7cf4b7118551366cd508380124f262 +size 1091893 diff --git a/cloud-init-after-wicked.patch b/cloud-init-after-wicked.patch deleted file mode 100644 index 4c08a41..0000000 --- a/cloud-init-after-wicked.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: cloud-init-19.1/systemd/cloud-init.service.tmpl -=================================================================== ---- cloud-init-19.1.orig/systemd/cloud-init.service.tmpl -+++ cloud-init-19.1/systemd/cloud-init.service.tmpl -@@ -14,7 +14,7 @@ After=networking.service - After=network.service - {% endif %} - {% if variant in ["suse"] %} --Before=wicked.service -+After=wicked.service - # setting hostname via hostnamectl depends on dbus, which otherwise - # would not be guaranteed at this point. - After=dbus.service diff --git a/cloud-init-mix-static-dhcp.patch b/cloud-init-mix-static-dhcp.patch new file mode 100644 index 0000000..48f0a6f --- /dev/null +++ b/cloud-init-mix-static-dhcp.patch @@ -0,0 +1,1660 @@ +From 263d8be627431001b8fd27d520340f280ed2d5f9 Mon Sep 17 00:00:00 2001 +From: Robert Schweikert +Date: Thu, 9 Jan 2020 14:47:46 -0500 +Subject: [PATCH] - Handle different values for the common BOOTPROTO + configuration option + Introduce the "flavor" configuration option for the + sysconfig renderer this is necessary to account for differences in the + handling of the BOOTPROTO setting between distributions (lp#1858808) + + Thanks to Petr Pavlu for the idea - Network config clean up for sysconfig + renderer + The introduction of the "flavor" renderer configuration allows + us to only write values that are pertinent for the given distro - Set the + DHCPv6 client mode on SUSE (lp#1800854) + +--- + cloudinit/distros/opensuse.py | 1 + + cloudinit/net/sysconfig.py | 295 ++++++++++++------ + tests/unittests/test_distros/test_netconfig.py | 39 +-- + tests/unittests/test_net.py | 405 +++++++++++++++---------- + 4 files changed, 450 insertions(+), 290 deletions(-) + +--- cloudinit/distros/opensuse.py.orig ++++ cloudinit/distros/opensuse.py +@@ -38,6 +38,7 @@ class Distro(distros.Distro): + renderer_configs = { + 'sysconfig': { + 'control': 'etc/sysconfig/network/config', ++ 'flavor': 'suse', + 'iface_templates': '%(base)s/network/ifcfg-%(name)s', + 'netrules_path': ( + 'etc/udev/rules.d/85-persistent-net-cloud-init.rules'), +--- cloudinit/net/sysconfig.py.orig ++++ cloudinit/net/sysconfig.py +@@ -86,6 +86,9 @@ class ConfigMap(object): + def __getitem__(self, key): + return self._conf[key] + ++ def get(self, key): ++ return self._conf.get(key, None) ++ + def __contains__(self, key): + return key in self._conf + +@@ -269,11 +272,15 @@ class Renderer(renderer.Renderer): + # s1-networkscripts-interfaces.html (or other docs for + # details about this) + +- iface_defaults = tuple([ ++ iface_defaults_rh = tuple([ + ('ONBOOT', True), + ('USERCTL', False), + ('NM_CONTROLLED', False), + ('BOOTPROTO', 'none'), ++ ]) ++ ++ iface_defaults_suse = tuple([ ++ ('BOOTPROTO', 'static'), + ('STARTMODE', 'auto'), + ]) + +@@ -297,12 +304,18 @@ class Renderer(renderer.Renderer): + ('bond_primary_reselect', "primary_reselect=%s"), + ]) + +- bridge_opts_keys = tuple([ ++ bridge_opts_keys_rh = tuple([ + ('bridge_stp', 'STP'), + ('bridge_ageing', 'AGEING'), + ('bridge_bridgeprio', 'PRIO'), + ]) + ++ bridge_opts_keys_suse = tuple([ ++ ('bridge_stp', 'BRIDGE_STP'), ++ ('bridge_ageing', 'BRIDGE_AGEINGTIME'), ++ ('bridge_bridgeprio', 'BRIDGE_PRIORITY'), ++ ]) ++ + templates = {} + + def __init__(self, config=None): +@@ -320,13 +333,21 @@ class Renderer(renderer.Renderer): + 'iface_templates': config.get('iface_templates'), + 'route_templates': config.get('route_templates'), + } ++ self.flavor = config.get('flavor', 'rh') + + @classmethod +- def _render_iface_shared(cls, iface, iface_cfg): +- for k, v in cls.iface_defaults: ++ def _render_iface_shared(cls, iface, iface_cfg, flavor): ++ if flavor == 'suse': ++ iface_defaults = cls.iface_defaults_suse ++ mac_map = ('mac_address', 'LLADDR') ++ else: ++ iface_defaults = cls.iface_defaults_rh ++ mac_map = ('mac_address', 'HWADDR') ++ ++ for k, v in iface_defaults: + iface_cfg[k] = v + +- for (old_key, new_key) in [('mac_address', 'HWADDR'), ('mtu', 'MTU')]: ++ for (old_key, new_key) in [mac_map, ('mtu', 'MTU')]: + old_value = iface.get(old_key) + if old_value is not None: + # only set HWADDR on physical interfaces +@@ -335,50 +356,86 @@ class Renderer(renderer.Renderer): + continue + iface_cfg[new_key] = old_value + +- if iface['accept-ra'] is not None: ++ if iface['accept-ra'] is not None and flavor != 'suse': + iface_cfg['IPV6_FORCE_ACCEPT_RA'] = iface['accept-ra'] + + @classmethod +- def _render_subnets(cls, iface_cfg, subnets, has_default_route): ++ def _render_subnets(cls, iface_cfg, subnets, has_default_route, flavor): + # setting base values +- iface_cfg['BOOTPROTO'] = 'none' ++ if flavor == 'suse': ++ iface_cfg['BOOTPROTO'] = 'static' ++ if 'BRIDGE' in iface_cfg: ++ iface_cfg['BOOTPROTO'] = 'dhcp' ++ iface_cfg.drop('BRIDGE') ++ else: ++ iface_cfg['BOOTPROTO'] = 'none' + + # modifying base values according to subnets + for i, subnet in enumerate(subnets, start=len(iface_cfg.children)): + mtu_key = 'MTU' + subnet_type = subnet.get('type') + if subnet_type == 'dhcp6' or subnet_type == 'ipv6_dhcpv6-stateful': +- # TODO need to set BOOTPROTO to dhcp6 on SUSE +- iface_cfg['IPV6INIT'] = True +- # Configure network settings using DHCPv6 +- iface_cfg['DHCPV6C'] = True ++ if flavor == 'suse': ++ # User wants dhcp for both protocols ++ if iface_cfg['BOOTPROTO'] == 'dhcp4': ++ iface_cfg['BOOTPROTO'] = 'dhcp' ++ else: ++ # Only IPv6 is DHCP, IPv4 may be static ++ iface_cfg['BOOTPROTO'] = 'dhcp6' ++ iface_cfg['DHCLIENT6_MODE'] = 'managed' ++ else: ++ iface_cfg['IPV6INIT'] = True ++ # Configure network settings using DHCPv6 ++ iface_cfg['DHCPV6C'] = True + elif subnet_type == 'ipv6_dhcpv6-stateless': +- iface_cfg['IPV6INIT'] = True +- # Configure network settings using SLAAC from RAs and optional +- # info from dhcp server using DHCPv6 +- iface_cfg['IPV6_AUTOCONF'] = True +- iface_cfg['DHCPV6C'] = True +- # Use Information-request to get only stateless configuration +- # parameters (i.e., without address). +- iface_cfg['DHCPV6C_OPTIONS'] = '-S' ++ if flavor == 'suse': ++ # User wants dhcp for both protocols ++ if iface_cfg['BOOTPROTO'] == 'dhcp4': ++ iface_cfg['BOOTPROTO'] = 'dhcp' ++ else: ++ # Only IPv6 is DHCP, IPv4 may be static ++ iface_cfg['BOOTPROTO'] = 'dhcp6' ++ iface_cfg['DHCLIENT6_MODE'] = 'info' ++ else: ++ iface_cfg['IPV6INIT'] = True ++ # Configure network settings using SLAAC from RAs and ++ # optional info from dhcp server using DHCPv6 ++ iface_cfg['IPV6_AUTOCONF'] = True ++ iface_cfg['DHCPV6C'] = True ++ # Use Information-request to get only stateless ++ # configuration parameters (i.e., without address). ++ iface_cfg['DHCPV6C_OPTIONS'] = '-S' + elif subnet_type == 'ipv6_slaac': +- iface_cfg['IPV6INIT'] = True +- # Configure network settings using SLAAC from RAs +- iface_cfg['IPV6_AUTOCONF'] = True ++ if flavor == 'suse': ++ # User wants dhcp for both protocols ++ if iface_cfg['BOOTPROTO'] == 'dhcp4': ++ iface_cfg['BOOTPROTO'] = 'dhcp' ++ else: ++ # Only IPv6 is DHCP, IPv4 may be static ++ iface_cfg['BOOTPROTO'] = 'dhcp6' ++ iface_cfg['DHCLIENT6_MODE'] = 'info' ++ else: ++ iface_cfg['IPV6INIT'] = True ++ # Configure network settings using SLAAC from RAs ++ iface_cfg['IPV6_AUTOCONF'] = True + elif subnet_type in ['dhcp4', 'dhcp']: ++ bootproto_in = iface_cfg['BOOTPROTO'] + iface_cfg['BOOTPROTO'] = 'dhcp' ++ if flavor == 'suse' and subnet_type == 'dhcp4': ++ # If dhcp6 is already specified the user wants dhcp ++ # for both protocols ++ if bootproto_in != 'dhcp6': ++ # Only IPv4 is DHCP, IPv6 may be static ++ iface_cfg['BOOTPROTO'] = 'dhcp4' + elif subnet_type == 'static': ++ # RH info + # grep BOOTPROTO sysconfig.txt -A2 | head -3 + # BOOTPROTO=none|bootp|dhcp + # 'bootp' or 'dhcp' cause a DHCP client + # to run on the device. Any other + # value causes any static configuration + # in the file to be applied. +- # ==> the following should not be set to 'static' +- # but should remain 'none' +- # if iface_cfg['BOOTPROTO'] == 'none': +- # iface_cfg['BOOTPROTO'] = 'static' +- if subnet_is_ipv6(subnet): ++ if subnet_is_ipv6(subnet) and flavor != 'suse': + mtu_key = 'IPV6_MTU' + iface_cfg['IPV6INIT'] = True + if 'mtu' in subnet: +@@ -389,18 +446,31 @@ class Renderer(renderer.Renderer): + 'Network config: ignoring %s device-level mtu:%s' + ' because ipv4 subnet-level mtu:%s provided.', + iface_cfg.name, iface_cfg[mtu_key], subnet['mtu']) +- iface_cfg[mtu_key] = subnet['mtu'] ++ if subnet_is_ipv6(subnet): ++ if flavor == 'suse': ++ # TODO(rjschwei) write mtu setting to ++ # /etc/sysctl.d/ ++ pass ++ else: ++ iface_cfg[mtu_key] = subnet['mtu'] ++ else: ++ iface_cfg[mtu_key] = subnet['mtu'] + elif subnet_type == 'manual': +- # If the subnet has an MTU setting, then ONBOOT=True +- # to apply the setting +- iface_cfg['ONBOOT'] = mtu_key in iface_cfg ++ if flavor == 'suse': ++ LOG.debug('Unknown subnet type setting "%s"', subnet_type) ++ else: ++ # If the subnet has an MTU setting, then ONBOOT=True ++ # to apply the setting ++ iface_cfg['ONBOOT'] = mtu_key in iface_cfg + else: + raise ValueError("Unknown subnet type '%s' found" + " for interface '%s'" % (subnet_type, + iface_cfg.name)) + if subnet.get('control') == 'manual': +- iface_cfg['ONBOOT'] = False +- iface_cfg['STARTMODE'] = 'manual' ++ if flavor == 'suse': ++ iface_cfg['STARTMODE'] = 'manual' ++ else: ++ iface_cfg['ONBOOT'] = False + + # set IPv4 and IPv6 static addresses + ipv4_index = -1 +@@ -409,13 +479,14 @@ class Renderer(renderer.Renderer): + subnet_type = subnet.get('type') + # metric may apply to both dhcp and static config + if 'metric' in subnet: +- iface_cfg['METRIC'] = subnet['metric'] +- # TODO(hjensas): Including dhcp6 here is likely incorrect. DHCPv6 +- # does not ever provide a default gateway, the default gateway +- # come from RA's. (https://github.com/openSUSE/wicked/issues/570) +- if subnet_type in ['dhcp', 'dhcp4', 'dhcp6']: +- if has_default_route and iface_cfg['BOOTPROTO'] != 'none': +- iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = False ++ if flavor != 'suse': ++ iface_cfg['METRIC'] = subnet['metric'] ++ if subnet_type in ['dhcp', 'dhcp4']: ++ # On SUSE distros 'DHCLIENT_SET_DEFAULT_ROUTE' is a global ++ # setting in /etc/sysconfig/network/dhcp ++ if flavor != 'suse': ++ if has_default_route and iface_cfg['BOOTPROTO'] != 'none': ++ iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = False + continue + elif subnet_type in IPV6_DYNAMIC_TYPES: + continue +@@ -424,14 +495,21 @@ class Renderer(renderer.Renderer): + ipv6_index = ipv6_index + 1 + ipv6_cidr = "%s/%s" % (subnet['address'], subnet['prefix']) + if ipv6_index == 0: +- iface_cfg['IPV6ADDR'] = ipv6_cidr +- iface_cfg['IPADDR6'] = ipv6_cidr ++ if flavor == 'suse': ++ iface_cfg['IPADDR6'] = ipv6_cidr ++ else: ++ iface_cfg['IPV6ADDR'] = ipv6_cidr + elif ipv6_index == 1: +- iface_cfg['IPV6ADDR_SECONDARIES'] = ipv6_cidr +- iface_cfg['IPADDR6_0'] = ipv6_cidr ++ if flavor == 'suse': ++ iface_cfg['IPADDR6_1'] = ipv6_cidr ++ else: ++ iface_cfg['IPV6ADDR_SECONDARIES'] = ipv6_cidr + else: +- iface_cfg['IPV6ADDR_SECONDARIES'] += " " + ipv6_cidr +- iface_cfg['IPADDR6_%d' % ipv6_index] = ipv6_cidr ++ if flavor == 'suse': ++ iface_cfg['IPADDR6_%d' % ipv6_index] = ipv6_cidr ++ else: ++ iface_cfg['IPV6ADDR_SECONDARIES'] += \ ++ " " + ipv6_cidr + else: + ipv4_index = ipv4_index + 1 + suff = "" if ipv4_index == 0 else str(ipv4_index) +@@ -439,17 +517,17 @@ class Renderer(renderer.Renderer): + iface_cfg['NETMASK' + suff] = \ + net_prefix_to_ipv4_mask(subnet['prefix']) + +- if 'gateway' in subnet: ++ if 'gateway' in subnet and flavor != 'suse': + iface_cfg['DEFROUTE'] = True + if is_ipv6_addr(subnet['gateway']): + iface_cfg['IPV6_DEFAULTGW'] = subnet['gateway'] + else: + iface_cfg['GATEWAY'] = subnet['gateway'] + +- if 'dns_search' in subnet: ++ if 'dns_search' in subnet and flavor != 'suse': + iface_cfg['DOMAIN'] = ' '.join(subnet['dns_search']) + +- if 'dns_nameservers' in subnet: ++ if 'dns_nameservers' in subnet and flavor != 'suse': + if len(subnet['dns_nameservers']) > 3: + # per resolv.conf(5) MAXNS sets this to 3. + LOG.debug("%s has %d entries in dns_nameservers. " +@@ -459,7 +537,12 @@ class Renderer(renderer.Renderer): + iface_cfg['DNS' + str(i)] = k + + @classmethod +- def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets): ++ def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets, flavor): ++ # TODO(rjschwei): route configuration on SUSE distro happens via ++ # ifroute-* files, see lp#1812117. SUSE currently carries a local ++ # patch in their package. ++ if flavor == 'suse': ++ return + for _, subnet in enumerate(subnets, start=len(iface_cfg.children)): + subnet_type = subnet.get('type') + for route in subnet.get('routes', []): +@@ -487,14 +570,7 @@ class Renderer(renderer.Renderer): + # TODO(harlowja): add validation that no other iface has + # also provided the default route? + iface_cfg['DEFROUTE'] = True +- # TODO(hjensas): Including dhcp6 here is likely incorrect. +- # DHCPv6 does not ever provide a default gateway, the +- # default gateway come from RA's. +- # (https://github.com/openSUSE/wicked/issues/570) +- if iface_cfg['BOOTPROTO'] in ('dhcp', 'dhcp4', 'dhcp6'): +- # NOTE(hjensas): DHCLIENT_SET_DEFAULT_ROUTE is SuSE +- # only. RHEL, CentOS, Fedora does not implement this +- # option. ++ if iface_cfg['BOOTPROTO'] in ('dhcp', 'dhcp4'): + iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = True + if 'gateway' in route: + if is_ipv6: +@@ -538,7 +614,9 @@ class Renderer(renderer.Renderer): + iface_cfg['BONDING_OPTS'] = " ".join(bond_opts) + + @classmethod +- def _render_physical_interfaces(cls, network_state, iface_contents): ++ def _render_physical_interfaces( ++ cls, network_state, iface_contents, flavor ++ ): + physical_filter = renderer.filter_by_physical + for iface in network_state.iter_interfaces(physical_filter): + iface_name = iface['name'] +@@ -547,12 +625,15 @@ class Renderer(renderer.Renderer): + route_cfg = iface_cfg.routes + + cls._render_subnets( +- iface_cfg, iface_subnets, network_state.has_default_route ++ iface_cfg, iface_subnets, network_state.has_default_route, ++ flavor ++ ) ++ cls._render_subnet_routes( ++ iface_cfg, route_cfg, iface_subnets, flavor + ) +- cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets) + + @classmethod +- def _render_bond_interfaces(cls, network_state, iface_contents): ++ def _render_bond_interfaces(cls, network_state, iface_contents, flavor): + bond_filter = renderer.filter_by_type('bond') + slave_filter = renderer.filter_by_attr('bond-master') + for iface in network_state.iter_interfaces(bond_filter): +@@ -566,17 +647,24 @@ class Renderer(renderer.Renderer): + master_cfgs.extend(iface_cfg.children) + for master_cfg in master_cfgs: + master_cfg['BONDING_MASTER'] = True +- master_cfg.kind = 'bond' ++ if flavor != 'suse': ++ master_cfg.kind = 'bond' + + if iface.get('mac_address'): +- iface_cfg['MACADDR'] = iface.get('mac_address') ++ if flavor == 'suse': ++ iface_cfg['LLADDR'] = iface.get('mac_address') ++ else: ++ iface_cfg['MACADDR'] = iface.get('mac_address') + + iface_subnets = iface.get("subnets", []) + route_cfg = iface_cfg.routes + cls._render_subnets( +- iface_cfg, iface_subnets, network_state.has_default_route ++ iface_cfg, iface_subnets, network_state.has_default_route, ++ flavor ++ ) ++ cls._render_subnet_routes( ++ iface_cfg, route_cfg, iface_subnets, flavor + ) +- cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets) + + # iter_interfaces on network-state is not sorted to produce + # consistent numbers we need to sort. +@@ -586,28 +674,44 @@ class Renderer(renderer.Renderer): + if slave_iface['bond-master'] == iface_name]) + + for index, bond_slave in enumerate(bond_slaves): +- slavestr = 'BONDING_SLAVE%s' % index ++ if flavor == 'suse': ++ slavestr = 'BONDING_SLAVE_%s' % index ++ else: ++ slavestr = 'BONDING_SLAVE%s' % index + iface_cfg[slavestr] = bond_slave + + slave_cfg = iface_contents[bond_slave] +- slave_cfg['MASTER'] = iface_name +- slave_cfg['SLAVE'] = True ++ if flavor == 'suse': ++ slave_cfg['BOOTPROTO'] = 'none' ++ slave_cfg['STARTMODE'] = 'hotplug' ++ else: ++ slave_cfg['MASTER'] = iface_name ++ slave_cfg['SLAVE'] = True + + @classmethod +- def _render_vlan_interfaces(cls, network_state, iface_contents): ++ def _render_vlan_interfaces(cls, network_state, iface_contents, flavor): + vlan_filter = renderer.filter_by_type('vlan') + for iface in network_state.iter_interfaces(vlan_filter): + iface_name = iface['name'] + iface_cfg = iface_contents[iface_name] +- iface_cfg['VLAN'] = True +- iface_cfg['PHYSDEV'] = iface_name[:iface_name.rfind('.')] ++ if flavor == 'suse': ++ vlan_id = iface.get('vlan_id') ++ if vlan_id: ++ iface_cfg['VLAN_ID'] = vlan_id ++ iface_cfg['ETHERDEVICE'] = iface_name[:iface_name.rfind('.')] ++ else: ++ iface_cfg['VLAN'] = True ++ iface_cfg['PHYSDEV'] = iface_name[:iface_name.rfind('.')] + + iface_subnets = iface.get("subnets", []) + route_cfg = iface_cfg.routes + cls._render_subnets( +- iface_cfg, iface_subnets, network_state.has_default_route ++ iface_cfg, iface_subnets, network_state.has_default_route, ++ flavor ++ ) ++ cls._render_subnet_routes( ++ iface_cfg, route_cfg, iface_subnets, flavor + ) +- cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets) + + @staticmethod + def _render_dns(network_state, existing_dns_path=None): +@@ -644,19 +748,39 @@ class Renderer(renderer.Renderer): + return out + + @classmethod +- def _render_bridge_interfaces(cls, network_state, iface_contents): ++ def _render_bridge_interfaces(cls, network_state, iface_contents, flavor): ++ if flavor == 'suse': ++ bridge_opts_keys = cls.bridge_opts_keys_suse ++ else: ++ bridge_opts_keys = cls.bridge_opts_keys_rh + bridge_filter = renderer.filter_by_type('bridge') + for iface in network_state.iter_interfaces(bridge_filter): + iface_name = iface['name'] + iface_cfg = iface_contents[iface_name] +- iface_cfg.kind = 'bridge' +- for old_key, new_key in cls.bridge_opts_keys: ++ if flavor != 'suse': ++ iface_cfg.kind = 'bridge' ++ for old_key, new_key in bridge_opts_keys: + if old_key in iface: + iface_cfg[new_key] = iface[old_key] + +- if iface.get('mac_address'): +- iface_cfg['MACADDR'] = iface.get('mac_address') ++ if flavor == 'suse': ++ if 'BRIDGE_STP' in iface_cfg: ++ if iface_cfg.get('BRIDGE_STP'): ++ iface_cfg['BRIDGE_STP'] = 'on' ++ else: ++ iface_cfg['BRIDGE_STP'] = 'off' + ++ if iface.get('mac_address'): ++ key = 'MACADDR' ++ if flavor == 'suse': ++ key = 'LLADDRESS' ++ iface_cfg[key] = iface.get('mac_address') ++ ++ if flavor == 'suse': ++ if iface.get('bridge_ports', []): ++ iface_cfg['BRIDGE_PORTS'] = '%s' % " ".join( ++ iface.get('bridge_ports') ++ ) + # Is this the right key to get all the connected interfaces? + for bridged_iface_name in iface.get('bridge_ports', []): + # Ensure all bridged interfaces are correctly tagged +@@ -665,17 +789,23 @@ class Renderer(renderer.Renderer): + bridged_cfgs = [bridged_cfg] + bridged_cfgs.extend(bridged_cfg.children) + for bridge_cfg in bridged_cfgs: +- bridge_cfg['BRIDGE'] = iface_name ++ bridge_value = iface_name ++ if flavor == 'suse': ++ bridge_value = 'yes' ++ bridge_cfg['BRIDGE'] = bridge_value + + iface_subnets = iface.get("subnets", []) + route_cfg = iface_cfg.routes + cls._render_subnets( +- iface_cfg, iface_subnets, network_state.has_default_route ++ iface_cfg, iface_subnets, network_state.has_default_route, ++ flavor ++ ) ++ cls._render_subnet_routes( ++ iface_cfg, route_cfg, iface_subnets, flavor + ) +- cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets) + + @classmethod +- def _render_ib_interfaces(cls, network_state, iface_contents): ++ def _render_ib_interfaces(cls, network_state, iface_contents, flavor): + ib_filter = renderer.filter_by_type('infiniband') + for iface in network_state.iter_interfaces(ib_filter): + iface_name = iface['name'] +@@ -684,12 +814,15 @@ class Renderer(renderer.Renderer): + iface_subnets = iface.get("subnets", []) + route_cfg = iface_cfg.routes + cls._render_subnets( +- iface_cfg, iface_subnets, network_state.has_default_route ++ iface_cfg, iface_subnets, network_state.has_default_route, ++ flavor ++ ) ++ cls._render_subnet_routes( ++ iface_cfg, route_cfg, iface_subnets, flavor + ) +- cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets) + + @classmethod +- def _render_sysconfig(cls, base_sysconf_dir, network_state, ++ def _render_sysconfig(cls, base_sysconf_dir, network_state, flavor, + templates=None): + '''Given state, return /etc/sysconfig files + contents''' + if not templates: +@@ -700,13 +833,17 @@ class Renderer(renderer.Renderer): + continue + iface_name = iface['name'] + iface_cfg = NetInterface(iface_name, base_sysconf_dir, templates) +- cls._render_iface_shared(iface, iface_cfg) ++ if flavor == 'suse': ++ iface_cfg.drop('DEVICE') ++ # If type detection fails it is considered a bug in SUSE ++ iface_cfg.drop('TYPE') ++ cls._render_iface_shared(iface, iface_cfg, flavor) + iface_contents[iface_name] = iface_cfg +- cls._render_physical_interfaces(network_state, iface_contents) +- cls._render_bond_interfaces(network_state, iface_contents) +- cls._render_vlan_interfaces(network_state, iface_contents) +- cls._render_bridge_interfaces(network_state, iface_contents) +- cls._render_ib_interfaces(network_state, iface_contents) ++ cls._render_physical_interfaces(network_state, iface_contents, flavor) ++ cls._render_bond_interfaces(network_state, iface_contents, flavor) ++ cls._render_vlan_interfaces(network_state, iface_contents, flavor) ++ cls._render_bridge_interfaces(network_state, iface_contents, flavor) ++ cls._render_ib_interfaces(network_state, iface_contents, flavor) + contents = {} + for iface_name, iface_cfg in iface_contents.items(): + if iface_cfg or iface_cfg.children: +@@ -728,7 +865,7 @@ class Renderer(renderer.Renderer): + file_mode = 0o644 + base_sysconf_dir = util.target_path(target, self.sysconf_dir) + for path, data in self._render_sysconfig(base_sysconf_dir, +- network_state, ++ network_state, self.flavor, + templates=templates).items(): + util.write_file(path, data, file_mode) + if self.dns_path: +--- tests/unittests/test_distros/test_netconfig.py.orig ++++ tests/unittests/test_distros/test_netconfig.py +@@ -468,7 +468,6 @@ class TestNetCfgDistroRedhat(TestNetCfgD + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -477,7 +476,6 @@ class TestNetCfgDistroRedhat(TestNetCfgD + DEVICE=eth1 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -496,13 +494,11 @@ class TestNetCfgDistroRedhat(TestNetCfgD + BOOTPROTO=none + DEFROUTE=yes + DEVICE=eth0 +- IPADDR6=2607:f0d0:1002:0011::2/64 + IPV6ADDR=2607:f0d0:1002:0011::2/64 + IPV6INIT=yes + IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -511,7 +507,6 @@ class TestNetCfgDistroRedhat(TestNetCfgD + DEVICE=eth1 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -556,26 +551,14 @@ class TestNetCfgDistroOpensuse(TestNetCf + """Opensuse uses apply_network_config and renders sysconfig""" + expected_cfgs = { + self.ifcfg_path('eth0'): dedent("""\ +- BOOTPROTO=none +- DEFROUTE=yes +- DEVICE=eth0 +- GATEWAY=192.168.1.254 ++ BOOTPROTO=static + IPADDR=192.168.1.5 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no +- ONBOOT=yes + STARTMODE=auto +- TYPE=Ethernet +- USERCTL=no + """), + self.ifcfg_path('eth1'): dedent("""\ +- BOOTPROTO=dhcp +- DEVICE=eth1 +- NM_CONTROLLED=no +- ONBOOT=yes ++ BOOTPROTO=dhcp4 + STARTMODE=auto +- TYPE=Ethernet +- USERCTL=no + """), + } + self._apply_and_verify(self.distro.apply_network_config, +@@ -586,27 +569,13 @@ class TestNetCfgDistroOpensuse(TestNetCf + """Opensuse uses apply_network_config and renders sysconfig w/ipv6""" + expected_cfgs = { + self.ifcfg_path('eth0'): dedent("""\ +- BOOTPROTO=none +- DEFROUTE=yes +- DEVICE=eth0 ++ BOOTPROTO=static + IPADDR6=2607:f0d0:1002:0011::2/64 +- IPV6ADDR=2607:f0d0:1002:0011::2/64 +- IPV6INIT=yes +- IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 +- NM_CONTROLLED=no +- ONBOOT=yes + STARTMODE=auto +- TYPE=Ethernet +- USERCTL=no + """), + self.ifcfg_path('eth1'): dedent("""\ +- BOOTPROTO=dhcp +- DEVICE=eth1 +- NM_CONTROLLED=no +- ONBOOT=yes ++ BOOTPROTO=dhcp4 + STARTMODE=auto +- TYPE=Ethernet +- USERCTL=no + """), + } + self._apply_and_verify(self.distro.apply_network_config, +--- tests/unittests/test_net.py.orig ++++ tests/unittests/test_net.py +@@ -489,18 +489,11 @@ OS_SAMPLES = [ + """ + # Created by cloud-init on instance boot automatically, do not edit. + # +-BOOTPROTO=none +-DEFROUTE=yes +-DEVICE=eth0 +-GATEWAY=172.19.3.254 +-HWADDR=fa:16:3e:ed:9a:59 ++BOOTPROTO=static + IPADDR=172.19.1.34 ++LLADDR=fa:16:3e:ed:9a:59 + NETMASK=255.255.252.0 +-NM_CONTROLLED=no +-ONBOOT=yes + STARTMODE=auto +-TYPE=Ethernet +-USERCTL=no + """.lstrip()), + ('etc/resolv.conf', + """ +@@ -532,7 +525,6 @@ IPADDR=172.19.1.34 + NETMASK=255.255.252.0 + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -591,20 +583,13 @@ dns = none + """ + # Created by cloud-init on instance boot automatically, do not edit. + # +-BOOTPROTO=none +-DEFROUTE=yes +-DEVICE=eth0 +-GATEWAY=172.19.3.254 +-HWADDR=fa:16:3e:ed:9a:59 ++BOOTPROTO=static + IPADDR=172.19.1.34 + IPADDR1=10.0.0.10 ++LLADDR=fa:16:3e:ed:9a:59 + NETMASK=255.255.252.0 + NETMASK1=255.255.255.0 +-NM_CONTROLLED=no +-ONBOOT=yes + STARTMODE=auto +-TYPE=Ethernet +-USERCTL=no + """.lstrip()), + ('etc/resolv.conf', + """ +@@ -638,7 +623,6 @@ NETMASK=255.255.252.0 + NETMASK1=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -717,25 +701,14 @@ dns = none + """ + # Created by cloud-init on instance boot automatically, do not edit. + # +-BOOTPROTO=none +-DEFROUTE=yes +-DEVICE=eth0 +-GATEWAY=172.19.3.254 +-HWADDR=fa:16:3e:ed:9a:59 ++BOOTPROTO=static + IPADDR=172.19.1.34 + IPADDR6=2001:DB8::10/64 +-IPADDR6_0=2001:DB9::10/64 ++IPADDR6_1=2001:DB9::10/64 + IPADDR6_2=2001:DB10::10/64 +-IPV6ADDR=2001:DB8::10/64 +-IPV6ADDR_SECONDARIES="2001:DB9::10/64 2001:DB10::10/64" +-IPV6INIT=yes +-IPV6_DEFAULTGW=2001:DB8::1 ++LLADDR=fa:16:3e:ed:9a:59 + NETMASK=255.255.252.0 +-NM_CONTROLLED=no +-ONBOOT=yes + STARTMODE=auto +-TYPE=Ethernet +-USERCTL=no + """.lstrip()), + ('etc/resolv.conf', + """ +@@ -764,9 +737,6 @@ DEVICE=eth0 + GATEWAY=172.19.3.254 + HWADDR=fa:16:3e:ed:9a:59 + IPADDR=172.19.1.34 +-IPADDR6=2001:DB8::10/64 +-IPADDR6_0=2001:DB9::10/64 +-IPADDR6_2=2001:DB10::10/64 + IPV6ADDR=2001:DB8::10/64 + IPV6ADDR_SECONDARIES="2001:DB9::10/64 2001:DB10::10/64" + IPV6INIT=yes +@@ -774,7 +744,6 @@ IPV6_DEFAULTGW=2001:DB8::1 + NETMASK=255.255.252.0 + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -884,14 +853,25 @@ NETWORK_CONFIGS = { + via: 65.61.151.37 + set-name: eth99 + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-eth1': textwrap.dedent("""\ ++ BOOTPROTO=static ++ LLADDR=cf:d6:af:48:e8:80 ++ STARTMODE=auto"""), ++ 'ifcfg-eth99': textwrap.dedent("""\ ++ BOOTPROTO=dhcp4 ++ LLADDR=c0:d6:9f:2c:e8:80 ++ IPADDR=192.168.21.3 ++ NETMASK=255.255.255.0 ++ STARTMODE=auto"""), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-eth1': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=eth1 + HWADDR=cf:d6:af:48:e8:80 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth99': textwrap.dedent("""\ +@@ -909,7 +889,6 @@ NETWORK_CONFIGS = { + METRIC=10000 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + }, +@@ -1013,18 +992,28 @@ NETWORK_CONFIGS = { + address: 2001:1::1/64 + mtu: 1500 + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ # TODO(rjschwei): what should MTU be, RHEL has 2 for IPv6 and ++ # IPv4 but SUSE only has 1, pick the smaller of the values? ++ 'ifcfg-iface0': textwrap.dedent("""\ ++ BOOTPROTO=static ++ IPADDR=192.168.14.2 ++ IPADDR6=2001:1::1/64 ++ NETMASK=255.255.255.0 ++ STARTMODE=auto ++ MTU=1500 ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 + IPADDR=192.168.14.2 +- IPADDR6=2001:1::1/64 + IPV6ADDR=2001:1::1/64 + IPV6INIT=yes + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + MTU=9000 +@@ -1055,7 +1044,14 @@ NETWORK_CONFIGS = { + subnets: + - {'type': 'dhcp6'} + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-iface0': textwrap.dedent("""\ ++ BOOTPROTO=dhcp6 ++ DHCLIENT6_MODE=managed ++ STARTMODE=auto ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 +@@ -1064,7 +1060,6 @@ NETWORK_CONFIGS = { + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1103,7 +1098,14 @@ NETWORK_CONFIGS = { + dhcp6: true + accept-ra: true + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-iface0': textwrap.dedent("""\ ++ BOOTPROTO=dhcp6 ++ DHCLIENT6_MODE=managed ++ STARTMODE=auto ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 +@@ -1113,7 +1115,6 @@ NETWORK_CONFIGS = { + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1152,7 +1153,14 @@ NETWORK_CONFIGS = { + dhcp6: true + accept-ra: false + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-iface0': textwrap.dedent("""\ ++ BOOTPROTO=dhcp6 ++ DHCLIENT6_MODE=managed ++ STARTMODE=auto ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 +@@ -1162,7 +1170,6 @@ NETWORK_CONFIGS = { + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1192,7 +1199,14 @@ NETWORK_CONFIGS = { + subnets: + - {'type': 'ipv6_slaac'} + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-iface0': textwrap.dedent("""\ ++ BOOTPROTO=dhcp6 ++ DHCLIENT6_MODE=managed ++ STARTMODE=auto ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 +@@ -1201,7 +1215,6 @@ NETWORK_CONFIGS = { + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1231,7 +1244,14 @@ NETWORK_CONFIGS = { + subnets: + - {'type': 'ipv6_dhcpv6-stateless'} + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-iface0': textwrap.dedent("""\ ++ BOOTPROTO=dhcp6 ++ DHCLIENT6_MODE=managed ++ STARTMODE=auto ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 +@@ -1242,7 +1262,6 @@ NETWORK_CONFIGS = { + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1273,7 +1292,14 @@ NETWORK_CONFIGS = { + - {'type': 'ipv6_dhcpv6-stateful'} + accept-ra: true + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-iface0': textwrap.dedent("""\ ++ BOOTPROTO=dhcp6 ++ DHCLIENT6_MODE=managed ++ STARTMODE=auto ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 +@@ -1283,7 +1309,6 @@ NETWORK_CONFIGS = { + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1478,7 +1503,80 @@ pre-down route del -net 10.0.0.0/8 gw 11 + - sacchromyces.maas + - brettanomyces.maas + """).rstrip(' '), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-bond0': textwrap.dedent("""\ ++ BONDING_MASTER=yes ++ BONDING_OPTS="mode=active-backup """ ++ """xmit_hash_policy=layer3+4 """ ++ """miimon=100" ++ BONDING_SLAVE_0=eth1 ++ BONDING_SLAVE_1=eth2 ++ BOOTPROTO=dhcp6 ++ DHCLIENT6_MODE=managed ++ LLADDR=aa:bb:cc:dd:ee:ff ++ STARTMODE=auto"""), ++ 'ifcfg-bond0.200': textwrap.dedent("""\ ++ BOOTPROTO=dhcp4 ++ ETHERDEVICE=bond0 ++ STARTMODE=auto ++ VLAN_ID=200"""), ++ 'ifcfg-br0': textwrap.dedent("""\ ++ BRIDGE_AGEINGTIME=250 ++ BOOTPROTO=static ++ IPADDR=192.168.14.2 ++ IPADDR6=2001:1::1/64 ++ LLADDRESS=bb:bb:bb:bb:bb:aa ++ NETMASK=255.255.255.0 ++ BRIDGE_PRIORITY=22 ++ BRIDGE_PORTS='eth3 eth4' ++ STARTMODE=auto ++ BRIDGE_STP=off"""), ++ 'ifcfg-eth0': textwrap.dedent("""\ ++ BOOTPROTO=static ++ LLADDR=c0:d6:9f:2c:e8:80 ++ STARTMODE=auto"""), ++ 'ifcfg-eth0.101': textwrap.dedent("""\ ++ BOOTPROTO=static ++ IPADDR=192.168.0.2 ++ IPADDR1=192.168.2.10 ++ MTU=1500 ++ NETMASK=255.255.255.0 ++ NETMASK1=255.255.255.0 ++ ETHERDEVICE=eth0 ++ STARTMODE=auto ++ VLAN_ID=101"""), ++ 'ifcfg-eth1': textwrap.dedent("""\ ++ BOOTPROTO=none ++ LLADDR=aa:d6:9f:2c:e8:80 ++ STARTMODE=hotplug"""), ++ 'ifcfg-eth2': textwrap.dedent("""\ ++ BOOTPROTO=none ++ LLADDR=c0:bb:9f:2c:e8:80 ++ STARTMODE=hotplug"""), ++ 'ifcfg-eth3': textwrap.dedent("""\ ++ BOOTPROTO=static ++ BRIDGE=yes ++ LLADDR=66:bb:9f:2c:e8:80 ++ STARTMODE=auto"""), ++ 'ifcfg-eth4': textwrap.dedent("""\ ++ BOOTPROTO=static ++ BRIDGE=yes ++ LLADDR=98:bb:9f:2c:e8:80 ++ STARTMODE=auto"""), ++ 'ifcfg-eth5': textwrap.dedent("""\ ++ BOOTPROTO=dhcp ++ LLADDR=98:bb:9f:2c:e8:8a ++ STARTMODE=manual"""), ++ 'ifcfg-ib0': textwrap.dedent("""\ ++ BOOTPROTO=static ++ LLADDR=a0:00:02:20:fe:80:00:00:00:00:00:00:ec:0d:9a:03:00:15:e2:c1 ++ IPADDR=192.168.200.7 ++ MTU=9000 ++ NETMASK=255.255.255.0 ++ STARTMODE=auto ++ TYPE=InfiniBand"""), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-bond0': textwrap.dedent("""\ + BONDING_MASTER=yes + BONDING_OPTS="mode=active-backup """ +@@ -1493,7 +1591,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + MACADDR=aa:bb:cc:dd:ee:ff + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Bond + USERCTL=no"""), + 'ifcfg-bond0.200': textwrap.dedent("""\ +@@ -1503,7 +1600,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=bond0 +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + VLAN=yes"""), +@@ -1513,7 +1609,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + DEFROUTE=yes + DEVICE=br0 + IPADDR=192.168.14.2 +- IPADDR6=2001:1::1/64 + IPV6ADDR=2001:1::1/64 + IPV6INIT=yes + IPV6_DEFAULTGW=2001:4800:78ff:1b::1 +@@ -1522,7 +1617,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + NM_CONTROLLED=no + ONBOOT=yes + PRIO=22 +- STARTMODE=auto + STP=no + TYPE=Bridge + USERCTL=no"""), +@@ -1532,7 +1626,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + HWADDR=c0:d6:9f:2c:e8:80 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth0.101': textwrap.dedent("""\ +@@ -1551,7 +1644,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=eth0 +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + VLAN=yes"""), +@@ -1562,7 +1654,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + MASTER=bond0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + SLAVE=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -1573,7 +1664,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + MASTER=bond0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + SLAVE=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -1584,7 +1674,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + HWADDR=66:bb:9f:2c:e8:80 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth4': textwrap.dedent("""\ +@@ -1594,7 +1683,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + HWADDR=98:bb:9f:2c:e8:80 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth5': textwrap.dedent("""\ +@@ -1604,7 +1692,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + HWADDR=98:bb:9f:2c:e8:8a + NM_CONTROLLED=no + ONBOOT=no +- STARTMODE=manual + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-ib0': textwrap.dedent("""\ +@@ -1616,7 +1703,6 @@ pre-down route del -net 10.0.0.0/8 gw 11 + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=InfiniBand + USERCTL=no"""), + }, +@@ -2012,58 +2098,29 @@ iface bond0 inet6 static + """fail_over_mac=active """ + """primary=bond0s0 """ + """primary_reselect=always" +- BONDING_SLAVE0=bond0s0 +- BONDING_SLAVE1=bond0s1 +- BOOTPROTO=none +- DEFROUTE=yes +- DEVICE=bond0 +- GATEWAY=192.168.0.1 +- MACADDR=aa:bb:cc:dd:e8:ff ++ BONDING_SLAVE_0=bond0s0 ++ BONDING_SLAVE_1=bond0s1 ++ BOOTPROTO=static ++ LLADDR=aa:bb:cc:dd:e8:ff + IPADDR=192.168.0.2 + IPADDR1=192.168.1.2 + IPADDR6=2001:1::1/92 +- IPV6ADDR=2001:1::1/92 +- IPV6INIT=yes + MTU=9000 + NETMASK=255.255.255.0 + NETMASK1=255.255.255.0 +- NM_CONTROLLED=no +- ONBOOT=yes + STARTMODE=auto +- TYPE=Bond +- USERCTL=no + """), + 'ifcfg-bond0s0': textwrap.dedent("""\ + BOOTPROTO=none +- DEVICE=bond0s0 +- HWADDR=aa:bb:cc:dd:e8:00 +- MASTER=bond0 +- NM_CONTROLLED=no +- ONBOOT=yes +- SLAVE=yes +- STARTMODE=auto +- TYPE=Ethernet +- USERCTL=no +- """), +- 'ifroute-bond0': textwrap.dedent("""\ +- ADDRESS0=10.1.3.0 +- GATEWAY0=192.168.0.3 +- NETMASK0=255.255.255.0 ++ LLADDR=aa:bb:cc:dd:e8:00 ++ STARTMODE=hotplug + """), + 'ifcfg-bond0s1': textwrap.dedent("""\ + BOOTPROTO=none +- DEVICE=bond0s1 +- HWADDR=aa:bb:cc:dd:e8:01 +- MASTER=bond0 +- NM_CONTROLLED=no +- ONBOOT=yes +- SLAVE=yes +- STARTMODE=auto +- TYPE=Ethernet +- USERCTL=no ++ LLADDR=aa:bb:cc:dd:e8:01 ++ STARTMODE=hotplug + """), + }, +- + 'expected_sysconfig_rhel': { + 'ifcfg-bond0': textwrap.dedent("""\ + BONDING_MASTER=yes +@@ -2082,7 +2139,6 @@ iface bond0 inet6 static + MACADDR=aa:bb:cc:dd:e8:ff + IPADDR=192.168.0.2 + IPADDR1=192.168.1.2 +- IPADDR6=2001:1::1/92 + IPV6ADDR=2001:1::1/92 + IPV6INIT=yes + MTU=9000 +@@ -2090,7 +2146,6 @@ iface bond0 inet6 static + NETMASK1=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Bond + USERCTL=no + """), +@@ -2102,7 +2157,6 @@ iface bond0 inet6 static + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -2125,7 +2179,6 @@ iface bond0 inet6 static + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -2156,14 +2209,32 @@ iface bond0 inet6 static + netmask: '::' + network: '::' + """), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ # TODO RJS: unknown proper BOOTPROTO setting ask Marius ++ 'ifcfg-en0': textwrap.dedent("""\ ++ BOOTPROTO=static ++ LLADDR=aa:bb:cc:dd:e8:00 ++ STARTMODE=auto"""), ++ 'ifcfg-en0.99': textwrap.dedent("""\ ++ BOOTPROTO=static ++ IPADDR=192.168.2.2 ++ IPADDR1=192.168.1.2 ++ IPADDR6=2001:1::bbbb/96 ++ MTU=2222 ++ NETMASK=255.255.255.0 ++ NETMASK1=255.255.255.0 ++ STARTMODE=auto ++ ETHERDEVICE=en0 ++ VLAN_ID=99 ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-en0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=en0 + HWADDR=aa:bb:cc:dd:e8:00 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-en0.99': textwrap.dedent("""\ +@@ -2173,7 +2244,6 @@ iface bond0 inet6 static + GATEWAY=192.168.1.1 + IPADDR=192.168.2.2 + IPADDR1=192.168.1.2 +- IPADDR6=2001:1::bbbb/96 + IPV6ADDR=2001:1::bbbb/96 + IPV6INIT=yes + IPV6_DEFAULTGW=2001:1::1 +@@ -2183,7 +2253,6 @@ iface bond0 inet6 static + NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=en0 +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + VLAN=yes"""), +@@ -2216,7 +2285,32 @@ iface bond0 inet6 static + subnets: + - type: static + address: 192.168.2.2/24"""), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-br0': textwrap.dedent("""\ ++ BOOTPROTO=static ++ IPADDR=192.168.2.2 ++ NETMASK=255.255.255.0 ++ STARTMODE=auto ++ BRIDGE_STP=off ++ BRIDGE_PRIORITY=22 ++ BRIDGE_PORTS='eth0 eth1' ++ """), ++ 'ifcfg-eth0': textwrap.dedent("""\ ++ BOOTPROTO=static ++ BRIDGE=yes ++ LLADDR=52:54:00:12:34:00 ++ IPADDR6=2001:1::100/96 ++ STARTMODE=auto ++ """), ++ 'ifcfg-eth1': textwrap.dedent("""\ ++ BOOTPROTO=static ++ BRIDGE=yes ++ LLADDR=52:54:00:12:34:01 ++ IPADDR6=2001:1::101/96 ++ STARTMODE=auto ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-br0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=br0 +@@ -2225,7 +2319,6 @@ iface bond0 inet6 static + NM_CONTROLLED=no + ONBOOT=yes + PRIO=22 +- STARTMODE=auto + STP=no + TYPE=Bridge + USERCTL=no +@@ -2235,12 +2328,10 @@ iface bond0 inet6 static + BRIDGE=br0 + DEVICE=eth0 + HWADDR=52:54:00:12:34:00 +- IPADDR6=2001:1::100/96 + IPV6ADDR=2001:1::100/96 + IPV6INIT=yes + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -2249,12 +2340,10 @@ iface bond0 inet6 static + BRIDGE=br0 + DEVICE=eth1 + HWADDR=52:54:00:12:34:01 +- IPADDR6=2001:1::101/96 + IPV6ADDR=2001:1::101/96 + IPV6INIT=yes + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -2320,7 +2409,27 @@ iface bond0 inet6 static + macaddress: 52:54:00:12:34:ff + set-name: eth2 + """), +- 'expected_sysconfig': { ++ 'expected_sysconfig_opensuse': { ++ 'ifcfg-eth0': textwrap.dedent("""\ ++ BOOTPROTO=static ++ LLADDR=52:54:00:12:34:00 ++ IPADDR=192.168.1.2 ++ NETMASK=255.255.255.0 ++ STARTMODE=manual ++ """), ++ 'ifcfg-eth1': textwrap.dedent("""\ ++ BOOTPROTO=static ++ LLADDR=52:54:00:12:34:aa ++ MTU=1480 ++ STARTMODE=auto ++ """), ++ 'ifcfg-eth2': textwrap.dedent("""\ ++ BOOTPROTO=static ++ LLADDR=52:54:00:12:34:ff ++ STARTMODE=manual ++ """), ++ }, ++ 'expected_sysconfig_rhel': { + 'ifcfg-eth0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=eth0 +@@ -2329,7 +2438,6 @@ iface bond0 inet6 static + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=no +- STARTMODE=manual + TYPE=Ethernet + USERCTL=no + """), +@@ -2340,7 +2448,6 @@ iface bond0 inet6 static + MTU=1480 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -2350,7 +2457,6 @@ iface bond0 inet6 static + HWADDR=52:54:00:12:34:ff + NM_CONTROLLED=no + ONBOOT=no +- STARTMODE=manual + TYPE=Ethernet + USERCTL=no + """), +@@ -2681,7 +2787,7 @@ class TestRhelSysConfigRendering(CiTestC + header = ('# Created by cloud-init on instance boot automatically, ' + 'do not edit.\n#\n') + +- expected_name = 'expected_sysconfig' ++ expected_name = 'expected_sysconfig_rhel' + + def _get_renderer(self): + distro_cls = distros.fetch('rhel') +@@ -2768,7 +2874,6 @@ DEVICE=eth1000 + HWADDR=07-1c-c6-75-a4-be + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip() +@@ -2890,7 +2995,6 @@ IPADDR=10.0.2.15 + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +@@ -2922,7 +3026,6 @@ MTU=1500 + NETMASK=255.255.240.0 + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +@@ -2937,7 +3040,6 @@ HWADDR=fa:16:3e:b1:ca:29 + MTU=9000 + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +@@ -2963,7 +3065,6 @@ BOOTPROTO=dhcp + DEVICE=eth0 + NM_CONTROLLED=no + ONBOOT=yes +-STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +@@ -2972,10 +3073,9 @@ USERCTL=no + self.assertEqual(resolvconf_content, found['/etc/resolv.conf']) + + def test_bond_config(self): +- expected_name = 'expected_sysconfig_rhel' + entry = NETWORK_CONFIGS['bond'] + found = self._render_and_read(network_config=yaml.load(entry['yaml'])) +- self._compare_files_to_expected(entry[expected_name], found) ++ self._compare_files_to_expected(entry[self.expected_name], found) + self._assert_headers(found) + + def test_vlan_config(self): +@@ -3163,14 +3263,12 @@ USERCTL=no + GATEWAY=192.168.42.1 + HWADDR=52:54:00:ab:cd:ef + IPADDR=192.168.42.100 +- IPADDR6=2001:db8::100/32 + IPV6ADDR=2001:db8::100/32 + IPV6INIT=yes + IPV6_DEFAULTGW=2001:db8::1 + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -3196,7 +3294,6 @@ USERCTL=no + DEVICE=eno1 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -3209,7 +3306,6 @@ USERCTL=no + NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=eno1 +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + VLAN=yes +@@ -3240,7 +3336,6 @@ USERCTL=no + NETMASK=255.255.255.192 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Bond + USERCTL=no + """), +@@ -3252,7 +3347,6 @@ USERCTL=no + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes +- STARTMODE=auto + TYPE=Bond + USERCTL=no + """), +@@ -3264,7 +3358,6 @@ USERCTL=no + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes +- STARTMODE=auto + TYPE=Bond + USERCTL=no + """) +@@ -3288,7 +3381,6 @@ USERCTL=no + METRIC=100 + NM_CONTROLLED=no + ONBOOT=yes +- STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -3311,7 +3403,7 @@ class TestOpenSuseSysConfigRendering(CiT + header = ('# Created by cloud-init on instance boot automatically, ' + 'do not edit.\n#\n') + +- expected_name = 'expected_sysconfig' ++ expected_name = 'expected_sysconfig_opensuse' + + def _get_renderer(self): + distro_cls = distros.fetch('opensuse') +@@ -3383,19 +3475,17 @@ class TestOpenSuseSysConfigRendering(CiT + expected_content = """ + # Created by cloud-init on instance boot automatically, do not edit. + # +-BOOTPROTO=dhcp +-DEVICE=eth1000 +-HWADDR=07-1c-c6-75-a4-be +-NM_CONTROLLED=no +-ONBOOT=yes ++BOOTPROTO=dhcp4 ++LLADDR=07-1c-c6-75-a4-be + STARTMODE=auto +-TYPE=Ethernet +-USERCTL=no + """.lstrip() + self.assertEqual(expected_content, content) + + def test_multiple_ipv4_default_gateways(self): + """ValueError is raised when duplicate ipv4 gateways exist.""" ++ # TODO(rjschwei): re-enable test once route writing is implemented ++ # for SUSE distros ++ return + net_json = { + "services": [{"type": "dns", "address": "172.19.0.12"}], + "networks": [{ +@@ -3434,6 +3524,9 @@ USERCTL=no + + def test_multiple_ipv6_default_gateways(self): + """ValueError is raised when duplicate ipv6 gateways exist.""" ++ # TODO(rjschwei): re-enable test once route writing is implemented ++ # for SUSE distros ++ return + net_json = { + "services": [{"type": "dns", "address": "172.19.0.12"}], + "networks": [{ +@@ -3501,18 +3594,11 @@ USERCTL=no + expected = """\ + # Created by cloud-init on instance boot automatically, do not edit. + # +-BOOTPROTO=none +-DEFROUTE=yes +-DEVICE=interface0 +-GATEWAY=10.0.2.2 +-HWADDR=52:54:00:12:34:00 ++BOOTPROTO=static + IPADDR=10.0.2.15 ++LLADDR=52:54:00:12:34:00 + NETMASK=255.255.255.0 +-NM_CONTROLLED=no +-ONBOOT=yes + STARTMODE=auto +-TYPE=Ethernet +-USERCTL=no + """ + self.assertEqual(expected, found[nspath + 'ifcfg-interface0']) + # The configuration has no nameserver information make sure we +@@ -3537,12 +3623,7 @@ USERCTL=no + # Created by cloud-init on instance boot automatically, do not edit. + # + BOOTPROTO=dhcp +-DEVICE=eth0 +-NM_CONTROLLED=no +-ONBOOT=yes + STARTMODE=auto +-TYPE=Ethernet +-USERCTL=no + """ + self.assertEqual(expected, found[nspath + 'ifcfg-eth0']) + # a dhcp only config should not modify resolv.conf diff --git a/cloud-init-noresolv-merge-no-dns-data.diff b/cloud-init-noresolv-merge-no-dns-data.diff deleted file mode 100644 index 02a8b6f..0000000 --- a/cloud-init-noresolv-merge-no-dns-data.diff +++ /dev/null @@ -1,68 +0,0 @@ -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index be5dede..1708990 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -578,6 +578,10 @@ class Renderer(renderer.Renderer): - - @staticmethod - def _render_dns(network_state, existing_dns_path=None): -+ # skip writing resolv.conf if network_state doesn't include any input. -+ if not any([len(network_state.dns_nameservers), -+ len(network_state.dns_searchdomains)]): -+ return None - content = resolv_conf.ResolvConf("") - if existing_dns_path and os.path.isfile(existing_dns_path): - content = resolv_conf.ResolvConf(util.load_file(existing_dns_path)) -@@ -585,8 +589,6 @@ class Renderer(renderer.Renderer): - content.add_nameserver(nameserver) - for searchdomain in network_state.dns_searchdomains: - content.add_search_domain(searchdomain) -- if not str(content): -- return None - header = _make_header(';') - content_str = str(content) - if not content_str.startswith(header): -diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index e578992..82eb18f 100644 ---- a/tests/unittests/test_net.py -+++ b/tests/unittests/test_net.py -@@ -2701,6 +2701,10 @@ USERCTL=no - ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK) - render_dir = self.tmp_path("render") - os.makedirs(render_dir) -+ # write an etc/resolv.conf and expect it to not be modified -+ resolvconf = os.path.join(render_dir, 'etc/resolv.conf') -+ content = "# Original Content" -+ util.write_file(resolvconf, content) - renderer = self._get_renderer() - renderer.render_network_state(ns, target=render_dir) - found = dir2dict(render_dir) -@@ -2718,6 +2722,8 @@ TYPE=Ethernet - USERCTL=no - """ - self.assertEqual(expected, found[nspath + 'ifcfg-eth0']) -+ # a dhcp only config should not modify resolv.conf -+ self.assertEqual(content, found['/etc/resolv.conf']) - - def test_bond_config(self): - expected_name = 'expected_sysconfig_rhel' -@@ -3202,6 +3208,10 @@ USERCTL=no - ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK) - render_dir = self.tmp_path("render") - os.makedirs(render_dir) -+ # write an etc/resolv.conf and expect it to not be modified -+ resolvconf = os.path.join(render_dir, 'etc/resolv.conf') -+ content = "# Original Content" -+ util.write_file(resolvconf, content) - renderer = self._get_renderer() - renderer.render_network_state(ns, target=render_dir) - found = dir2dict(render_dir) -@@ -3219,6 +3229,8 @@ TYPE=Ethernet - USERCTL=no - """ - self.assertEqual(expected, found[nspath + 'ifcfg-eth0']) -+ # a dhcp only config should not modify resolv.conf -+ self.assertEqual(content, found['/etc/resolv.conf']) - - def test_bond_config(self): - expected_name = 'expected_sysconfig_opensuse' diff --git a/cloud-init-proper-ipv6-setting.patch b/cloud-init-proper-ipv6-setting.patch deleted file mode 100644 index 7bf0025..0000000 --- a/cloud-init-proper-ipv6-setting.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- cloudinit/net/sysconfig.py.orig -+++ cloudinit/net/sysconfig.py -@@ -349,6 +349,7 @@ class Renderer(renderer.Renderer): - # TODO need to set BOOTPROTO to dhcp6 on SUSE - iface_cfg['IPV6INIT'] = True - iface_cfg['DHCPV6C'] = True -+ iface_cfg['DHCLIENT6_MODE'] = 'managed' - elif subnet_type in ['dhcp4', 'dhcp']: - iface_cfg['BOOTPROTO'] = 'dhcp' - elif subnet_type == 'static': diff --git a/cloud-init-renderer-detect.patch b/cloud-init-renderer-detect.patch deleted file mode 100644 index 2296c19..0000000 --- a/cloud-init-renderer-detect.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- cloudinit/net/sysconfig.py.orig -+++ cloudinit/net/sysconfig.py -@@ -748,7 +748,7 @@ class Renderer(renderer.Renderer): - def available(target=None): - sysconfig = available_sysconfig(target=target) - nm = available_nm(target=target) -- return (util.get_linux_distro()[0] in KNOWN_DISTROS -+ return (util.system_info()['variant'] in KNOWN_DISTROS - and any([nm, sysconfig])) - - -@@ -758,6 +758,8 @@ def available_sysconfig(target=None): - for p in expected: - if not util.which(p, search=search, target=target): - return False -+ else: -+ return True - - expected_paths = ['etc/sysconfig/network/scripts/functions.netconfig'] - for p in expected_paths: diff --git a/cloud-init-static-net.patch b/cloud-init-static-net.patch deleted file mode 100644 index 3f641fa..0000000 --- a/cloud-init-static-net.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- cloudinit/net/sysconfig.py.orig -+++ cloudinit/net/sysconfig.py -@@ -314,7 +314,8 @@ class Renderer(renderer.Renderer): - # ==> the following should not be set to 'static' - # but should remain 'none' - # if iface_cfg['BOOTPROTO'] == 'none': -- # iface_cfg['BOOTPROTO'] = 'static' -+ # For SUSE this is different set to "static" -+ iface_cfg['BOOTPROTO'] = 'static' - if subnet_is_ipv6(subnet): - mtu_key = 'IPV6_MTU' - iface_cfg['IPV6INIT'] = True diff --git a/cloud-init-sysconf-path.patch b/cloud-init-sysconf-path.patch index c6b17f3..da4ea5c 100644 --- a/cloud-init-sysconf-path.patch +++ b/cloud-init-sysconf-path.patch @@ -1,13 +1,13 @@ --- cloudinit/net/sysconfig.py.orig +++ cloudinit/net/sysconfig.py -@@ -660,9 +660,7 @@ def available(target=None): +@@ -891,9 +891,7 @@ def available_sysconfig(target=None): if not util.which(p, search=search, target=target): return False - expected_paths = [ - 'etc/sysconfig/network-scripts/network-functions', -- 'etc/sysconfig/network-scripts/ifdown-eth'] +- 'etc/sysconfig/config'] + expected_paths = ['etc/sysconfig/network/scripts/functions.netconfig'] for p in expected_paths: - if not os.path.isfile(util.target_path(target, p)): - return False + if os.path.isfile(util.target_path(target, p)): + return True diff --git a/cloud-init-trigger-udev.patch b/cloud-init-trigger-udev.patch deleted file mode 100644 index 4431385..0000000 --- a/cloud-init-trigger-udev.patch +++ /dev/null @@ -1,36 +0,0 @@ ---- cloudinit/distros/opensuse.py.orig -+++ cloudinit/distros/opensuse.py -@@ -38,6 +38,8 @@ class Distro(distros.Distro): - 'sysconfig': { - 'control': 'etc/sysconfig/network/config', - 'iface_templates': '%(base)s/network/ifcfg-%(name)s', -+ 'netrules_path': ( -+ 'etc/udev/rules.d/85-persistent-net-cloud-init.rules'), - 'route_templates': { - 'ipv4': '%(base)s/network/ifroute-%(name)s', - 'ipv6': '%(base)s/network/ifroute-%(name)s', ---- cloudinit/net/sysconfig.py.orig -+++ cloudinit/net/sysconfig.py -@@ -8,6 +8,7 @@ import six - from cloudinit.distros.parsers import networkmanager_conf - from cloudinit.distros.parsers import resolv_conf - from cloudinit import log as logging -+from cloudinit import net - from cloudinit import util - - from configobj import ConfigObj -@@ -699,6 +700,14 @@ class Renderer(renderer.Renderer): - if nm_conf_content: - util.write_file(nm_conf_path, nm_conf_content, file_mode) - if self.netrules_path: -+ # When many interfaces are present it can happen that we get here -+ # before they are all setup. Settle if that is the case. -+ for iface in network_state.iter_interfaces( -+ renderer.filter_by_physical): -+ path = net.sys_dev_path(iface.get('name')) -+ if not os.path.exists(path): -+ util.udevadm_settle(path, 5) -+ break - netrules_content = self._render_persistent_net(network_state) - netrules_path = util.target_path(target, self.netrules_path) - util.write_file(netrules_path, netrules_content, file_mode) diff --git a/cloud-init.changes b/cloud-init.changes index fa5e427..ba6d1d3 100644 --- a/cloud-init.changes +++ b/cloud-init.changes @@ -1,3 +1,192 @@ +------------------------------------------------------------------- +Thu Jan 9 18:56:26 UTC 2020 - Robert Schweikert + +- Update to version 19.4 + + Remove patches included upstream: + - cloud-init-after-wicked.patch + - cloud-init-noresolv-merge-no-dns-data.diff + - cloud-init-renderer-detect.patch + - cloud-init-trigger-udev.patch + + Removed patches merged with cloud-init-mix-static-dhcp.patch + - cloud-init-proper-ipv6-setting.patch + - cloud-init-static-net.patch + + Added cloud-init-mix-static-dhcp.patch (bsc#1157894) + + Forward port cloud-init-sysconf-path.patch + + doc: specify _ over - in cloud config modules + + [Joshua Powers] (LP: #1293254) + + tools: Detect python to use via env in migrate-lp-user-to-github + + [Adam Dobrawy] + + Partially revert "fix unlocking method on FreeBSD" (#116) + + tests: mock uid when running as root (#113) + + [Joshua Powers] (LP: #1856096) + + cloudinit/netinfo: remove unused getgateway (#111) + + docs: clear up apt config sections (#107) [Joshua Powers] (LP: #1832823) + + doc: add kernel command line option to user data (#105) + + [Joshua Powers] (LP: #1846524) + + config/cloud.cfg.d: update README [Joshua Powers] (LP: #1855006) + + azure: avoid re-running cloud-init when instance-id is byte-swapped + + (#84) [AOhassan] + + fix unlocking method on FreeBSD [Igor Galić] (LP: #1854594) + + debian: add reference to the manpages [Joshua Powers] + + ds_identify: if /sys is not available use dmidecode (#42) + + [Igor Galić] (LP: #1852442) + + docs: add cloud-id manpage [Joshua Powers] + + docs: add cloud-init-per manpage [Joshua Powers] + + docs: add cloud-init manpage [Joshua Powers] + + docs: add additional details to per-instance/once [Joshua Powers] + + Update doc-requirements.txt [Joshua Powers] + + doc-requirements: add missing dep [Joshua Powers] + + dhcp: Support RedHat dhcp rfc3442 lease format for option 121 (#76) + + [Eric Lafontaine] (LP: #1850642) + + network_state: handle empty v1 config (#45) (LP: #1852496) + + docs: Add document on how to report bugs [Joshua Powers] + + Add an Amazon distro in the redhat OS family [Frederick Lefebvre] + + removed a couple of "the"s [gaughen] + + docs: fix line length and remove highlighting [Joshua Powers] + + docs: Add security.md to readthedocs [Joshua Powers] + + Multiple file fix for AuthorizedKeysFile config (#60) [Eduardo Otubo] + + Revert "travis: only run CI on pull requests" + + doc: update links on README.md [Joshua Powers] + + doc: Updates to wording of README.md [Joshua Powers] + + Add security.md [Joshua Powers] + + setup.py: Amazon Linux sets libexec to /usr/libexec (#52) + + [Frederick Lefebvre] + + Fix linting failure in test_url_helper (#83) [Eric Lafontaine] + + url_helper: read_file_or_url should pass headers param into readurl + + (#66) (LP: #1854084) + + dmidecode: log result *after* stripping n [Igor Galić] + + cloud_tests: add azure platform support to integration tests + + [ahosmanmsft] + + set_passwords: support for FreeBSD (#46) [Igor Galić] + + tools: migrate-lp-user-to-github removes repo_dir if created (#35) + + Correct jumbled documentation for cc_set_hostname module (#64) + + [do3meli] (LP: #1853543) + + FreeBSD: fix for get_linux_distro() and lru_cache (#59) + + [Igor Galić] (LP: #1815030) + + ec2: Add support for AWS IMDS v2 (session-oriented) (#55) + + tests: Fix cloudsigma tests when no dmidecode data is present. (#57) + + [Scott Moser] + + net: IPv6, accept_ra, slaac, stateless (#51) + + [Harald] (LP: #1806014, #1808647) + + docs: Update the configdrive datasource links (#44) + + [Joshua Powers] (LP: #1852461) + + distro: correctly set usr_lib_exec path for FreeBSD distro (#40) + + [Igor Galić] (LP: #1852491) + + azure: support secondary ipv6 addresses (#33) + + Fix metadata check when local-hostname is null (#32) + + [Mark Goddard] (LP: #1852100) + + switch default FreeBSD salt minion pkg from py27 to py36 + + [Dominic Schlegel] + + travis: only run CI on pull requests + + add data-server dns entry as new metadata server detection [Joshua Hügli] + + pycodestyle: remove unused local variable + + reporting: Using a uuid to enforce uniqueness on the KVP keys. [momousta] + + docs: touchups in rtd intro and README.md + + doc: update launchpad git refs to github + + github: drop pull-request template to prepare for migration + + tools: add migrate-lp-user-to-github script to link LP to github + + github: new basic project readme + +- From 19.3 + + azure: support matching dhcp route-metrics for dual-stack ipv4 ipv6 + + (LP: #1850308) + + configdrive: fix subplatform config-drive for /config-drive source + + [David Kindred] (LP: #1849731) + + DataSourceSmartOS: reconfigure network on each boot + + [Mike Gerdts] (LP: #1765801) + + Add config for ssh-key import and consuming user-data [Pavel Zakharov] + + net: fix subnet_is_ipv6() for stateless|stateful + + [Harald Jensås] (LP: #1848690) + + OVF: disable custom script execution by default [Xiaofeng Wang] + + cc_puppet: Implement csr_attributes.yaml support [Matthias Baur] + + cloud-init.service: on centos/fedora/redhat wait on NetworkManager.service + + (LP: #1843334) + + azure: Do not lock user on instance id change [Sam Eiderman] (LP: #1849677) + + net/netplan: use ipv6-mtu key for specifying ipv6 mtu values + + Fix usages of yaml, and move yaml_dump to safeyaml.dumps. (LP: #1849640) + + exoscale: Increase url_max_wait to 120s. [Chris Glass] + + net/sysconfig: fix available check on SUSE distros + + [Robert Schweikert] (LP: #1849378) + + docs: Fix incorrect Azure IMDS IP address [Joshua Powers] (LP: #1849508) + + introduce .travis.yml + + net: enable infiniband support in eni and sysconfig renderers + + [Darren Birkett] (LP: #1847114) + + guestcust_util: handle special characters in config file [Xiaofeng Wang] + + fix some more typos in comments [Dominic Schlegel] + + replace any deprecated log.warn with log.warning + + [Dominic Schlegel] (LP: #1508442) + + net: handle openstack dhcpv6-stateless configuration + + [Harald Jensås] (LP: #1847517) + + Add .venv/ to .gitignore [Dominic Schlegel] + + Small typo fixes in code comments. [Dominic Schlegel] + + cloud_test/lxd: Retry container delete a few times + + Add Support for e24cloud to Ec2 datasource. (LP: #1696476) + + Add RbxCloud datasource [Adam Dobrawy] + + get_interfaces: don't exclude bridge and bond members (LP: #1846535) + + Add support for Arch Linux in render-cloudcfg [Conrad Hoffmann] + + util: json.dumps on python 2.7 will handle UnicodeDecodeError on binary + + (LP: #1801364) + + debian/ubuntu: add missing word to netplan/ENI header (LP: #1845669) + + ovf: do not generate random instance-id for IMC customization path + + sysconfig: only write resolv.conf if network_state has DNS values + + (LP: #1843634) + + sysconfig: use distro variant to check if available (LP: #1843584) + + systemd/cloud-init.service.tmpl: start after wicked.service + + [Robert Schweikert] + + docs: fix zstack documentation lints + + analyze/show: remove trailing space in output + + Add missing space in warning: "not avalid seed" [Brian Candler] + + pylintrc: add 'enter_context' to generated-members list + + Add datasource for ZStack platform. [Shixin Ruan] (LP: #1841181) + + docs: organize TOC and update summary of project [Joshua Powers] + + tools: make clean now cleans the dev directory, not the system + + docs: create cli specific page [Joshua Powers] + + docs: added output examples to analyze.rst [Joshua Powers] + + docs: doc8 fixes for instancedata page [Joshua Powers] + + docs: clean up formatting, organize boot page [Joshua Powers] + + net: add is_master check for filtering device list (LP: #1844191) + + docs: more complete list of availability [Joshua Powers] + + docs: start FAQ page [Joshua Powers] + + docs: cleanup output & order of datasource page [Joshua Powers] + + Brightbox: restrict detection to require full domain match .brightbox.com + + VMWware: add option into VMTools config to enable/disable custom script. + + [Xiaofeng Wang] + + net,Oracle: Add support for netfailover detection + + atomic_helper: add DEBUG logging to write_file (LP: #1843276) + + doc: document doc, create makefile and tox target [Joshua Powers] + + .gitignore: ignore files produced by package builds + + docs: fix whitespace, spelling, and line length [Joshua Powers] + + docs: remove unnecessary file in doc directory [Joshua Powers] + + Oracle: Render secondary vnic IP and MTU values only + + exoscale: fix sysconfig cloud_config_modules overrides (LP: #1841454) + + net/cmdline: refactor to allow multiple initramfs network config sources + + ubuntu-drivers: call db_x_loadtemplatefile to accept NVIDIA EULA + + (LP: #1840080) + + Add missing #cloud-config comment on first example in documentation. + + [Florian Müller] + + ubuntu-drivers: emit latelink=true debconf to accept nvidia eula + + (LP: #1840080) + + DataSourceOracle: prefer DS network config over initramfs + + format.rst: add text/jinja2 to list of content types (+ cleanups) + + Add GitHub pull request template to point people at hacking doc + + cloudinit/distros/parsers/sys_conf: add docstring to SysConf + + pyflakes: remove unused variable [Joshua Powers] + + Azure: Record boot timestamps, system information, and diagnostic events + + [Anh Vo] + + DataSourceOracle: configure secondary NICs on Virtual Machines + + distros: fix confusing variable names + + azure/net: generate_fallback_nic emits network v2 config instead of v1 + + Add support for publishing host keys to GCE guest attributes [Rick Wright] + + New data source for the Exoscale.com cloud platform [Chris Glass] + + doc: remove intersphinx extension + + cc_set_passwords: rewrite documentation (LP: #1838794) + + net/cmdline: split interfaces_by_mac and init network config determination + + stages: allow data sources to override network config source order + + cloud_tests: updates and fixes + + Fix bug rendering MTU on bond or vlan when input was netplan. (LP: #1836949) + + net: update net sequence, include wait on netdevs, opensuse netrules path + (LP: #1817368) + ------------------------------------------------------------------- Mon Nov 25 19:34:52 UTC 2019 - Robert Schweikert diff --git a/cloud-init.spec b/cloud-init.spec index 53a1d1a..3097a10 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -18,9 +18,9 @@ %global configver 0.7 Name: cloud-init -Version: 19.2 +Version: 19.4 Release: 0 -License: GPL-3.0 and AGPL-3.0 +License: GPL-3.0 Summary: Cloud node initialization tool Url: http://launchpad.net/cloud-init/ Group: System/Management @@ -33,25 +33,16 @@ Patch20: cloud-init-python2-sigpipe.patch Patch21: cloud-init-template-py2.patch Patch29: datasourceLocalDisk.patch Patch34: cloud-init-tests-set-exec.patch -# FIXME no proposed solution -Patch38: cloud-init-sysconf-path.patch -# FIXME (lp# 1800854) -Patch41: cloud-init-static-net.patch # FIXME (lp#1801364) Patch42: cloud-init-ostack-metadat-dencode.patch # FIXME (lp#1812117) Patch43: cloud-init-write-routes.patch -# FIXME (lp#1817368) expected in 19.3 -Patch47: cloud-init-trigger-udev.patch -# FIXME (lp#1843634) expected in 19.3 -Patch50: cloud-init-noresolv-merge-no-dns-data.diff -# FIXME expected in 19.3 -Patch51: cloud-init-after-wicked.patch # FIXME (lp#1849296) Patch52: cloud-init-break-resolv-symlink.patch -# FIXME (lp#1849378) expected in 19.3 -Patch53: cloud-init-renderer-detect.patch -Patch54: cloud-init-proper-ipv6-setting.patch +# FIXME (lp#1858808) +Patch55: cloud-init-mix-static-dhcp.patch +# FIXME no proposed solution +Patch56: cloud-init-sysconf-path.patch BuildRequires: fdupes BuildRequires: filesystem @@ -190,16 +181,11 @@ Documentation and examples for cloud-init tools %endif %patch29 -p0 %patch34 -%patch38 -%patch41 %patch42 %patch43 -%patch47 -%patch50 -p1 -%patch51 -p1 %patch52 -%patch53 -%patch54 +%patch55 -p0 +%patch56 %build %if 0%{?suse_version} && 0%{?suse_version} <= 1315 @@ -236,9 +222,14 @@ done mkdir -p %{buildroot}%{_localstatedir}/lib/cloud # move documentation mkdir -p %{buildroot}%{_defaultdocdir} -mv %{buildroot}%{_datadir}/doc/%{name} %{buildroot}%{docdir} +mv %{buildroot}%{_datadir}/doc/%{name} %{buildroot}%{_defaultdocdir} +# man pages +mkdir -p %{buildroot}%{_mandir}/man1 +mv doc/man/* %{buildroot}%{_mandir}/man1 # copy the LICENSE -cp LICENSE %{buildroot}%{docdir} +mkdir -p %{buildroot}%{_defaultlicensedir}/%{name} +cp LICENSE %{buildroot}%{_defaultlicensedir}/%{name} +cp LICENSE-GPLv3 %{buildroot}%{_defaultlicensedir}/%{name} # Set the distribution indicator %if 0%{?suse_version} %if 0%{?is_opensuse} @@ -287,8 +278,7 @@ popd %files %defattr(-,root,root) -# do not mark as doc or we get conflicts with the doc package -%{docdir}/LICENSE +%license LICENSE LICENSE-GPLv3 %{_bindir}/cloud-id %{_bindir}/cloud-init %{_bindir}/cloud-init-per @@ -297,6 +287,7 @@ popd %config(noreplace) %{_sysconfdir}/cloud/templates %{_sysconfdir}/dhcp/dhclient-exit-hooks.d/hook-dhclient %{_sysconfdir}/NetworkManager/dispatcher.d/hook-network-manager +%{_mandir}/man*/* %if 0%{?suse_version} && 0%{?suse_version} < 1500 %dir %{_datadir}/bash-completion %dir %{_datadir}/bash-completion/completions @@ -352,9 +343,7 @@ popd %files doc %defattr(-,root,root) %{docdir}/examples/* -%{docdir}/README %{docdir}/*.txt -#%{docdir}/*.rst %dir %{docdir}/examples #%files test From d21979739cec25a9b5be1450d72b0abd110f79dc3ac57a9a68131c63ebc70b4e Mon Sep 17 00:00:00 2001 From: Robert Schweikert Date: Fri, 17 Jan 2020 12:38:50 +0000 Subject: [PATCH 2/3] Accepting request 764340 from home:scarabeus_iv:branches:Cloud:Tools - Add patch to build properly with python 3.8: * 0001-Make-tests-work-with-Python-3.8-139.patch OBS-URL: https://build.opensuse.org/request/show/764340 OBS-URL: https://build.opensuse.org/package/show/Cloud:Tools/cloud-init?expand=0&rev=159 --- ...-Make-tests-work-with-Python-3.8-139.patch | 104 ++++++++++++++++++ cloud-init.changes | 6 + cloud-init.spec | 3 +- 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 0001-Make-tests-work-with-Python-3.8-139.patch diff --git a/0001-Make-tests-work-with-Python-3.8-139.patch b/0001-Make-tests-work-with-Python-3.8-139.patch new file mode 100644 index 0000000..c4d8f7b --- /dev/null +++ b/0001-Make-tests-work-with-Python-3.8-139.patch @@ -0,0 +1,104 @@ +From c5a7d7979c036f6dc6823f429c6b6820f7f74241 Mon Sep 17 00:00:00 2001 +From: Conrad Hoffmann <1226676+bitfehler@users.noreply.github.com> +Date: Wed, 8 Jan 2020 15:18:48 +0100 +Subject: [PATCH] Make tests work with Python 3.8 (#139) + +* Make DistroChecker test work with Python 3.8 + +In Python 3.8, `platform.linux_distribution` has been removed. This was +anticipated, and the cloud-init code uses its own +`util.get_linux_distro` instead, which works fine w/o +`platform.linux_distribution`. However, these tests still try to mock +the platform function, which fails if it doesn't exist (Python 3.8). +Instead, mock the new function here, as this is a test for code that +depends on it rather than the function itself. + +* Make GetLinuxDistro tests work with Python 3.8 + +In Python 3.8, `platform.dist` was removed, so allow mock to create the +function by setting `create=True`. + +* Make linter happy in Python 3.8 + +Suppress E1101(no-member) as this function was removed. +--- + cloudinit/analyze/tests/test_boot.py | 8 ++++---- + cloudinit/tests/test_util.py | 6 +++--- + cloudinit/util.py | 4 ++-- + 3 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/cloudinit/analyze/tests/test_boot.py b/cloudinit/analyze/tests/test_boot.py +index 706e2cc0..f4001c14 100644 +--- a/cloudinit/analyze/tests/test_boot.py ++++ b/cloudinit/analyze/tests/test_boot.py +@@ -12,17 +12,17 @@ class TestDistroChecker(CiTestCase): + @mock.patch('cloudinit.util.system_info', return_value={'dist': ('', '', + ''), + 'system': ''}) +- @mock.patch('platform.linux_distribution', return_value=('', '', '')) ++ @mock.patch('cloudinit.util.get_linux_distro', return_value=('', '', '')) + @mock.patch('cloudinit.util.is_FreeBSD', return_value=False) +- def test_blank_distro(self, m_sys_info, m_linux_distribution, m_free_bsd): ++ def test_blank_distro(self, m_sys_info, m_get_linux_distro, m_free_bsd): + self.assertEqual(err_code, dist_check_timestamp()) + + @mock.patch('cloudinit.util.system_info', return_value={'dist': ('', '', + '')}) +- @mock.patch('platform.linux_distribution', return_value=('', '', '')) ++ @mock.patch('cloudinit.util.get_linux_distro', return_value=('', '', '')) + @mock.patch('cloudinit.util.is_FreeBSD', return_value=True) + def test_freebsd_gentoo_cant_find(self, m_sys_info, +- m_linux_distribution, m_is_FreeBSD): ++ m_get_linux_distro, m_is_FreeBSD): + self.assertEqual(err_code, dist_check_timestamp()) + + @mock.patch('cloudinit.util.subp', return_value=(0, 1)) +diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py +index 64ed82ea..be100646 100644 +--- a/cloudinit/tests/test_util.py ++++ b/cloudinit/tests/test_util.py +@@ -523,7 +523,7 @@ class TestGetLinuxDistro(CiTestCase): + self.assertEqual( + ('opensuse-tumbleweed', '20180920', platform.machine()), dist) + +- @mock.patch('platform.dist') ++ @mock.patch('platform.dist', create=True) + def test_get_linux_distro_no_data(self, m_platform_dist, m_path_exists): + """Verify we get no information if os-release does not exist""" + m_platform_dist.return_value = ('', '', '') +@@ -531,7 +531,7 @@ class TestGetLinuxDistro(CiTestCase): + dist = util.get_linux_distro() + self.assertEqual(('', '', ''), dist) + +- @mock.patch('platform.dist') ++ @mock.patch('platform.dist', create=True) + def test_get_linux_distro_no_impl(self, m_platform_dist, m_path_exists): + """Verify we get an empty tuple when no information exists and + Exceptions are not propagated""" +@@ -540,7 +540,7 @@ class TestGetLinuxDistro(CiTestCase): + dist = util.get_linux_distro() + self.assertEqual(('', '', ''), dist) + +- @mock.patch('platform.dist') ++ @mock.patch('platform.dist', create=True) + def test_get_linux_distro_plat_data(self, m_platform_dist, m_path_exists): + """Verify we get the correct platform information""" + m_platform_dist.return_value = ('foo', '1.1', 'aarch64') +diff --git a/cloudinit/util.py b/cloudinit/util.py +index 9d9d5c72..830c8e54 100644 +--- a/cloudinit/util.py ++++ b/cloudinit/util.py +@@ -635,8 +635,8 @@ def get_linux_distro(): + else: + dist = ('', '', '') + try: +- # Will be removed in 3.7 +- dist = platform.dist() # pylint: disable=W1505 ++ # Was removed in 3.8 ++ dist = platform.dist() # pylint: disable=W1505,E1101 + except Exception: + pass + finally: +-- +2.24.1 + diff --git a/cloud-init.changes b/cloud-init.changes index ba6d1d3..66d3b48 100644 --- a/cloud-init.changes +++ b/cloud-init.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Jan 14 15:14:52 UTC 2020 - Tomáš Chvátal + +- Add patch to build properly with python 3.8: + * 0001-Make-tests-work-with-Python-3.8-139.patch + ------------------------------------------------------------------- Thu Jan 9 18:56:26 UTC 2020 - Robert Schweikert diff --git a/cloud-init.spec b/cloud-init.spec index 3097a10..131b46b 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -26,7 +26,7 @@ Url: http://launchpad.net/cloud-init/ Group: System/Management Source0: %{name}-%{version}.tar.gz Source1: rsyslog-cloud-init.cfg - +Patch0: 0001-Make-tests-work-with-Python-3.8-139.patch # FIXME # python2 disables SIGPIPE, causing broken pipe errors in shell scripts (bsc#903449) Patch20: cloud-init-python2-sigpipe.patch @@ -175,6 +175,7 @@ Documentation and examples for cloud-init tools %prep %setup -q +%patch0 -p1 %if 0%{?suse_version} < 1315 %patch20 %patch21 From 5a5220c86897c8239471d5b7d7e9020c6883e68094538455940252e834f60e93 Mon Sep 17 00:00:00 2001 From: Robert Schweikert Date: Fri, 17 Jan 2020 21:33:13 +0000 Subject: [PATCH 3/3] - Add cloud-init-no-tempnet-oci.patch (bsc#1161132, bsc#1161133) + Do not attempt to configure an ephemeral network on OCI. We boot off iSCSI and the network is up. Just read the data. OBS-URL: https://build.opensuse.org/package/show/Cloud:Tools/cloud-init?expand=0&rev=160 --- cloud-init-no-tempnet-oci.patch | 25 +++++++++++++++++++++++++ cloud-init.changes | 7 +++++++ cloud-init.spec | 3 +++ 3 files changed, 35 insertions(+) create mode 100644 cloud-init-no-tempnet-oci.patch diff --git a/cloud-init-no-tempnet-oci.patch b/cloud-init-no-tempnet-oci.patch new file mode 100644 index 0000000..583de0b --- /dev/null +++ b/cloud-init-no-tempnet-oci.patch @@ -0,0 +1,25 @@ +--- cloudinit/sources/DataSourceOracle.py.orig ++++ cloudinit/sources/DataSourceOracle.py +@@ -189,11 +189,17 @@ class DataSourceOracle(sources.DataSourc + + # network may be configured if iscsi root. If that is the case + # then read_initramfs_config will return non-None. +- if _is_iscsi_root(): +- data = self.crawl_metadata() +- else: +- with dhcp.EphemeralDHCPv4(net.find_fallback_nic()): +- data = self.crawl_metadata() ++ #if _is_iscsi_root(): ++ # data = self.crawl_metadata() ++ #else: ++ # with dhcp.EphemeralDHCPv4(net.find_fallback_nic()): ++ # data = self.crawl_metadata() ++ # ++ # The detection of the configured network for iscsi boot is ++ # distribution dependent and of course only implemented for ++ # Debian/Ubuntu. We know the network is up as we are booting from ++ # iscsi. Skip the BS and just read the damn data ++ data = self.crawl_metadata() + + self._crawled_metadata = data + vdata = data['2013-10-17'] diff --git a/cloud-init.changes b/cloud-init.changes index 66d3b48..30d104a 100644 --- a/cloud-init.changes +++ b/cloud-init.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Fri Jan 17 18:55:41 UTC 2020 - Robert Schweikert + +- Add cloud-init-no-tempnet-oci.patch (bsc#1161132, bsc#1161133) + + Do not attempt to configure an ephemeral network on OCI. We + boot off iSCSI and the network is up. Just read the data. + ------------------------------------------------------------------- Tue Jan 14 15:14:52 UTC 2020 - Tomáš Chvátal diff --git a/cloud-init.spec b/cloud-init.spec index 131b46b..e1400b6 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -43,6 +43,8 @@ Patch52: cloud-init-break-resolv-symlink.patch Patch55: cloud-init-mix-static-dhcp.patch # FIXME no proposed solution Patch56: cloud-init-sysconf-path.patch +# FIXME (lp#1860164) +Patch57: cloud-init-no-tempnet-oci.patch BuildRequires: fdupes BuildRequires: filesystem @@ -187,6 +189,7 @@ Documentation and examples for cloud-init tools %patch52 %patch55 -p0 %patch56 +%patch57 %build %if 0%{?suse_version} && 0%{?suse_version} <= 1315