Exemple #1
0
    def create(self, do_apply, excpts, oper="add"):
        logger.info(oper,
                    extra={
                        'iface': self.settings['ifname'],
                        'style': IfStateLogging.STYLE_CHG
                    })

        logger.debug("ip link add: {}".format(" ".join(
            "{}={}".format(k, v) for k, v in self.settings.items())))
        if do_apply:
            try:
                state = self.settings.pop('state', None)
                ipr.link('add', **(self.settings))
                self.idx = next(
                    iter(ipr.link_lookup(ifname=self.settings['ifname'])),
                    None)
                if not state is None and not self.idx is None:
                    try:
                        ipr.link('set', index=self.idx, state=state)
                    except Exception as err:
                        if not isinstance(err, netlinkerror_classes):
                            raise
                        excpts.add('set', err, state=state)
            except Exception as err:
                if not isinstance(err, netlinkerror_classes):
                    raise
                excpts.add('add', err, **(self.settings))

        if not self.ethtool is None:
            logger.debug("ethtool: {}".format(self.ethtool))
            self.set_ethtool_state(self.settings['ifname'],
                                   self.ethtool.keys(), do_apply)
Exemple #2
0
    def apply(self, do_apply):
        excpts = ExceptionCollector(self.settings['ifname'])
        osettings = copy.deepcopy(self.settings)

        # lookup for attributes requiring a interface index
        for attr in self.attr_idx:
            if attr in self.settings:
                self.settings[attr] = next(
                    iter(ipr.link_lookup(ifname=self.settings[attr])),
                    self.settings[attr])

        if self.idx is None:
            self.idx = next(
                iter(ipr.link_lookup(ifname=self.settings['ifname'])), None)

        if self.idx is not None:
            self.iface = next(iter(ipr.get_links(self.idx)), None)
            permaddr = ipr.get_permaddr(self.iface.get_attr('IFLA_IFNAME'))
            if not permaddr is None:
                self.iface['permaddr'] = permaddr
            businfo = ipr.get_businfo(self.iface.get_attr('IFLA_IFNAME'))
            if not businfo is None:
                self.iface['businfo'] = businfo

            # check for ifname collisions
            idx = next(iter(ipr.link_lookup(ifname=self.settings['ifname'])),
                       None)
            if idx is not None and idx != self.idx and do_apply:
                try:
                    ipr.link('set', index=idx, state='down')
                    ipr.link('set',
                             index=idx,
                             ifname='{}!'.format(self.settings['ifname']))
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    excpts.add('set', err, state='down', ifname='{}!')

            if self.cap_create and self.get_if_attr(
                    'kind') != self.settings['kind']:
                self.recreate(do_apply, excpts)
            else:
                excpts.set_quiet(self.cap_create)
                self.update(do_apply, excpts)
                if self.cap_create and excpts.get_all():
                    excpts.reset()
                    self.recreate(do_apply, excpts)
        else:
            self.create(do_apply, excpts)

        self.settings = osettings
        return excpts
Exemple #3
0
 def recreate(self, do_apply, excpts):
     logger.debug('has wrong link kind %s, removing',
                  self.settings['kind'],
                  extra={'iface': self.settings['ifname']})
     if do_apply:
         try:
             ipr.link('del', index=self.idx)
         except Exception as err:
             if not isinstance(err, netlinkerror_classes):
                 raise
             excpts.add('del', err)
     self.idx = None
     self.create(do_apply, "replace")
Exemple #4
0
    def update(self, do_apply, excpts):
        logger.debug('checking link', extra={'iface': self.settings['ifname']})

        old_state = self.iface['state']
        has_link_changes = False
        has_state_changes = False
        for setting in self.settings.keys():
            logger.debug('  %s: %s => %s',
                         setting,
                         self.get_if_attr(setting),
                         self.settings[setting],
                         extra={'iface': self.settings['ifname']})
            if setting == "state":
                has_state_changes = self.get_if_attr(
                    setting) != self.settings[setting]
            else:
                if setting != 'kind' or self.cap_create:
                    has_link_changes |= self.get_if_attr(
                        setting) != self.settings[setting]

        has_ethtool_changes = set()
        if not self.ethtool is None:
            logger.debug('checking ethtool',
                         extra={'iface': self.settings['ifname']})
            ethtool = self.get_ethtool_state(self.ethtool.keys())
            if ethtool is None:
                has_ethtool_changes.add(self.ethtool.keys())
            else:
                for setting, options in self.ethtool.items():
                    if not setting in ethtool:
                        has_ethtool_changes.add(setting)
                    else:
                        for option in options.keys():
                            logger.debug(
                                '  %s.%s: %s => %s',
                                setting,
                                option,
                                ethtool[setting].get(option),
                                self.ethtool[setting][option],
                                extra={'iface': self.settings['ifname']})
                            if self.ethtool[setting][option] != ethtool[
                                    setting].get(option):
                                has_ethtool_changes.add(setting)

        if has_link_changes:
            logger.debug('needs to be configured',
                         extra={'iface': self.settings['ifname']})
            if old_state:
                logger.debug('shutting down',
                             extra={'iface': self.settings['ifname']})
                if do_apply:
                    try:
                        ipr.link('set', index=self.idx, state='down')
                    except Exception as err:
                        if not isinstance(err, netlinkerror_classes):
                            raise
                        excpts.add('set', err, state='down')
                if not 'state' in self.settings:
                    self.settings['state'] = 'up'

            self.set_ethtool_state(self.get_if_attr('ifname'),
                                   has_ethtool_changes, do_apply)

            if self.get_if_attr('ifname') == self.settings['ifname']:
                logger.info('change',
                            extra={
                                'iface': self.settings['ifname'],
                                'style': IfStateLogging.STYLE_CHG
                            })
            else:
                logger.info('change (was {})'.format(
                    self.get_if_attr('ifname')),
                            extra={
                                'iface': self.settings['ifname'],
                                'style': IfStateLogging.STYLE_CHG
                            })
            if do_apply:
                try:
                    state = self.settings.pop('state', None)
                    ipr.link('set', index=self.idx, **(self.settings))
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    excpts.add('set', err, state=state)

                try:
                    if not state is None:
                        # restore state setting for recreate
                        self.settings['state'] = state
                        ipr.link('set', index=self.idx, state=state)
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    excpts.add('set', err, state=state)
        else:
            self.set_ethtool_state(self.get_if_attr('ifname'),
                                   has_ethtool_changes, do_apply)

            if has_state_changes:
                try:
                    ipr.link('set',
                             index=self.idx,
                             state=self.settings["state"])
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    excpts.add('set', err, state=state)
                logger.info('change',
                            extra={
                                'iface': self.settings['ifname'],
                                'style': IfStateLogging.STYLE_CHG
                            })

            else:
                logger.info('ok',
                            extra={
                                'iface': self.settings['ifname'],
                                'style': IfStateLogging.STYLE_OK
                            })
Exemple #5
0
    def _apply(self, do_apply, vrrp_type, vrrp_name, vrrp_state):
        vrrp_ignore = []
        vrrp_remove = []

        by_vrrp = not None in [vrrp_type, vrrp_name, vrrp_state]

        for ifname, link in self.links.items():
            if ifname in self.vrrp['links']:
                if not by_vrrp:
                    vrrp_ignore.append(ifname)
                else:
                    if not link.match_vrrp_select(vrrp_type, vrrp_name):
                        vrrp_ignore.append(ifname)
                    elif not vrrp_name in self.vrrp[
                            vrrp_type] or not vrrp_state in self.vrrp[
                                vrrp_type][
                                    vrrp_name] or not ifname in self.vrrp[
                                        vrrp_type][vrrp_name][vrrp_state]:
                        vrrp_remove.append(ifname)
            elif by_vrrp:
                vrrp_ignore.append(ifname)

        self.ipaddr_ignore = set()
        for ip in self.ignore.get('ipaddr', []):
            self.ipaddr_ignore.add(ip_network(ip))

        if not any(not x is None for x in self.links.values()):
            logger.error("DANGER: Not a single link config has been found!")
            raise LinkNoConfigFound()

        for iface in ['all', 'default']:
            if self.sysctl.has_settings(iface):
                logger.info("\nconfiguring {} interface sysctl".format(iface))
                self.sysctl.apply(iface, do_apply)

        for stage in range(2):
            if stage == 0:
                logger.info("\nconfiguring interface links")

                for ifname in vrrp_remove:
                    logger.debug('to be removed due to vrrp constraint',
                                 extra={'iface': ifname})
                    del self.links[ifname]
            else:
                logger.info("\nconfiguring interface links (stage 2)")

            retry = False
            applied = []
            while len(applied) + len(vrrp_ignore) < len(self.links):
                last = len(applied)
                for name, link in self.links.items():
                    if name in applied:
                        continue

                    if name in vrrp_ignore:
                        logger.debug('skipped due to vrrp constraint',
                                     extra={'iface': name})
                        continue

                    if link is None:
                        logger.debug('skipped due to no link settings',
                                     extra={'iface': name})
                        applied.append(name)
                    else:
                        deps = link.depends()
                        if all(x in applied for x in deps):
                            self.sysctl.apply(name, do_apply)
                            excpts = link.apply(do_apply)
                            if excpts.has_errno(errno.EEXIST):
                                retry = True
                            applied.append(name)
                if last == len(applied):
                    raise LinkCircularLinked()

            for link in ipr.get_links():
                name = link.get_attr('IFLA_IFNAME')
                # skip links on ignore list
                if not name in self.links and not any(
                        re.match(regex, name)
                        for regex in self.ignore.get('ifname', [])):
                    info = link.get_attr('IFLA_LINKINFO')
                    # remove virtual interface
                    if info is not None:
                        kind = info.get_attr('IFLA_INFO_KIND')
                        logger.info('del',
                                    extra={
                                        'iface': name,
                                        'style': IfStateLogging.STYLE_DEL
                                    })
                        if do_apply:
                            try:
                                ipr.link('set',
                                         index=link.get('index'),
                                         state='down')
                                ipr.link('del', index=link.get('index'))
                            except Exception as err:
                                if not isinstance(err, netlinkerror_classes):
                                    raise
                                logger.warning(
                                    'removing link {} failed: {}'.format(
                                        name, err.args[1]))
                    # shutdown physical interfaces
                    else:
                        if name in vrrp_ignore:
                            logger.warning('vrrp',
                                           extra={
                                               'iface': name,
                                               'style': IfStateLogging.STYLE_OK
                                           })
                        if link.get('state') == 'down':
                            logger.warning('orphan',
                                           extra={
                                               'iface': name,
                                               'style': IfStateLogging.STYLE_OK
                                           })
                        else:
                            logger.warning('orphan',
                                           extra={
                                               'iface': name,
                                               'style':
                                               IfStateLogging.STYLE_CHG
                                           })
                            if do_apply:
                                try:
                                    ipr.link('set',
                                             index=link.get('index'),
                                             state='down')
                                except Exception as err:
                                    if not isinstance(err,
                                                      netlinkerror_classes):
                                        raise
                                    logger.warning(
                                        'updating link {} failed: {}'.format(
                                            name, err.args[1]))
            if not retry:
                break

        if any(not x is None for x in self.tc.values()):
            logger.info("\nconfiguring interface traffic control...")

            for name, tc in self.tc.items():
                if name in vrrp_ignore:
                    logger.debug('skipped due to vrrp constraint',
                                 extra={'iface': name})
                elif tc is None:
                    logger.debug('skipped due to no tc settings',
                                 extra={'iface': name})
                else:
                    tc.apply(do_apply)

        if any(not x is None for x in self.addresses.values()):
            logger.info("\nconfiguring interface ip addresses...")
            # add empty objects for unhandled interfaces
            for link in ipr.get_links():
                name = link.get_attr('IFLA_IFNAME')
                # skip links on ignore list
                if not name in self.addresses and not any(
                        re.match(regex, name)
                        for regex in self.ignore.get('ifname', [])):
                    self.addresses[name] = Addresses(name, [])

            for name, addresses in self.addresses.items():
                if name in vrrp_ignore:
                    logger.debug('skipped due to vrrp constraint',
                                 extra={'iface': name})
                elif addresses is None:
                    logger.debug('skipped due to no address settings',
                                 extra={'iface': name})
                else:
                    addresses.apply(self.ipaddr_ignore,
                                    self.ignore.get('ipaddr_dynamic', True),
                                    do_apply)
        else:
            logger.info("\nno interface ip addressing to be applied")

        if any(not x is None for x in self.neighbours.values()):
            logger.info("\nconfiguring interface neighbours...")
            # add empty objects for unhandled interfaces
            for link in ipr.get_links():
                name = link.get_attr('IFLA_IFNAME')
                # skip links on ignore list
                if not name in self.neighbours and not any(
                        re.match(regex, name)
                        for regex in self.ignore.get('ifname', [])):
                    self.neighbours[name] = Neighbours(name, [])

            for name, neighbours in self.neighbours.items():
                if name in vrrp_ignore:
                    logger.debug('skipped due to vrrp constraint',
                                 extra={'iface': name})
                elif neighbours is None:
                    logger.debug('skipped due to no address settings',
                                 extra={'iface': name})
                else:
                    neighbours.apply(do_apply)
        else:
            logger.info("\nno interface neighbours to be applied")

        if not self.tables is None:
            self.tables.apply(self.ignore.get('routes', []), do_apply)

        if not self.rules is None:
            self.rules.apply(self.ignore.get('rules', []), do_apply)

        if len(self.wireguard):
            logger.info("\nconfiguring WireGuard...")
            for iface, wireguard in self.wireguard.items():
                if iface in vrrp_ignore:
                    logger.debug('skipped due to vrrp constraint',
                                 extra={'iface': name})
                    continue
                wireguard.apply(do_apply)