Blame cloudinit/net/sysconfig.py

Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service 751c4a
import copy
Packit Service 751c4a
import io
Packit Service a04d08
import os
Packit Service a04d08
import re
Packit Service a04d08
Packit Service 751c4a
from configobj import ConfigObj
Packit Service a04d08
Packit Service 11b429
from cloudinit import log as logging
Packit Service 11b429
from cloudinit import util
Packit Service 751c4a
from cloudinit import subp
Packit Service 751c4a
from cloudinit.distros.parsers import networkmanager_conf
Packit Service 751c4a
from cloudinit.distros.parsers import resolv_conf
Packit Service a04d08
Packit Service a04d08
from . import renderer
Packit Service a04d08
from .network_state import (
Packit Service a04d08
    is_ipv6_addr, net_prefix_to_ipv4_mask, subnet_is_ipv6, IPV6_DYNAMIC_TYPES)
Packit Service a04d08
Packit Service a04d08
LOG = logging.getLogger(__name__)
Packit Service a04d08
NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf"
Packit Service a04d08
KNOWN_DISTROS = ['centos', 'fedora', 'rhel', 'suse']
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def _make_header(sep='#'):
Packit Service a04d08
    lines = [
Packit Service a04d08
        "Created by cloud-init on instance boot automatically, do not edit.",
Packit Service a04d08
        "",
Packit Service a04d08
    ]
Packit Service a04d08
    for i in range(0, len(lines)):
Packit Service a04d08
        if lines[i]:
Packit Service a04d08
            lines[i] = sep + " " + lines[i]
Packit Service a04d08
        else:
Packit Service a04d08
            lines[i] = sep
Packit Service a04d08
    return "\n".join(lines)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def _is_default_route(route):
Packit Service a04d08
    default_nets = ('::', '0.0.0.0')
Packit Service a04d08
    return route['prefix'] == 0 and route['network'] in default_nets
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def _quote_value(value):
Packit Service a04d08
    if re.search(r"\s", value):
Packit Service a04d08
        # This doesn't handle complex cases...
Packit Service a04d08
        if value.startswith('"') and value.endswith('"'):
Packit Service a04d08
            return value
Packit Service a04d08
        else:
Packit Service a04d08
            return '"%s"' % value
Packit Service a04d08
    else:
Packit Service a04d08
        return value
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def enable_ifcfg_rh(path):
Packit Service a04d08
    """Add ifcfg-rh to NetworkManager.cfg plugins if main section is present"""
Packit Service a04d08
    config = ConfigObj(path)
Packit Service a04d08
    if 'main' in config:
Packit Service a04d08
        if 'plugins' in config['main']:
Packit Service a04d08
            if 'ifcfg-rh' in config['main']['plugins']:
Packit Service a04d08
                return
Packit Service a04d08
        else:
Packit Service a04d08
            config['main']['plugins'] = []
Packit Service a04d08
Packit Service a04d08
        if isinstance(config['main']['plugins'], list):
Packit Service a04d08
            config['main']['plugins'].append('ifcfg-rh')
Packit Service a04d08
        else:
Packit Service a04d08
            config['main']['plugins'] = [config['main']['plugins'], 'ifcfg-rh']
Packit Service a04d08
        config.write()
Packit Service a04d08
        LOG.debug('Enabled ifcfg-rh NetworkManager plugins')
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class ConfigMap(object):
Packit Service a04d08
    """Sysconfig like dictionary object."""
Packit Service a04d08
Packit Service a04d08
    # Why does redhat prefer yes/no to true/false??
Packit Service a04d08
    _bool_map = {
Packit Service a04d08
        True: 'yes',
Packit Service a04d08
        False: 'no',
Packit Service a04d08
    }
Packit Service a04d08
Packit Service a04d08
    def __init__(self):
Packit Service a04d08
        self._conf = {}
Packit Service a04d08
Packit Service a04d08
    def __setitem__(self, key, value):
Packit Service a04d08
        self._conf[key] = value
Packit Service a04d08
Packit Service a04d08
    def __getitem__(self, key):
Packit Service a04d08
        return self._conf[key]
Packit Service a04d08
Packit Service 751c4a
    def get(self, key):
Packit Service 751c4a
        return self._conf.get(key)
Packit Service 751c4a
Packit Service a04d08
    def __contains__(self, key):
Packit Service a04d08
        return key in self._conf
Packit Service a04d08
Packit Service a04d08
    def drop(self, key):
Packit Service a04d08
        self._conf.pop(key, None)
Packit Service a04d08
Packit Service a04d08
    def __len__(self):
Packit Service a04d08
        return len(self._conf)
Packit Service a04d08
Packit Service a04d08
    def to_string(self):
Packit Service 751c4a
        buf = io.StringIO()
Packit Service a04d08
        buf.write(_make_header())
Packit Service a04d08
        if self._conf:
Packit Service a04d08
            buf.write("\n")
Packit Service a04d08
        for key in sorted(self._conf.keys()):
Packit Service a04d08
            value = self._conf[key]
Packit Service a04d08
            if isinstance(value, bool):
Packit Service a04d08
                value = self._bool_map[value]
Packit Service 751c4a
            if not isinstance(value, str):
Packit Service a04d08
                value = str(value)
Packit Service a04d08
            buf.write("%s=%s\n" % (key, _quote_value(value)))
Packit Service a04d08
        return buf.getvalue()
Packit Service a04d08
Packit Service 751c4a
    def update(self, updates):
Packit Service 751c4a
        self._conf.update(updates)
Packit Service 751c4a
Packit Service a04d08
Packit Service a04d08
class Route(ConfigMap):
Packit Service a04d08
    """Represents a route configuration."""
Packit Service a04d08
Packit Service a04d08
    def __init__(self, route_name, base_sysconf_dir,
Packit Service a04d08
                 ipv4_tpl, ipv6_tpl):
Packit Service a04d08
        super(Route, self).__init__()
Packit Service a04d08
        self.last_idx = 1
Packit Service a04d08
        self.has_set_default_ipv4 = False
Packit Service a04d08
        self.has_set_default_ipv6 = False
Packit Service a04d08
        self._route_name = route_name
Packit Service a04d08
        self._base_sysconf_dir = base_sysconf_dir
Packit Service a04d08
        self.route_fn_tpl_ipv4 = ipv4_tpl
Packit Service a04d08
        self.route_fn_tpl_ipv6 = ipv6_tpl
Packit Service a04d08
Packit Service a04d08
    def copy(self):
Packit Service a04d08
        r = Route(self._route_name, self._base_sysconf_dir,
Packit Service a04d08
                  self.route_fn_tpl_ipv4, self.route_fn_tpl_ipv6)
Packit Service a04d08
        r._conf = self._conf.copy()
Packit Service a04d08
        r.last_idx = self.last_idx
Packit Service a04d08
        r.has_set_default_ipv4 = self.has_set_default_ipv4
Packit Service a04d08
        r.has_set_default_ipv6 = self.has_set_default_ipv6
Packit Service a04d08
        return r
Packit Service a04d08
Packit Service a04d08
    @property
Packit Service a04d08
    def path_ipv4(self):
Packit Service a04d08
        return self.route_fn_tpl_ipv4 % ({'base': self._base_sysconf_dir,
Packit Service a04d08
                                          'name': self._route_name})
Packit Service a04d08
Packit Service a04d08
    @property
Packit Service a04d08
    def path_ipv6(self):
Packit Service a04d08
        return self.route_fn_tpl_ipv6 % ({'base': self._base_sysconf_dir,
Packit Service a04d08
                                          'name': self._route_name})
Packit Service a04d08
Packit Service a04d08
    def is_ipv6_route(self, address):
Packit Service a04d08
        return ':' in address
Packit Service a04d08
Packit Service a04d08
    def to_string(self, proto="ipv4"):
Packit Service a04d08
        # only accept ipv4 and ipv6
Packit Service a04d08
        if proto not in ['ipv4', 'ipv6']:
Packit Service a04d08
            raise ValueError("Unknown protocol '%s'" % (str(proto)))
Packit Service 751c4a
        buf = io.StringIO()
Packit Service a04d08
        buf.write(_make_header())
Packit Service a04d08
        if self._conf:
Packit Service a04d08
            buf.write("\n")
Packit Service a04d08
        # need to reindex IPv4 addresses
Packit Service a04d08
        # (because Route can contain a mix of IPv4 and IPv6)
Packit Service a04d08
        reindex = -1
Packit Service a04d08
        for key in sorted(self._conf.keys()):
Packit Service a04d08
            if 'ADDRESS' in key:
Packit Service a04d08
                index = key.replace('ADDRESS', '')
Packit Service a04d08
                address_value = str(self._conf[key])
Packit Service a04d08
                # only accept combinations:
Packit Service a04d08
                # if proto ipv6 only display ipv6 routes
Packit Service a04d08
                # if proto ipv4 only display ipv4 routes
Packit Service a04d08
                # do not add ipv6 routes if proto is ipv4
Packit Service a04d08
                # do not add ipv4 routes if proto is ipv6
Packit Service a04d08
                # (this array will contain a mix of ipv4 and ipv6)
Packit Service a04d08
                if proto == "ipv4" and not self.is_ipv6_route(address_value):
Packit Service a04d08
                    netmask_value = str(self._conf['NETMASK' + index])
Packit Service a04d08
                    gateway_value = str(self._conf['GATEWAY' + index])
Packit Service a04d08
                    # increase IPv4 index
Packit Service a04d08
                    reindex = reindex + 1
Packit Service a04d08
                    buf.write("%s=%s\n" % ('ADDRESS' + str(reindex),
Packit Service a04d08
                                           _quote_value(address_value)))
Packit Service a04d08
                    buf.write("%s=%s\n" % ('GATEWAY' + str(reindex),
Packit Service a04d08
                                           _quote_value(gateway_value)))
Packit Service a04d08
                    buf.write("%s=%s\n" % ('NETMASK' + str(reindex),
Packit Service a04d08
                                           _quote_value(netmask_value)))
Packit Service a04d08
                    metric_key = 'METRIC' + index
Packit Service a04d08
                    if metric_key in self._conf:
Packit Service a04d08
                        metric_value = str(self._conf['METRIC' + index])
Packit Service a04d08
                        buf.write("%s=%s\n" % ('METRIC' + str(reindex),
Packit Service a04d08
                                               _quote_value(metric_value)))
Packit Service a04d08
                elif proto == "ipv6" and self.is_ipv6_route(address_value):
Packit Service a04d08
                    netmask_value = str(self._conf['NETMASK' + index])
Packit Service a04d08
                    gateway_value = str(self._conf['GATEWAY' + index])
Packit Service a04d08
                    metric_value = (
Packit Service a04d08
                        'metric ' + str(self._conf['METRIC' + index])
Packit Service a04d08
                        if 'METRIC' + index in self._conf else '')
Packit Service a04d08
                    buf.write(
Packit Service a04d08
                        "%s/%s via %s %s dev %s\n" % (address_value,
Packit Service a04d08
                                                      netmask_value,
Packit Service a04d08
                                                      gateway_value,
Packit Service a04d08
                                                      metric_value,
Packit Service a04d08
                                                      self._route_name))
Packit Service a04d08
Packit Service a04d08
        return buf.getvalue()
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class NetInterface(ConfigMap):
Packit Service a04d08
    """Represents a sysconfig/networking-script (and its config + children)."""
Packit Service a04d08
Packit Service a04d08
    iface_types = {
Packit Service a04d08
        'ethernet': 'Ethernet',
Packit Service a04d08
        'bond': 'Bond',
Packit Service a04d08
        'bridge': 'Bridge',
Packit Service a04d08
        'infiniband': 'InfiniBand',
Packit Service a04d08
    }
Packit Service a04d08
Packit Service a04d08
    def __init__(self, iface_name, base_sysconf_dir, templates,
Packit Service a04d08
                 kind='ethernet'):
Packit Service a04d08
        super(NetInterface, self).__init__()
Packit Service a04d08
        self.children = []
Packit Service a04d08
        self.templates = templates
Packit Service a04d08
        route_tpl = self.templates.get('route_templates')
Packit Service a04d08
        self.routes = Route(iface_name, base_sysconf_dir,
Packit Service a04d08
                            ipv4_tpl=route_tpl.get('ipv4'),
Packit Service a04d08
                            ipv6_tpl=route_tpl.get('ipv6'))
Packit Service a04d08
        self.iface_fn_tpl = self.templates.get('iface_templates')
Packit Service a04d08
        self.kind = kind
Packit Service a04d08
Packit Service a04d08
        self._iface_name = iface_name
Packit Service a04d08
        self._conf['DEVICE'] = iface_name
Packit Service a04d08
        self._base_sysconf_dir = base_sysconf_dir
Packit Service a04d08
Packit Service a04d08
    @property
Packit Service a04d08
    def name(self):
Packit Service a04d08
        return self._iface_name
Packit Service a04d08
Packit Service a04d08
    @name.setter
Packit Service a04d08
    def name(self, iface_name):
Packit Service a04d08
        self._iface_name = iface_name
Packit Service a04d08
        self._conf['DEVICE'] = iface_name
Packit Service a04d08
Packit Service a04d08
    @property
Packit Service a04d08
    def kind(self):
Packit Service a04d08
        return self._kind
Packit Service a04d08
Packit Service a04d08
    @kind.setter
Packit Service a04d08
    def kind(self, kind):
Packit Service a04d08
        if kind not in self.iface_types:
Packit Service a04d08
            raise ValueError(kind)
Packit Service a04d08
        self._kind = kind
Packit Service a04d08
        self._conf['TYPE'] = self.iface_types[kind]
Packit Service a04d08
Packit Service a04d08
    @property
Packit Service a04d08
    def path(self):
Packit Service a04d08
        return self.iface_fn_tpl % ({'base': self._base_sysconf_dir,
Packit Service a04d08
                                     'name': self.name})
Packit Service a04d08
Packit Service a04d08
    def copy(self, copy_children=False, copy_routes=False):
Packit Service a04d08
        c = NetInterface(self.name, self._base_sysconf_dir,
Packit Service a04d08
                         self.templates, kind=self._kind)
Packit Service a04d08
        c._conf = self._conf.copy()
Packit Service a04d08
        if copy_children:
Packit Service a04d08
            c.children = list(self.children)
Packit Service a04d08
        if copy_routes:
Packit Service a04d08
            c.routes = self.routes.copy()
Packit Service a04d08
        return c
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class Renderer(renderer.Renderer):
Packit Service a04d08
    """Renders network information in a /etc/sysconfig format."""
Packit Service a04d08
Packit Service a04d08
    # See: https://access.redhat.com/documentation/en-US/\
Packit Service a04d08
    #      Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/\
Packit Service a04d08
    #      s1-networkscripts-interfaces.html (or other docs for
Packit Service a04d08
    #                                         details about this)
Packit Service a04d08
Packit Service 751c4a
    iface_defaults = {
Packit Service b35483
        'rhel': {'ONBOOT': True, 'USERCTL': False,
Packit Service 751c4a
                 'BOOTPROTO': 'none'},
Packit Service 751c4a
        'suse': {'BOOTPROTO': 'static', 'STARTMODE': 'auto'},
Packit Service 751c4a
    }
Packit Service 751c4a
Packit Service 751c4a
    cfg_key_maps = {
Packit Service 751c4a
        'rhel': {
Packit Service 751c4a
            'accept-ra': 'IPV6_FORCE_ACCEPT_RA',
Packit Service 751c4a
            'bridge_stp': 'STP',
Packit Service 751c4a
            'bridge_ageing': 'AGEING',
Packit Service 751c4a
            'bridge_bridgeprio': 'PRIO',
Packit Service 751c4a
            'mac_address': 'HWADDR',
Packit Service 751c4a
            'mtu': 'MTU',
Packit Service 751c4a
        },
Packit Service 751c4a
        'suse': {
Packit Service 751c4a
            'bridge_stp': 'BRIDGE_STP',
Packit Service 751c4a
            'bridge_ageing': 'BRIDGE_AGEINGTIME',
Packit Service 751c4a
            'bridge_bridgeprio': 'BRIDGE_PRIORITY',
Packit Service 751c4a
            'mac_address': 'LLADDR',
Packit Service 751c4a
            'mtu': 'MTU',
Packit Service 751c4a
        },
Packit Service 751c4a
    }
Packit Service a04d08
Packit Service a04d08
    # If these keys exist, then their values will be used to form
Packit Service a04d08
    # a BONDING_OPTS grouping; otherwise no grouping will be set.
Packit Service a04d08
    bond_tpl_opts = tuple([
Packit Service a04d08
        ('bond_mode', "mode=%s"),
Packit Service a04d08
        ('bond_xmit_hash_policy', "xmit_hash_policy=%s"),
Packit Service a04d08
        ('bond_miimon', "miimon=%s"),
Packit Service a04d08
        ('bond_min_links', "min_links=%s"),
Packit Service a04d08
        ('bond_arp_interval', "arp_interval=%s"),
Packit Service a04d08
        ('bond_arp_ip_target', "arp_ip_target=%s"),
Packit Service a04d08
        ('bond_arp_validate', "arp_validate=%s"),
Packit Service a04d08
        ('bond_ad_select', "ad_select=%s"),
Packit Service a04d08
        ('bond_num_grat_arp', "num_grat_arp=%s"),
Packit Service a04d08
        ('bond_downdelay', "downdelay=%s"),
Packit Service a04d08
        ('bond_updelay', "updelay=%s"),
Packit Service a04d08
        ('bond_lacp_rate', "lacp_rate=%s"),
Packit Service a04d08
        ('bond_fail_over_mac', "fail_over_mac=%s"),
Packit Service a04d08
        ('bond_primary', "primary=%s"),
Packit Service a04d08
        ('bond_primary_reselect', "primary_reselect=%s"),
Packit Service a04d08
    ])
Packit Service a04d08
Packit Service a04d08
    templates = {}
Packit Service a04d08
Packit Service a04d08
    def __init__(self, config=None):
Packit Service a04d08
        if not config:
Packit Service a04d08
            config = {}
Packit Service a04d08
        self.sysconf_dir = config.get('sysconf_dir', 'etc/sysconfig')
Packit Service a04d08
        self.netrules_path = config.get(
Packit Service a04d08
            'netrules_path', 'etc/udev/rules.d/70-persistent-net.rules')
Packit Service a04d08
        self.dns_path = config.get('dns_path', 'etc/resolv.conf')
Packit Service a04d08
        nm_conf_path = 'etc/NetworkManager/conf.d/99-cloud-init.conf'
Packit Service a04d08
        self.networkmanager_conf_path = config.get('networkmanager_conf_path',
Packit Service a04d08
                                                   nm_conf_path)
Packit Service a04d08
        self.templates = {
Packit Service a04d08
            'control': config.get('control'),
Packit Service a04d08
            'iface_templates': config.get('iface_templates'),
Packit Service a04d08
            'route_templates': config.get('route_templates'),
Packit Service a04d08
        }
Packit Service 751c4a
        self.flavor = config.get('flavor', 'rhel')
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_iface_shared(cls, iface, iface_cfg, flavor):
Packit Service 751c4a
        flavor_defaults = copy.deepcopy(cls.iface_defaults.get(flavor, {}))
Packit Service 751c4a
        iface_cfg.update(flavor_defaults)
Packit Service a04d08
Packit Service 751c4a
        for old_key in ('mac_address', 'mtu', 'accept-ra'):
Packit Service a04d08
            old_value = iface.get(old_key)
Packit Service a04d08
            if old_value is not None:
Packit Service a04d08
                # only set HWADDR on physical interfaces
Packit Service a04d08
                if (old_key == 'mac_address' and
Packit Service a04d08
                   iface['type'] not in ['physical', 'infiniband']):
Packit Service a04d08
                    continue
Packit Service 751c4a
                new_key = cls.cfg_key_maps[flavor].get(old_key)
Packit Service 751c4a
                if new_key:
Packit Service 751c4a
                    iface_cfg[new_key] = old_value
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_subnets(cls, iface_cfg, subnets, has_default_route, flavor):
Packit Service a04d08
        # setting base values
Packit Service 751c4a
        if flavor == 'suse':
Packit Service 751c4a
            iface_cfg['BOOTPROTO'] = 'static'
Packit Service 751c4a
            if 'BRIDGE' in iface_cfg:
Packit Service 751c4a
                iface_cfg['BOOTPROTO'] = 'dhcp'
Packit Service 751c4a
                iface_cfg.drop('BRIDGE')
Packit Service 751c4a
        else:
Packit Service 751c4a
            iface_cfg['BOOTPROTO'] = 'none'
Packit Service a04d08
Packit Service a04d08
        # modifying base values according to subnets
Packit Service a04d08
        for i, subnet in enumerate(subnets, start=len(iface_cfg.children)):
Packit Service a04d08
            mtu_key = 'MTU'
Packit Service a04d08
            subnet_type = subnet.get('type')
Packit Service a04d08
            if subnet_type == 'dhcp6' or subnet_type == 'ipv6_dhcpv6-stateful':
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    # User wants dhcp for both protocols
Packit Service 751c4a
                    if iface_cfg['BOOTPROTO'] == 'dhcp4':
Packit Service 751c4a
                        iface_cfg['BOOTPROTO'] = 'dhcp'
Packit Service 751c4a
                    else:
Packit Service 751c4a
                        # Only IPv6 is DHCP, IPv4 may be static
Packit Service 751c4a
                        iface_cfg['BOOTPROTO'] = 'dhcp6'
Packit Service 751c4a
                    iface_cfg['DHCLIENT6_MODE'] = 'managed'
Packit Service 751c4a
                else:
Packit Service 751c4a
                    iface_cfg['IPV6INIT'] = True
Packit Service 751c4a
                    # Configure network settings using DHCPv6
Packit Service 751c4a
                    iface_cfg['DHCPV6C'] = True
Packit Service a04d08
            elif subnet_type == 'ipv6_dhcpv6-stateless':
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    # User wants dhcp for both protocols
Packit Service 751c4a
                    if iface_cfg['BOOTPROTO'] == 'dhcp4':
Packit Service 751c4a
                        iface_cfg['BOOTPROTO'] = 'dhcp'
Packit Service 751c4a
                    else:
Packit Service 751c4a
                        # Only IPv6 is DHCP, IPv4 may be static
Packit Service 751c4a
                        iface_cfg['BOOTPROTO'] = 'dhcp6'
Packit Service 751c4a
                    iface_cfg['DHCLIENT6_MODE'] = 'info'
Packit Service 751c4a
                else:
Packit Service 751c4a
                    iface_cfg['IPV6INIT'] = True
Packit Service 751c4a
                    # Configure network settings using SLAAC from RAs and
Packit Service 751c4a
                    # optional info from dhcp server using DHCPv6
Packit Service 751c4a
                    iface_cfg['IPV6_AUTOCONF'] = True
Packit Service 751c4a
                    iface_cfg['DHCPV6C'] = True
Packit Service 751c4a
                    # Use Information-request to get only stateless
Packit Service 751c4a
                    # configuration parameters (i.e., without address).
Packit Service 751c4a
                    iface_cfg['DHCPV6C_OPTIONS'] = '-S'
Packit Service a04d08
            elif subnet_type == 'ipv6_slaac':
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    # User wants dhcp for both protocols
Packit Service 751c4a
                    if iface_cfg['BOOTPROTO'] == 'dhcp4':
Packit Service 751c4a
                        iface_cfg['BOOTPROTO'] = 'dhcp'
Packit Service 751c4a
                    else:
Packit Service 751c4a
                        # Only IPv6 is DHCP, IPv4 may be static
Packit Service 751c4a
                        iface_cfg['BOOTPROTO'] = 'dhcp6'
Packit Service 751c4a
                    iface_cfg['DHCLIENT6_MODE'] = 'info'
Packit Service 751c4a
                else:
Packit Service 751c4a
                    iface_cfg['IPV6INIT'] = True
Packit Service 751c4a
                    # Configure network settings using SLAAC from RAs
Packit Service 751c4a
                    iface_cfg['IPV6_AUTOCONF'] = True
Packit Service a04d08
            elif subnet_type in ['dhcp4', 'dhcp']:
Packit Service 751c4a
                bootproto_in = iface_cfg['BOOTPROTO']
Packit Service a04d08
                iface_cfg['BOOTPROTO'] = 'dhcp'
Packit Service 751c4a
                if flavor == 'suse' and subnet_type == 'dhcp4':
Packit Service 751c4a
                    # If dhcp6 is already specified the user wants dhcp
Packit Service 751c4a
                    # for both protocols
Packit Service 751c4a
                    if bootproto_in != 'dhcp6':
Packit Service 751c4a
                        # Only IPv4 is DHCP, IPv6 may be static
Packit Service 751c4a
                        iface_cfg['BOOTPROTO'] = 'dhcp4'
Packit Service 751c4a
            elif subnet_type in ['static', 'static6']:
Packit Service 751c4a
                # RH info
Packit Service a04d08
                # grep BOOTPROTO sysconfig.txt -A2 | head -3
Packit Service a04d08
                # BOOTPROTO=none|bootp|dhcp
Packit Service a04d08
                # 'bootp' or 'dhcp' cause a DHCP client
Packit Service a04d08
                # to run on the device. Any other
Packit Service a04d08
                # value causes any static configuration
Packit Service a04d08
                # in the file to be applied.
Packit Service 751c4a
                if subnet_is_ipv6(subnet) and flavor != 'suse':
Packit Service a04d08
                    mtu_key = 'IPV6_MTU'
Packit Service a04d08
                    iface_cfg['IPV6INIT'] = True
Packit Service a04d08
                if 'mtu' in subnet:
Packit Service a04d08
                    mtu_mismatch = bool(mtu_key in iface_cfg and
Packit Service a04d08
                                        subnet['mtu'] != iface_cfg[mtu_key])
Packit Service a04d08
                    if mtu_mismatch:
Packit Service a04d08
                        LOG.warning(
Packit Service a04d08
                            'Network config: ignoring %s device-level mtu:%s'
Packit Service a04d08
                            ' because ipv4 subnet-level mtu:%s provided.',
Packit Service a04d08
                            iface_cfg.name, iface_cfg[mtu_key], subnet['mtu'])
Packit Service 751c4a
                    if subnet_is_ipv6(subnet):
Packit Service 751c4a
                        if flavor == 'suse':
Packit Service 751c4a
                            # TODO(rjschwei) write mtu setting to
Packit Service 751c4a
                            # /etc/sysctl.d/
Packit Service 751c4a
                            pass
Packit Service 751c4a
                        else:
Packit Service 751c4a
                            iface_cfg[mtu_key] = subnet['mtu']
Packit Service 751c4a
                    else:
Packit Service 751c4a
                        iface_cfg[mtu_key] = subnet['mtu']
Packit Service a04d08
            elif subnet_type == 'manual':
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    LOG.debug('Unknown subnet type setting "%s"', subnet_type)
Packit Service 751c4a
                else:
Packit Service 751c4a
                    # If the subnet has an MTU setting, then ONBOOT=True
Packit Service 751c4a
                    # to apply the setting
Packit Service 751c4a
                    iface_cfg['ONBOOT'] = mtu_key in iface_cfg
Packit Service a04d08
            else:
Packit Service a04d08
                raise ValueError("Unknown subnet type '%s' found"
Packit Service a04d08
                                 " for interface '%s'" % (subnet_type,
Packit Service a04d08
                                                          iface_cfg.name))
Packit Service a04d08
            if subnet.get('control') == 'manual':
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    iface_cfg['STARTMODE'] = 'manual'
Packit Service 751c4a
                else:
Packit Service 751c4a
                    iface_cfg['ONBOOT'] = False
Packit Service a04d08
Packit Service a04d08
        # set IPv4 and IPv6 static addresses
Packit Service a04d08
        ipv4_index = -1
Packit Service a04d08
        ipv6_index = -1
Packit Service a04d08
        for i, subnet in enumerate(subnets, start=len(iface_cfg.children)):
Packit Service a04d08
            subnet_type = subnet.get('type')
Packit Service a04d08
            # metric may apply to both dhcp and static config
Packit Service a04d08
            if 'metric' in subnet:
Packit Service 751c4a
                if flavor != 'suse':
Packit Service 751c4a
                    iface_cfg['METRIC'] = subnet['metric']
Packit Service 751c4a
            if subnet_type in ['dhcp', 'dhcp4']:
Packit Service 751c4a
                # On SUSE distros 'DHCLIENT_SET_DEFAULT_ROUTE' is a global
Packit Service 751c4a
                # setting in /etc/sysconfig/network/dhcp
Packit Service 751c4a
                if flavor != 'suse':
Packit Service 751c4a
                    if has_default_route and iface_cfg['BOOTPROTO'] != 'none':
Packit Service 751c4a
                        iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = False
Packit Service a04d08
                continue
Packit Service a04d08
            elif subnet_type in IPV6_DYNAMIC_TYPES:
Packit Service a04d08
                continue
Packit Service 751c4a
            elif subnet_type in ['static', 'static6']:
Packit Service a04d08
                if subnet_is_ipv6(subnet):
Packit Service a04d08
                    ipv6_index = ipv6_index + 1
Packit Service a04d08
                    ipv6_cidr = "%s/%s" % (subnet['address'], subnet['prefix'])
Packit Service a04d08
                    if ipv6_index == 0:
Packit Service 751c4a
                        if flavor == 'suse':
Packit Service 751c4a
                            iface_cfg['IPADDR6'] = ipv6_cidr
Packit Service 751c4a
                        else:
Packit Service 751c4a
                            iface_cfg['IPV6ADDR'] = ipv6_cidr
Packit Service a04d08
                    elif ipv6_index == 1:
Packit Service 751c4a
                        if flavor == 'suse':
Packit Service 751c4a
                            iface_cfg['IPADDR6_1'] = ipv6_cidr
Packit Service 751c4a
                        else:
Packit Service 751c4a
                            iface_cfg['IPV6ADDR_SECONDARIES'] = ipv6_cidr
Packit Service a04d08
                    else:
Packit Service 751c4a
                        if flavor == 'suse':
Packit Service 751c4a
                            iface_cfg['IPADDR6_%d' % ipv6_index] = ipv6_cidr
Packit Service 751c4a
                        else:
Packit Service 751c4a
                            iface_cfg['IPV6ADDR_SECONDARIES'] += \
Packit Service 751c4a
                                " " + ipv6_cidr
Packit Service a04d08
                else:
Packit Service a04d08
                    ipv4_index = ipv4_index + 1
Packit Service a04d08
                    suff = "" if ipv4_index == 0 else str(ipv4_index)
Packit Service a04d08
                    iface_cfg['IPADDR' + suff] = subnet['address']
Packit Service a04d08
                    iface_cfg['NETMASK' + suff] = \
Packit Service a04d08
                        net_prefix_to_ipv4_mask(subnet['prefix'])
Packit Service a04d08
Packit Service 751c4a
                if 'gateway' in subnet and flavor != 'suse':
Packit Service a04d08
                    iface_cfg['DEFROUTE'] = True
Packit Service a04d08
                    if is_ipv6_addr(subnet['gateway']):
Packit Service a04d08
                        iface_cfg['IPV6_DEFAULTGW'] = subnet['gateway']
Packit Service a04d08
                    else:
Packit Service a04d08
                        iface_cfg['GATEWAY'] = subnet['gateway']
Packit Service a04d08
Packit Service 751c4a
                if 'dns_search' in subnet and flavor != 'suse':
Packit Service a04d08
                    iface_cfg['DOMAIN'] = ' '.join(subnet['dns_search'])
Packit Service a04d08
Packit Service 751c4a
                if 'dns_nameservers' in subnet and flavor != 'suse':
Packit Service a04d08
                    if len(subnet['dns_nameservers']) > 3:
Packit Service a04d08
                        # per resolv.conf(5) MAXNS sets this to 3.
Packit Service a04d08
                        LOG.debug("%s has %d entries in dns_nameservers. "
Packit Service a04d08
                                  "Only 3 are used.", iface_cfg.name,
Packit Service a04d08
                                  len(subnet['dns_nameservers']))
Packit Service a04d08
                    for i, k in enumerate(subnet['dns_nameservers'][:3], 1):
Packit Service a04d08
                        iface_cfg['DNS' + str(i)] = k
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets, flavor):
Packit Service 751c4a
        # TODO(rjschwei): route configuration on SUSE distro happens via
Packit Service 751c4a
        # ifroute-* files, see lp#1812117. SUSE currently carries a local
Packit Service 751c4a
        # patch in their package.
Packit Service 751c4a
        if flavor == 'suse':
Packit Service 751c4a
            return
Packit Service a04d08
        for _, subnet in enumerate(subnets, start=len(iface_cfg.children)):
Packit Service a04d08
            subnet_type = subnet.get('type')
Packit Service a04d08
            for route in subnet.get('routes', []):
Packit Service a04d08
                is_ipv6 = subnet.get('ipv6') or is_ipv6_addr(route['gateway'])
Packit Service a04d08
Packit Service a04d08
                # Any dynamic configuration method, slaac, dhcpv6-stateful/
Packit Service a04d08
                # stateless should get router information from router RA's.
Packit Service a04d08
                if (_is_default_route(route) and subnet_type not in
Packit Service a04d08
                        IPV6_DYNAMIC_TYPES):
Packit Service a04d08
                    if (
Packit Service a04d08
                            (subnet.get('ipv4') and
Packit Service a04d08
                             route_cfg.has_set_default_ipv4) or
Packit Service a04d08
                            (subnet.get('ipv6') and
Packit Service a04d08
                             route_cfg.has_set_default_ipv6)
Packit Service a04d08
                    ):
Packit Service a04d08
                        raise ValueError("Duplicate declaration of default "
Packit Service a04d08
                                         "route found for interface '%s'"
Packit Service a04d08
                                         % (iface_cfg.name))
Packit Service a04d08
                    # NOTE(harlowja): ipv6 and ipv4 default gateways
Packit Service a04d08
                    gw_key = 'GATEWAY0'
Packit Service a04d08
                    nm_key = 'NETMASK0'
Packit Service a04d08
                    addr_key = 'ADDRESS0'
Packit Service a04d08
                    # The owning interface provides the default route.
Packit Service a04d08
                    #
Packit Service a04d08
                    # TODO(harlowja): add validation that no other iface has
Packit Service a04d08
                    # also provided the default route?
Packit Service a04d08
                    iface_cfg['DEFROUTE'] = True
Packit Service 751c4a
                    if iface_cfg['BOOTPROTO'] in ('dhcp', 'dhcp4'):
Packit Service a04d08
                        iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = True
Packit Service a04d08
                    if 'gateway' in route:
Packit Service a04d08
                        if is_ipv6:
Packit Service a04d08
                            iface_cfg['IPV6_DEFAULTGW'] = route['gateway']
Packit Service a04d08
                            route_cfg.has_set_default_ipv6 = True
Packit Service a04d08
                        else:
Packit Service a04d08
                            iface_cfg['GATEWAY'] = route['gateway']
Packit Service a04d08
                            route_cfg.has_set_default_ipv4 = True
Packit Service a04d08
                    if 'metric' in route:
Packit Service a04d08
                        iface_cfg['METRIC'] = route['metric']
Packit Service a04d08
Packit Service a04d08
                else:
Packit Service a04d08
                    gw_key = 'GATEWAY%s' % route_cfg.last_idx
Packit Service a04d08
                    nm_key = 'NETMASK%s' % route_cfg.last_idx
Packit Service a04d08
                    addr_key = 'ADDRESS%s' % route_cfg.last_idx
Packit Service a04d08
                    metric_key = 'METRIC%s' % route_cfg.last_idx
Packit Service a04d08
                    route_cfg.last_idx += 1
Packit Service a04d08
                    # add default routes only to ifcfg files, not
Packit Service a04d08
                    # to route-* or route6-*
Packit Service a04d08
                    for (old_key, new_key) in [('gateway', gw_key),
Packit Service a04d08
                                               ('metric', metric_key),
Packit Service a04d08
                                               ('netmask', nm_key),
Packit Service a04d08
                                               ('network', addr_key)]:
Packit Service a04d08
                        if old_key in route:
Packit Service a04d08
                            route_cfg[new_key] = route[old_key]
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service a04d08
    def _render_bonding_opts(cls, iface_cfg, iface):
Packit Service a04d08
        bond_opts = []
Packit Service a04d08
        for (bond_key, value_tpl) in cls.bond_tpl_opts:
Packit Service a04d08
            # Seems like either dash or underscore is possible?
Packit Service a04d08
            bond_keys = [bond_key, bond_key.replace("_", "-")]
Packit Service a04d08
            for bond_key in bond_keys:
Packit Service a04d08
                if bond_key in iface:
Packit Service a04d08
                    bond_value = iface[bond_key]
Packit Service a04d08
                    if isinstance(bond_value, (tuple, list)):
Packit Service a04d08
                        bond_value = " ".join(bond_value)
Packit Service a04d08
                    bond_opts.append(value_tpl % (bond_value))
Packit Service a04d08
                    break
Packit Service a04d08
        if bond_opts:
Packit Service a04d08
            iface_cfg['BONDING_OPTS'] = " ".join(bond_opts)
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_physical_interfaces(
Packit Service 751c4a
            cls, network_state, iface_contents, flavor
Packit Service 751c4a
    ):
Packit Service a04d08
        physical_filter = renderer.filter_by_physical
Packit Service a04d08
        for iface in network_state.iter_interfaces(physical_filter):
Packit Service a04d08
            iface_name = iface['name']
Packit Service a04d08
            iface_subnets = iface.get("subnets", [])
Packit Service a04d08
            iface_cfg = iface_contents[iface_name]
Packit Service a04d08
            route_cfg = iface_cfg.routes
Packit Service a04d08
Packit Service a04d08
            cls._render_subnets(
Packit Service 751c4a
                iface_cfg, iface_subnets, network_state.has_default_route,
Packit Service 751c4a
                flavor
Packit Service 751c4a
            )
Packit Service 751c4a
            cls._render_subnet_routes(
Packit Service 751c4a
                iface_cfg, route_cfg, iface_subnets, flavor
Packit Service a04d08
            )
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_bond_interfaces(cls, network_state, iface_contents, flavor):
Packit Service a04d08
        bond_filter = renderer.filter_by_type('bond')
Packit Service a04d08
        slave_filter = renderer.filter_by_attr('bond-master')
Packit Service a04d08
        for iface in network_state.iter_interfaces(bond_filter):
Packit Service a04d08
            iface_name = iface['name']
Packit Service a04d08
            iface_cfg = iface_contents[iface_name]
Packit Service a04d08
            cls._render_bonding_opts(iface_cfg, iface)
Packit Service a04d08
Packit Service a04d08
            # Ensure that the master interface (and any of its children)
Packit Service a04d08
            # are actually marked as being bond types...
Packit Service a04d08
            master_cfgs = [iface_cfg]
Packit Service a04d08
            master_cfgs.extend(iface_cfg.children)
Packit Service a04d08
            for master_cfg in master_cfgs:
Packit Service a04d08
                master_cfg['BONDING_MASTER'] = True
Packit Service 751c4a
                if flavor != 'suse':
Packit Service 751c4a
                    master_cfg.kind = 'bond'
Packit Service a04d08
Packit Service a04d08
            if iface.get('mac_address'):
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    iface_cfg['LLADDR'] = iface.get('mac_address')
Packit Service 751c4a
                else:
Packit Service 751c4a
                    iface_cfg['MACADDR'] = iface.get('mac_address')
Packit Service a04d08
Packit Service a04d08
            iface_subnets = iface.get("subnets", [])
Packit Service a04d08
            route_cfg = iface_cfg.routes
Packit Service a04d08
            cls._render_subnets(
Packit Service 751c4a
                iface_cfg, iface_subnets, network_state.has_default_route,
Packit Service 751c4a
                flavor
Packit Service 751c4a
            )
Packit Service 751c4a
            cls._render_subnet_routes(
Packit Service 751c4a
                iface_cfg, route_cfg, iface_subnets, flavor
Packit Service a04d08
            )
Packit Service a04d08
Packit Service a04d08
            # iter_interfaces on network-state is not sorted to produce
Packit Service a04d08
            # consistent numbers we need to sort.
Packit Service a04d08
            bond_slaves = sorted(
Packit Service a04d08
                [slave_iface['name'] for slave_iface in
Packit Service a04d08
                 network_state.iter_interfaces(slave_filter)
Packit Service a04d08
                 if slave_iface['bond-master'] == iface_name])
Packit Service a04d08
Packit Service a04d08
            for index, bond_slave in enumerate(bond_slaves):
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    slavestr = 'BONDING_SLAVE_%s' % index
Packit Service 751c4a
                else:
Packit Service 751c4a
                    slavestr = 'BONDING_SLAVE%s' % index
Packit Service a04d08
                iface_cfg[slavestr] = bond_slave
Packit Service a04d08
Packit Service a04d08
                slave_cfg = iface_contents[bond_slave]
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    slave_cfg['BOOTPROTO'] = 'none'
Packit Service 751c4a
                    slave_cfg['STARTMODE'] = 'hotplug'
Packit Service 751c4a
                else:
Packit Service 751c4a
                    slave_cfg['MASTER'] = iface_name
Packit Service 751c4a
                    slave_cfg['SLAVE'] = True
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_vlan_interfaces(cls, network_state, iface_contents, flavor):
Packit Service a04d08
        vlan_filter = renderer.filter_by_type('vlan')
Packit Service a04d08
        for iface in network_state.iter_interfaces(vlan_filter):
Packit Service a04d08
            iface_name = iface['name']
Packit Service a04d08
            iface_cfg = iface_contents[iface_name]
Packit Service 751c4a
            if flavor == 'suse':
Packit Service 751c4a
                vlan_id = iface.get('vlan_id')
Packit Service 751c4a
                if vlan_id:
Packit Service 751c4a
                    iface_cfg['VLAN_ID'] = vlan_id
Packit Service 751c4a
                iface_cfg['ETHERDEVICE'] = iface_name[:iface_name.rfind('.')]
Packit Service 751c4a
            else:
Packit Service 751c4a
                iface_cfg['VLAN'] = True
Packit Service 751c4a
                iface_cfg['PHYSDEV'] = iface_name[:iface_name.rfind('.')]
Packit Service a04d08
Packit Service a04d08
            iface_subnets = iface.get("subnets", [])
Packit Service a04d08
            route_cfg = iface_cfg.routes
Packit Service a04d08
            cls._render_subnets(
Packit Service 751c4a
                iface_cfg, iface_subnets, network_state.has_default_route,
Packit Service 751c4a
                flavor
Packit Service 751c4a
            )
Packit Service 751c4a
            cls._render_subnet_routes(
Packit Service 751c4a
                iface_cfg, route_cfg, iface_subnets, flavor
Packit Service a04d08
            )
Packit Service a04d08
Packit Service a04d08
    @staticmethod
Packit Service a04d08
    def _render_dns(network_state, existing_dns_path=None):
Packit Service a04d08
        # skip writing resolv.conf if network_state doesn't include any input.
Packit Service a04d08
        if not any([len(network_state.dns_nameservers),
Packit Service a04d08
                    len(network_state.dns_searchdomains)]):
Packit Service a04d08
            return None
Packit Service a04d08
        content = resolv_conf.ResolvConf("")
Packit Service a04d08
        if existing_dns_path and os.path.isfile(existing_dns_path):
Packit Service a04d08
            content = resolv_conf.ResolvConf(util.load_file(existing_dns_path))
Packit Service a04d08
        for nameserver in network_state.dns_nameservers:
Packit Service a04d08
            content.add_nameserver(nameserver)
Packit Service a04d08
        for searchdomain in network_state.dns_searchdomains:
Packit Service a04d08
            content.add_search_domain(searchdomain)
Packit Service a04d08
        header = _make_header(';')
Packit Service a04d08
        content_str = str(content)
Packit Service a04d08
        if not content_str.startswith(header):
Packit Service a04d08
            content_str = header + '\n' + content_str
Packit Service a04d08
        return content_str
Packit Service a04d08
Packit Service a04d08
    @staticmethod
Packit Service a04d08
    def _render_networkmanager_conf(network_state, templates=None):
Packit Service a04d08
        content = networkmanager_conf.NetworkManagerConf("")
Packit Service a04d08
Packit Service a04d08
        # If DNS server information is provided, configure
Packit Service a04d08
        # NetworkManager to not manage dns, so that /etc/resolv.conf
Packit Service a04d08
        # does not get clobbered.
Packit Service a04d08
        if network_state.dns_nameservers:
Packit Service a04d08
            content.set_section_keypair('main', 'dns', 'none')
Packit Service a04d08
Packit Service a04d08
        if len(content) == 0:
Packit Service a04d08
            return None
Packit Service a04d08
        out = "".join([_make_header(), "\n", "\n".join(content.write()), "\n"])
Packit Service a04d08
        return out
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_bridge_interfaces(cls, network_state, iface_contents, flavor):
Packit Service 751c4a
        bridge_key_map = {
Packit Service 751c4a
            old_k: new_k for old_k, new_k in cls.cfg_key_maps[flavor].items()
Packit Service 751c4a
            if old_k.startswith('bridge')}
Packit Service a04d08
        bridge_filter = renderer.filter_by_type('bridge')
Packit Service 751c4a
Packit Service a04d08
        for iface in network_state.iter_interfaces(bridge_filter):
Packit Service a04d08
            iface_name = iface['name']
Packit Service a04d08
            iface_cfg = iface_contents[iface_name]
Packit Service 751c4a
            if flavor != 'suse':
Packit Service 751c4a
                iface_cfg.kind = 'bridge'
Packit Service 751c4a
            for old_key, new_key in bridge_key_map.items():
Packit Service a04d08
                if old_key in iface:
Packit Service a04d08
                    iface_cfg[new_key] = iface[old_key]
Packit Service a04d08
Packit Service 751c4a
            if flavor == 'suse':
Packit Service 751c4a
                if 'BRIDGE_STP' in iface_cfg:
Packit Service 751c4a
                    if iface_cfg.get('BRIDGE_STP'):
Packit Service 751c4a
                        iface_cfg['BRIDGE_STP'] = 'on'
Packit Service 751c4a
                    else:
Packit Service 751c4a
                        iface_cfg['BRIDGE_STP'] = 'off'
Packit Service 11b429
Packit Service 751c4a
            if iface.get('mac_address'):
Packit Service 751c4a
                key = 'MACADDR'
Packit Service 751c4a
                if flavor == 'suse':
Packit Service 751c4a
                    key = 'LLADDRESS'
Packit Service 751c4a
                iface_cfg[key] = iface.get('mac_address')
Packit Service 751c4a
Packit Service 751c4a
            if flavor == 'suse':
Packit Service 751c4a
                if iface.get('bridge_ports', []):
Packit Service 751c4a
                    iface_cfg['BRIDGE_PORTS'] = '%s' % " ".join(
Packit Service 751c4a
                        iface.get('bridge_ports')
Packit Service 751c4a
                    )
Packit Service a04d08
            # Is this the right key to get all the connected interfaces?
Packit Service a04d08
            for bridged_iface_name in iface.get('bridge_ports', []):
Packit Service a04d08
                # Ensure all bridged interfaces are correctly tagged
Packit Service a04d08
                # as being bridged to this interface.
Packit Service a04d08
                bridged_cfg = iface_contents[bridged_iface_name]
Packit Service a04d08
                bridged_cfgs = [bridged_cfg]
Packit Service a04d08
                bridged_cfgs.extend(bridged_cfg.children)
Packit Service a04d08
                for bridge_cfg in bridged_cfgs:
Packit Service 751c4a
                    bridge_value = iface_name
Packit Service 751c4a
                    if flavor == 'suse':
Packit Service 751c4a
                        bridge_value = 'yes'
Packit Service 751c4a
                    bridge_cfg['BRIDGE'] = bridge_value
Packit Service a04d08
Packit Service a04d08
            iface_subnets = iface.get("subnets", [])
Packit Service a04d08
            route_cfg = iface_cfg.routes
Packit Service a04d08
            cls._render_subnets(
Packit Service 751c4a
                iface_cfg, iface_subnets, network_state.has_default_route,
Packit Service 751c4a
                flavor
Packit Service 751c4a
            )
Packit Service 751c4a
            cls._render_subnet_routes(
Packit Service 751c4a
                iface_cfg, route_cfg, iface_subnets, flavor
Packit Service a04d08
            )
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_ib_interfaces(cls, network_state, iface_contents, flavor):
Packit Service a04d08
        ib_filter = renderer.filter_by_type('infiniband')
Packit Service a04d08
        for iface in network_state.iter_interfaces(ib_filter):
Packit Service a04d08
            iface_name = iface['name']
Packit Service a04d08
            iface_cfg = iface_contents[iface_name]
Packit Service a04d08
            iface_cfg.kind = 'infiniband'
Packit Service a04d08
            iface_subnets = iface.get("subnets", [])
Packit Service a04d08
            route_cfg = iface_cfg.routes
Packit Service a04d08
            cls._render_subnets(
Packit Service 751c4a
                iface_cfg, iface_subnets, network_state.has_default_route,
Packit Service 751c4a
                flavor
Packit Service 751c4a
            )
Packit Service 751c4a
            cls._render_subnet_routes(
Packit Service 751c4a
                iface_cfg, route_cfg, iface_subnets, flavor
Packit Service a04d08
            )
Packit Service a04d08
Packit Service a04d08
    @classmethod
Packit Service 751c4a
    def _render_sysconfig(cls, base_sysconf_dir, network_state, flavor,
Packit Service a04d08
                          templates=None):
Packit Service a04d08
        '''Given state, return /etc/sysconfig files + contents'''
Packit Service a04d08
        if not templates:
Packit Service a04d08
            templates = cls.templates
Packit Service a04d08
        iface_contents = {}
Packit Service a04d08
        for iface in network_state.iter_interfaces():
Packit Service a04d08
            if iface['type'] == "loopback":
Packit Service a04d08
                continue
Packit Service a04d08
            iface_name = iface['name']
Packit Service a04d08
            iface_cfg = NetInterface(iface_name, base_sysconf_dir, templates)
Packit Service 751c4a
            if flavor == 'suse':
Packit Service 751c4a
                iface_cfg.drop('DEVICE')
Packit Service 751c4a
                # If type detection fails it is considered a bug in SUSE
Packit Service 751c4a
                iface_cfg.drop('TYPE')
Packit Service 751c4a
            cls._render_iface_shared(iface, iface_cfg, flavor)
Packit Service a04d08
            iface_contents[iface_name] = iface_cfg
Packit Service 751c4a
        cls._render_physical_interfaces(network_state, iface_contents, flavor)
Packit Service 751c4a
        cls._render_bond_interfaces(network_state, iface_contents, flavor)
Packit Service 751c4a
        cls._render_vlan_interfaces(network_state, iface_contents, flavor)
Packit Service 751c4a
        cls._render_bridge_interfaces(network_state, iface_contents, flavor)
Packit Service 751c4a
        cls._render_ib_interfaces(network_state, iface_contents, flavor)
Packit Service a04d08
        contents = {}
Packit Service a04d08
        for iface_name, iface_cfg in iface_contents.items():
Packit Service a04d08
            if iface_cfg or iface_cfg.children:
Packit Service a04d08
                contents[iface_cfg.path] = iface_cfg.to_string()
Packit Service a04d08
                for iface_cfg in iface_cfg.children:
Packit Service a04d08
                    if iface_cfg:
Packit Service a04d08
                        contents[iface_cfg.path] = iface_cfg.to_string()
Packit Service a04d08
            if iface_cfg.routes:
Packit Service a04d08
                for cpath, proto in zip([iface_cfg.routes.path_ipv4,
Packit Service a04d08
                                         iface_cfg.routes.path_ipv6],
Packit Service a04d08
                                        ["ipv4", "ipv6"]):
Packit Service a04d08
                    if cpath not in contents:
Packit Service a04d08
                        contents[cpath] = iface_cfg.routes.to_string(proto)
Packit Service a04d08
        return contents
Packit Service a04d08
Packit Service a04d08
    def render_network_state(self, network_state, templates=None, target=None):
Packit Service a04d08
        if not templates:
Packit Service a04d08
            templates = self.templates
Packit Service a04d08
        file_mode = 0o644
Packit Service 751c4a
        base_sysconf_dir = subp.target_path(target, self.sysconf_dir)
Packit Service a04d08
        for path, data in self._render_sysconfig(base_sysconf_dir,
Packit Service 751c4a
                                                 network_state, self.flavor,
Packit Service a04d08
                                                 templates=templates).items():
Packit Service a04d08
            util.write_file(path, data, file_mode)
Packit Service a04d08
        if self.dns_path:
Packit Service 751c4a
            dns_path = subp.target_path(target, self.dns_path)
Packit Service a04d08
            resolv_content = self._render_dns(network_state,
Packit Service a04d08
                                              existing_dns_path=dns_path)
Packit Service a04d08
            if resolv_content:
Packit Service a04d08
                util.write_file(dns_path, resolv_content, file_mode)
Packit Service a04d08
        if self.networkmanager_conf_path:
Packit Service 751c4a
            nm_conf_path = subp.target_path(target,
Packit Service a04d08
                                            self.networkmanager_conf_path)
Packit Service a04d08
            nm_conf_content = self._render_networkmanager_conf(network_state,
Packit Service a04d08
                                                               templates)
Packit Service a04d08
            if nm_conf_content:
Packit Service a04d08
                util.write_file(nm_conf_path, nm_conf_content, file_mode)
Packit Service a04d08
        if self.netrules_path:
Packit Service a04d08
            netrules_content = self._render_persistent_net(network_state)
Packit Service 751c4a
            netrules_path = subp.target_path(target, self.netrules_path)
Packit Service a04d08
            util.write_file(netrules_path, netrules_content, file_mode)
Packit Service a04d08
        if available_nm(target=target):
Packit Service 751c4a
            enable_ifcfg_rh(subp.target_path(target, path=NM_CFG_FILE))
Packit Service a04d08
Packit Service 751c4a
        sysconfig_path = subp.target_path(target, templates.get('control'))
Packit Service a04d08
        # Distros configuring /etc/sysconfig/network as a file e.g. Centos
Packit Service a04d08
        if sysconfig_path.endswith('network'):
Packit Service a04d08
            util.ensure_dir(os.path.dirname(sysconfig_path))
Packit Service 814755
            netcfg = []
Packit Service 814755
            for line in util.load_file(sysconfig_path, quiet=True).split('\n'):
Packit Service 814755
                if 'cloud-init' in line:
Packit Service 814755
                    break
Packit Service 814755
                if not line.startswith(('NETWORKING=',
Packit Service 814755
                                        'IPV6_AUTOCONF=',
Packit Service 814755
                                        'NETWORKING_IPV6=')):
Packit Service 814755
                    netcfg.append(line)
Packit Service 814755
            # Now generate the cloud-init portion of sysconfig/network
Packit Service 814755
            netcfg.extend([_make_header(), 'NETWORKING=yes'])
Packit Service a04d08
            if network_state.use_ipv6:
Packit Service a04d08
                netcfg.append('NETWORKING_IPV6=yes')
Packit Service a04d08
                netcfg.append('IPV6_AUTOCONF=no')
Packit Service a04d08
            util.write_file(sysconfig_path,
Packit Service a04d08
                            "\n".join(netcfg) + "\n", file_mode)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def available(target=None):
Packit Service a04d08
    sysconfig = available_sysconfig(target=target)
Packit Service a04d08
    nm = available_nm(target=target)
Packit Service a04d08
    return (util.system_info()['variant'] in KNOWN_DISTROS
Packit Service a04d08
            and any([nm, sysconfig]))
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def available_sysconfig(target=None):
Packit Service a04d08
    expected = ['ifup', 'ifdown']
Packit Service a04d08
    search = ['/sbin', '/usr/sbin']
Packit Service a04d08
    for p in expected:
Packit Service 751c4a
        if not subp.which(p, search=search, target=target):
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
    expected_paths = [
Packit Service a04d08
        'etc/sysconfig/network-scripts/network-functions',
Packit Service a04d08
        'etc/sysconfig/config']
Packit Service a04d08
    for p in expected_paths:
Packit Service 751c4a
        if os.path.isfile(subp.target_path(target, p)):
Packit Service a04d08
            return True
Packit Service a04d08
    return False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def available_nm(target=None):
Packit Service 751c4a
    if not os.path.isfile(subp.target_path(target, path=NM_CFG_FILE)):
Packit Service a04d08
        return False
Packit Service a04d08
    return True
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab