cloud-init/SOURCES/ci-sysconfig-distro-specifi...

1901 lines
71 KiB
Diff

From dc7315345b42b6f913191d1b52ed459d3ec5068b Mon Sep 17 00:00:00 2001
From: Eduardo Otubo <otubo@redhat.com>
Date: Tue, 23 Feb 2021 12:16:27 +0100
Subject: [PATCH] sysconfig: distro-specific config rendering for BOOTPROTO
option (#162)
RH-Author: Eduardo Terrell Ferrari Otubo (eterrell)
RH-MergeRequest: 1: sysconfig: distro-specific config rendering for BOOTPROTO option (#162)
RH-Commit: [1/1] d88e3e93e2d23c8b90191cf6c5d0e8b7733fcce2 (eterrell/cloud-init)
RH-Bugzilla: 1931835
commit 06e324ff8edb3126e5a8060757a48ceab2b1a121
Author: Robert Schweikert <rjschwei@suse.com>
Date: Mon Feb 3 14:56:51 2020 -0500
sysconfig: distro-specific config rendering for BOOTPROTO option (#162)
- 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)
Co-authored-by: Chad Smith <chad.smith@canonical.com>
LP: #1800854
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
---
cloudinit/distros/opensuse.py | 1 +
cloudinit/net/sysconfig.py | 329 +++++++---
.../unittests/test_distros/test_netconfig.py | 34 +-
tests/unittests/test_net.py | 596 +++++++++++-------
4 files changed, 592 insertions(+), 368 deletions(-)
diff --git a/cloudinit/distros/opensuse.py b/cloudinit/distros/opensuse.py
index e41e2f7b..dd56a3f4 100644
--- a/cloudinit/distros/opensuse.py
+++ b/cloudinit/distros/opensuse.py
@@ -37,6 +37,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'),
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index 1989d014..1e8a547e 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -1,5 +1,6 @@
# This file is part of cloud-init. See LICENSE file for license information.
+import copy
import os
import re
@@ -86,6 +87,9 @@ class ConfigMap(object):
def __getitem__(self, key):
return self._conf[key]
+ def get(self, key):
+ return self._conf.get(key)
+
def __contains__(self, key):
return key in self._conf
@@ -115,6 +119,9 @@ class ConfigMap(object):
buf.write("%s=%s\n" % (key, _quote_value(value)))
return buf.getvalue()
+ def update(self, updates):
+ self._conf.update(updates)
+
class Route(ConfigMap):
"""Represents a route configuration."""
@@ -281,12 +288,28 @@ class Renderer(renderer.Renderer):
# s1-networkscripts-interfaces.html (or other docs for
# details about this)
- iface_defaults = tuple([
- ('ONBOOT', True),
- ('USERCTL', False),
- ('BOOTPROTO', 'none'),
- ('STARTMODE', 'auto'),
- ])
+ iface_defaults = {
+ 'rhel': {'ONBOOT': True, 'USERCTL': False, 'BOOTPROTO': 'none'},
+ 'suse': {'BOOTPROTO': 'static', 'STARTMODE': 'auto'},
+ }
+
+ cfg_key_maps = {
+ 'rhel': {
+ 'accept-ra': 'IPV6_FORCE_ACCEPT_RA',
+ 'bridge_stp': 'STP',
+ 'bridge_ageing': 'AGEING',
+ 'bridge_bridgeprio': 'PRIO',
+ 'mac_address': 'HWADDR',
+ 'mtu': 'MTU',
+ },
+ 'suse': {
+ 'bridge_stp': 'BRIDGE_STP',
+ 'bridge_ageing': 'BRIDGE_AGEINGTIME',
+ 'bridge_bridgeprio': 'BRIDGE_PRIORITY',
+ 'mac_address': 'LLADDR',
+ 'mtu': 'MTU',
+ },
+ }
# If these keys exist, then their values will be used to form
# a BONDING_OPTS grouping; otherwise no grouping will be set.
@@ -308,12 +331,6 @@ class Renderer(renderer.Renderer):
('bond_primary_reselect', "primary_reselect=%s"),
])
- bridge_opts_keys = tuple([
- ('bridge_stp', 'STP'),
- ('bridge_ageing', 'AGEING'),
- ('bridge_bridgeprio', 'PRIO'),
- ])
-
templates = {}
def __init__(self, config=None):
@@ -331,65 +348,101 @@ class Renderer(renderer.Renderer):
'iface_templates': config.get('iface_templates'),
'route_templates': config.get('route_templates'),
}
+ self.flavor = config.get('flavor', 'rhel')
@classmethod
- def _render_iface_shared(cls, iface, iface_cfg):
- for k, v in cls.iface_defaults:
- iface_cfg[k] = v
+ def _render_iface_shared(cls, iface, iface_cfg, flavor):
+ flavor_defaults = copy.deepcopy(cls.iface_defaults.get(flavor, {}))
+ iface_cfg.update(flavor_defaults)
- for (old_key, new_key) in [('mac_address', 'HWADDR'), ('mtu', 'MTU')]:
+ for old_key in ('mac_address', 'mtu', 'accept-ra'):
old_value = iface.get(old_key)
if old_value is not None:
# only set HWADDR on physical interfaces
if (old_key == 'mac_address' and
iface['type'] not in ['physical', 'infiniband']):
continue
- iface_cfg[new_key] = old_value
-
- if iface['accept-ra'] is not None:
- iface_cfg['IPV6_FORCE_ACCEPT_RA'] = iface['accept-ra']
+ new_key = cls.cfg_key_maps[flavor].get(old_key)
+ if new_key:
+ iface_cfg[new_key] = old_value
@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 in ['static', 'static6']:
+ # 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:
@@ -406,16 +459,21 @@ class Renderer(renderer.Renderer):
iface_cfg['IPV6_FORCE_ACCEPT_RA'] = False
iface_cfg['IPV6_AUTOCONF'] = False
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
@@ -424,13 +482,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
@@ -439,14 +498,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)
@@ -454,17 +520,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. "
@@ -474,7 +540,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', []):
@@ -502,14 +573,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:
@@ -553,7 +617,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']
@@ -562,12 +628,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):
@@ -581,17 +650,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.
@@ -601,15 +677,22 @@ 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']
@@ -629,9 +712,12 @@ 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)
@staticmethod
def _render_dns(network_state, existing_dns_path=None):
@@ -668,19 +754,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):
+ bridge_key_map = {
+ old_k: new_k for old_k, new_k in cls.cfg_key_maps[flavor].items()
+ if old_k.startswith('bridge')}
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_key_map.items():
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
@@ -689,17 +795,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']
@@ -708,12 +820,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:
@@ -724,13 +839,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:
@@ -752,7 +871,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:
diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py
index e277bca2..905e8281 100644
--- a/tests/unittests/test_distros/test_netconfig.py
+++ b/tests/unittests/test_distros/test_netconfig.py
@@ -521,7 +521,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase):
NETMASK=255.255.255.0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -530,7 +529,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase):
DEVICE=eth1
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -549,13 +547,11 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase):
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
"""),
@@ -564,7 +560,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase):
DEVICE=eth1
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -690,26 +685,14 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase):
"""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,
@@ -720,9 +703,7 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase):
"""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
@@ -732,17 +713,10 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase):
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,
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index b2b7c4b2..7e598411 100644
--- a/tests/unittests/test_net.py
+++ b/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',
"""
@@ -531,7 +524,6 @@ HWADDR=fa:16:3e:ed:9a:59
IPADDR=172.19.1.34
NETMASK=255.255.252.0
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
""".lstrip()),
@@ -590,20 +582,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',
"""
@@ -636,7 +621,6 @@ IPADDR1=10.0.0.10
NETMASK=255.255.252.0
NETMASK1=255.255.255.0
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
""".lstrip()),
@@ -715,25 +699,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',
"""
@@ -762,9 +735,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
@@ -773,7 +743,6 @@ IPV6_DEFAULTGW=2001:DB8::1
IPV6_FORCE_ACCEPT_RA=no
NETMASK=255.255.252.0
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
""".lstrip()),
@@ -883,13 +852,24 @@ 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
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no"""),
'ifcfg-eth99': textwrap.dedent("""\
@@ -906,7 +886,6 @@ NETWORK_CONFIGS = {
NETMASK=255.255.255.0
METRIC=10000
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no"""),
},
@@ -960,6 +939,12 @@ NETWORK_CONFIGS = {
dhcp4: true
dhcp6: true
""").rstrip(' '),
+ 'expected_sysconfig_opensuse': {
+ 'ifcfg-iface0': textwrap.dedent("""\
+ BOOTPROTO=dhcp
+ DHCLIENT6_MODE=managed
+ STARTMODE=auto""")
+ },
'yaml': textwrap.dedent("""\
version: 1
config:
@@ -1010,19 +995,27 @@ NETWORK_CONFIGS = {
address: 2001:1::1/64
mtu: 1500
""").rstrip(' '),
- 'expected_sysconfig': {
+ 'expected_sysconfig_opensuse': {
+ 'ifcfg-iface0': textwrap.dedent("""\
+ BOOTPROTO=static
+ IPADDR=192.168.14.2
+ IPADDR6=2001:1::1/64
+ NETMASK=255.255.255.0
+ STARTMODE=auto
+ MTU=9000
+ """),
+ },
+ '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
IPV6_AUTOCONF=no
IPV6_FORCE_ACCEPT_RA=no
NETMASK=255.255.255.0
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
MTU=9000
@@ -1030,6 +1023,23 @@ NETWORK_CONFIGS = {
"""),
},
},
+ 'v6_and_v4': {
+ 'expected_sysconfig_opensuse': {
+ 'ifcfg-iface0': textwrap.dedent("""\
+ BOOTPROTO=dhcp
+ DHCLIENT6_MODE=managed
+ STARTMODE=auto""")
+ },
+ 'yaml': textwrap.dedent("""\
+ version: 1
+ config:
+ - type: 'physical'
+ name: 'iface0'
+ subnets:
+ - type: dhcp6
+ - type: dhcp4
+ """).rstrip(' '),
+ },
'dhcpv6_only': {
'expected_eni': textwrap.dedent("""\
auto lo
@@ -1053,7 +1063,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
@@ -1062,7 +1079,6 @@ NETWORK_CONFIGS = {
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -1101,7 +1117,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
@@ -1111,7 +1134,6 @@ NETWORK_CONFIGS = {
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -1150,7 +1172,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
@@ -1160,7 +1189,6 @@ NETWORK_CONFIGS = {
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -1190,7 +1218,14 @@ NETWORK_CONFIGS = {
subnets:
- {'type': 'ipv6_slaac'}
""").rstrip(' '),
- 'expected_sysconfig': {
+ 'expected_sysconfig_opensuse': {
+ 'ifcfg-iface0': textwrap.dedent("""\
+ BOOTPROTO=dhcp6
+ DHCLIENT6_MODE=info
+ STARTMODE=auto
+ """),
+ },
+ 'expected_sysconfig_rhel': {
'ifcfg-iface0': textwrap.dedent("""\
BOOTPROTO=none
DEVICE=iface0
@@ -1199,7 +1234,6 @@ NETWORK_CONFIGS = {
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -1256,7 +1290,14 @@ NETWORK_CONFIGS = {
subnets:
- {'type': 'ipv6_dhcpv6-stateless'}
""").rstrip(' '),
- 'expected_sysconfig': {
+ 'expected_sysconfig_opensuse': {
+ 'ifcfg-iface0': textwrap.dedent("""\
+ BOOTPROTO=dhcp6
+ DHCLIENT6_MODE=info
+ STARTMODE=auto
+ """),
+ },
+ 'expected_sysconfig_rhel': {
'ifcfg-iface0': textwrap.dedent("""\
BOOTPROTO=none
DEVICE=iface0
@@ -1267,7 +1308,6 @@ NETWORK_CONFIGS = {
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -1298,7 +1338,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
@@ -1308,7 +1355,6 @@ NETWORK_CONFIGS = {
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -1503,7 +1549,80 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
- 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 """
@@ -1517,7 +1636,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
IPV6INIT=yes
MACADDR=aa:bb:cc:dd:ee:ff
ONBOOT=yes
- STARTMODE=auto
TYPE=Bond
USERCTL=no"""),
'ifcfg-bond0.200': textwrap.dedent("""\
@@ -1527,6 +1645,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
ONBOOT=yes
PHYSDEV=bond0
STARTMODE=auto
+ TYPE=Ethernet
USERCTL=no
VLAN=yes"""),
'ifcfg-br0': textwrap.dedent("""\
@@ -1535,7 +1654,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
DEFROUTE=yes
DEVICE=br0
IPADDR=192.168.14.2
- IPADDR6=2001:1::1/64
IPV6ADDR=2001:1::1/64
IPV6INIT=yes
IPV6_AUTOCONF=no
@@ -1545,7 +1663,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NETMASK=255.255.255.0
ONBOOT=yes
PRIO=22
- STARTMODE=auto
STP=no
TYPE=Bridge
USERCTL=no"""),
@@ -1554,7 +1671,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
DEVICE=eth0
HWADDR=c0:d6:9f:2c:e8:80
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no"""),
'ifcfg-eth0.101': textwrap.dedent("""\
@@ -1573,6 +1689,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
ONBOOT=yes
PHYSDEV=eth0
STARTMODE=auto
+ TYPE=Ethernet
USERCTL=no
VLAN=yes"""),
'ifcfg-eth1': textwrap.dedent("""\
@@ -1581,7 +1698,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
HWADDR=aa:d6:9f:2c:e8:80
MASTER=bond0
ONBOOT=yes
- STARTMODE=auto
SLAVE=yes
TYPE=Ethernet
USERCTL=no"""),
@@ -1591,7 +1707,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
HWADDR=c0:bb:9f:2c:e8:80
MASTER=bond0
ONBOOT=yes
- STARTMODE=auto
SLAVE=yes
TYPE=Ethernet
USERCTL=no"""),
@@ -1601,7 +1716,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
DEVICE=eth3
HWADDR=66:bb:9f:2c:e8:80
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no"""),
'ifcfg-eth4': textwrap.dedent("""\
@@ -1610,7 +1724,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
DEVICE=eth4
HWADDR=98:bb:9f:2c:e8:80
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no"""),
'ifcfg-eth5': textwrap.dedent("""\
@@ -1619,7 +1732,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
DHCLIENT_SET_DEFAULT_ROUTE=no
HWADDR=98:bb:9f:2c:e8:8a
ONBOOT=no
- STARTMODE=manual
TYPE=Ethernet
USERCTL=no"""),
'ifcfg-ib0': textwrap.dedent("""\
@@ -1631,7 +1743,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NETMASK=255.255.255.0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=InfiniBand
USERCTL=no"""),
},
@@ -2027,58 +2138,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
@@ -2097,7 +2179,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
IPV6_AUTOCONF=no
@@ -2106,7 +2187,6 @@ iface bond0 inet6 static
NETMASK=255.255.255.0
NETMASK1=255.255.255.0
ONBOOT=yes
- STARTMODE=auto
TYPE=Bond
USERCTL=no
"""),
@@ -2117,7 +2197,6 @@ iface bond0 inet6 static
MASTER=bond0
ONBOOT=yes
SLAVE=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -2139,7 +2218,6 @@ iface bond0 inet6 static
MASTER=bond0
ONBOOT=yes
SLAVE=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -2170,13 +2248,31 @@ 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
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no"""),
'ifcfg-en0.99': textwrap.dedent("""\
@@ -2186,7 +2282,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_AUTOCONF=no
@@ -2198,6 +2293,7 @@ iface bond0 inet6 static
ONBOOT=yes
PHYSDEV=en0
STARTMODE=auto
+ TYPE=Ethernet
USERCTL=no
VLAN=yes"""),
},
@@ -2229,7 +2325,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
@@ -2237,7 +2358,6 @@ iface bond0 inet6 static
NETMASK=255.255.255.0
ONBOOT=yes
PRIO=22
- STARTMODE=auto
STP=no
TYPE=Bridge
USERCTL=no
@@ -2247,14 +2367,12 @@ 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
IPV6_AUTOCONF=no
IPV6_FORCE_ACCEPT_RA=no
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -2263,14 +2381,12 @@ 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
IPV6_AUTOCONF=no
IPV6_FORCE_ACCEPT_RA=no
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -2336,7 +2452,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
@@ -2344,7 +2480,6 @@ iface bond0 inet6 static
IPADDR=192.168.1.2
NETMASK=255.255.255.0
ONBOOT=no
- STARTMODE=manual
TYPE=Ethernet
USERCTL=no
"""),
@@ -2354,7 +2489,6 @@ iface bond0 inet6 static
HWADDR=52:54:00:12:34:aa
MTU=1480
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -2363,7 +2497,6 @@ iface bond0 inet6 static
DEVICE=eth2
HWADDR=52:54:00:12:34:ff
ONBOOT=no
- STARTMODE=manual
TYPE=Ethernet
USERCTL=no
"""),
@@ -2694,7 +2827,7 @@ class TestRhelSysConfigRendering(CiTestCase):
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')
@@ -2780,7 +2913,6 @@ BOOTPROTO=dhcp
DEVICE=eth1000
HWADDR=07-1c-c6-75-a4-be
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
""".lstrip()
@@ -2901,7 +3033,6 @@ HWADDR=52:54:00:12:34:00
IPADDR=10.0.2.15
NETMASK=255.255.255.0
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""
@@ -2933,7 +3064,6 @@ MTU=1500
NETMASK=255.255.240.0
NM_CONTROLLED=no
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""
@@ -2948,7 +3078,6 @@ HWADDR=fa:16:3e:b1:ca:29
MTU=9000
NM_CONTROLLED=no
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""
@@ -2973,7 +3102,6 @@ USERCTL=no
BOOTPROTO=dhcp
DEVICE=eth0
ONBOOT=yes
-STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""
@@ -2982,10 +3110,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):
@@ -3228,7 +3355,6 @@ 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_AUTOCONF=no
@@ -3237,7 +3363,6 @@ USERCTL=no
NETMASK=255.255.255.0
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -3263,7 +3388,6 @@ USERCTL=no
DEVICE=eno1
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -3277,6 +3401,7 @@ USERCTL=no
ONBOOT=yes
PHYSDEV=eno1
STARTMODE=auto
+ TYPE=Ethernet
USERCTL=no
VLAN=yes
""")
@@ -3306,7 +3431,6 @@ USERCTL=no
NETMASK=255.255.255.192
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Bond
USERCTL=no
"""),
@@ -3318,7 +3442,6 @@ USERCTL=no
NM_CONTROLLED=no
ONBOOT=yes
SLAVE=yes
- STARTMODE=auto
TYPE=Bond
USERCTL=no
"""),
@@ -3330,7 +3453,6 @@ USERCTL=no
NM_CONTROLLED=no
ONBOOT=yes
SLAVE=yes
- STARTMODE=auto
TYPE=Bond
USERCTL=no
""")
@@ -3354,7 +3476,6 @@ USERCTL=no
METRIC=100
NM_CONTROLLED=no
ONBOOT=yes
- STARTMODE=auto
TYPE=Ethernet
USERCTL=no
"""),
@@ -3377,7 +3498,7 @@ class TestOpenSuseSysConfigRendering(CiTestCase):
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')
@@ -3449,92 +3570,89 @@ class TestOpenSuseSysConfigRendering(CiTestCase):
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."""
- net_json = {
- "services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
- "type": "ipv4", "netmask": "255.255.252.0",
- "link": "tap1a81968a-79",
- "routes": [{
- "netmask": "0.0.0.0",
- "network": "0.0.0.0",
- "gateway": "172.19.3.254",
- }, {
- "netmask": "0.0.0.0", # A second default gateway
- "network": "0.0.0.0",
- "gateway": "172.20.3.254",
- }],
- "ip_address": "172.19.1.34", "id": "network0"
- }],
- "links": [
- {
- "ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
- },
- ],
- }
- macs = {'fa:16:3e:ed:9a:59': 'eth0'}
- render_dir = self.tmp_dir()
- network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
- renderer = self._get_renderer()
- with self.assertRaises(ValueError):
- renderer.render_network_state(ns, target=render_dir)
- self.assertEqual([], os.listdir(render_dir))
-
- def test_multiple_ipv6_default_gateways(self):
- """ValueError is raised when duplicate ipv6 gateways exist."""
- net_json = {
- "services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "public-ipv6",
- "type": "ipv6", "netmask": "",
- "link": "tap1a81968a-79",
- "routes": [{
- "gateway": "2001:DB8::1",
- "netmask": "::",
- "network": "::"
- }, {
- "gateway": "2001:DB9::1",
- "netmask": "::",
- "network": "::"
- }],
- "ip_address": "2001:DB8::10", "id": "network1"
- }],
- "links": [
- {
- "ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
- },
- ],
- }
- macs = {'fa:16:3e:ed:9a:59': 'eth0'}
- render_dir = self.tmp_dir()
- network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
- renderer = self._get_renderer()
- with self.assertRaises(ValueError):
- renderer.render_network_state(ns, target=render_dir)
- self.assertEqual([], os.listdir(render_dir))
+ # TODO(rjschwei): re-enable test once route writing is implemented
+ # for SUSE distros
+# def test_multiple_ipv4_default_gateways(self):
+# """ValueError is raised when duplicate ipv4 gateways exist."""
+# net_json = {
+# "services": [{"type": "dns", "address": "172.19.0.12"}],
+# "networks": [{
+# "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
+# "type": "ipv4", "netmask": "255.255.252.0",
+# "link": "tap1a81968a-79",
+# "routes": [{
+# "netmask": "0.0.0.0",
+# "network": "0.0.0.0",
+# "gateway": "172.19.3.254",
+# }, {
+# "netmask": "0.0.0.0", # A second default gateway
+# "network": "0.0.0.0",
+# "gateway": "172.20.3.254",
+# }],
+# "ip_address": "172.19.1.34", "id": "network0"
+# }],
+# "links": [
+# {
+# "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+# "mtu": None, "type": "bridge", "id":
+# "tap1a81968a-79",
+# "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+# },
+# ],
+# }
+# macs = {'fa:16:3e:ed:9a:59': 'eth0'}
+# render_dir = self.tmp_dir()
+# network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
+# ns = network_state.parse_net_config_data(network_cfg,
+# skip_broken=False)
+# renderer = self._get_renderer()
+# with self.assertRaises(ValueError):
+# renderer.render_network_state(ns, target=render_dir)
+# self.assertEqual([], os.listdir(render_dir))
+#
+# def test_multiple_ipv6_default_gateways(self):
+# """ValueError is raised when duplicate ipv6 gateways exist."""
+# net_json = {
+# "services": [{"type": "dns", "address": "172.19.0.12"}],
+# "networks": [{
+# "network_id": "public-ipv6",
+# "type": "ipv6", "netmask": "",
+# "link": "tap1a81968a-79",
+# "routes": [{
+# "gateway": "2001:DB8::1",
+# "netmask": "::",
+# "network": "::"
+# }, {
+# "gateway": "2001:DB9::1",
+# "netmask": "::",
+# "network": "::"
+# }],
+# "ip_address": "2001:DB8::10", "id": "network1"
+# }],
+# "links": [
+# {
+# "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+# "mtu": None, "type": "bridge", "id":
+# "tap1a81968a-79",
+# "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+# },
+# ],
+# }
+# macs = {'fa:16:3e:ed:9a:59': 'eth0'}
+# render_dir = self.tmp_dir()
+# network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
+# ns = network_state.parse_net_config_data(network_cfg,
+# skip_broken=False)
+# renderer = self._get_renderer()
+# with self.assertRaises(ValueError):
+# renderer.render_network_state(ns, target=render_dir)
+# self.assertEqual([], os.listdir(render_dir))
def test_openstack_rendering_samples(self):
for os_sample in OS_SAMPLES:
@@ -3567,18 +3685,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
@@ -3603,12 +3714,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
@@ -3679,6 +3785,30 @@ USERCTL=no
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
+ def test_simple_render_ipv6_slaac(self):
+ entry = NETWORK_CONFIGS['ipv6_slaac']
+ found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ self._compare_files_to_expected(entry[self.expected_name], found)
+ self._assert_headers(found)
+
+ def test_dhcpv6_stateless_config(self):
+ entry = NETWORK_CONFIGS['dhcpv6_stateless']
+ found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ self._compare_files_to_expected(entry[self.expected_name], found)
+ self._assert_headers(found)
+
+ def test_render_v4_and_v6(self):
+ entry = NETWORK_CONFIGS['v4_and_v6']
+ found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ self._compare_files_to_expected(entry[self.expected_name], found)
+ self._assert_headers(found)
+
+ def test_render_v6_and_v4(self):
+ entry = NETWORK_CONFIGS['v6_and_v4']
+ found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ self._compare_files_to_expected(entry[self.expected_name], found)
+ self._assert_headers(found)
+
class TestEniNetRendering(CiTestCase):
--
2.27.0