Blame libnmstate/nm/plugin.py

Packit Service 0535c1
#
Packit Service 0535c1
# Copyright (c) 2020 Red Hat, Inc.
Packit Service 0535c1
#
Packit Service 0535c1
# This file is part of nmstate
Packit Service 0535c1
#
Packit Service 0535c1
# This program is free software: you can redistribute it and/or modify
Packit Service 0535c1
# it under the terms of the GNU Lesser General Public License as published by
Packit Service 0535c1
# the Free Software Foundation, either version 2.1 of the License, or
Packit Service 0535c1
# (at your option) any later version.
Packit Service 0535c1
#
Packit Service 0535c1
# This program is distributed in the hope that it will be useful,
Packit Service 0535c1
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0535c1
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 0535c1
# GNU Lesser General Public License for more details.
Packit Service 0535c1
#
Packit Service 0535c1
# You should have received a copy of the GNU Lesser General Public License
Packit Service 0535c1
# along with this program. If not, see <https://www.gnu.org/licenses/>.
Packit Service 0535c1
#
Packit Service 0535c1
from distutils.version import StrictVersion
Packit Service 0535c1
import logging
Packit Service 0535c1
from operator import itemgetter
Packit Service 0535c1
Packit Service 0535c1
from libnmstate.error import NmstateValueError
Packit Service 0535c1
from libnmstate.ifaces.ovs import is_ovs_running
Packit Service 0535c1
from libnmstate.schema import DNS
Packit Service 0535c1
from libnmstate.schema import Interface
Packit Service 0535c1
from libnmstate.schema import Route
Packit Service 0535c1
from libnmstate.schema import RouteRule
Packit Service 0535c1
from libnmstate.plugin import NmstatePlugin
Packit Service 0535c1
Packit Service 0535c1
from . import bond as nm_bond
Packit Service 0535c1
from . import bridge as nm_bridge
Packit Service 0535c1
from . import connection as nm_connection
Packit Service 0535c1
from . import device as nm_device
Packit Service 0535c1
from . import ipv4 as nm_ipv4
Packit Service 0535c1
from . import ipv6 as nm_ipv6
Packit Service 0535c1
from . import lldp as nm_lldp
Packit Service 0535c1
from . import ovs as nm_ovs
Packit Service 0535c1
from . import translator as nm_translator
Packit Service 0535c1
from . import wired as nm_wired
Packit Service 0535c1
from . import user as nm_user
Packit Service 0535c1
from . import vlan as nm_vlan
Packit Service 0535c1
from . import vxlan as nm_vxlan
Packit Service 0535c1
from . import team as nm_team
Packit Service 0535c1
from . import dns as nm_dns
Packit Service 0535c1
from . import applier as nm_applier
Packit Service 0535c1
from .checkpoint import CheckPoint
Packit Service 0535c1
from .checkpoint import get_checkpoints
Packit Service 0535c1
from .common import NM
Packit Service 0535c1
from .context import NmContext
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
class NetworkManagerPlugin(NmstatePlugin):
Packit Service 0535c1
    def __init__(self):
Packit Service 0535c1
        self._ctx = NmContext()
Packit Service 0535c1
        self._checkpoint = None
Packit Service 0535c1
        self._check_version_mismatch()
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def name(self):
Packit Service 0535c1
        return "NetworkManager"
Packit Service 0535c1
Packit Service 0535c1
    def unload(self):
Packit Service 0535c1
        if self._ctx:
Packit Service 0535c1
            self._ctx.clean_up()
Packit Service 0535c1
            self._ctx = None
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def checkpoint(self):
Packit Service 0535c1
        return self._checkpoint
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def client(self):
Packit Service 0535c1
        return self._ctx.client if self._ctx else None
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def context(self):
Packit Service 0535c1
        return self._ctx
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def capabilities(self):
Packit Service 0535c1
        capabilities = []
Packit Service 0535c1
        if nm_ovs.has_ovs_capability(self.client) and is_ovs_running():
Packit Service 0535c1
            capabilities.append(NmstatePlugin.OVS_CAPABILITY)
Packit Service 0535c1
        if nm_team.has_team_capability(self.client):
Packit Service 0535c1
            capabilities.append(NmstatePlugin.TEAM_CAPABILITY)
Packit Service 0535c1
        return capabilities
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def plugin_capabilities(self):
Packit Service 0535c1
        return [
Packit Service 0535c1
            NmstatePlugin.PLUGIN_CAPABILITY_IFACE,
Packit Service 0535c1
            NmstatePlugin.PLUGIN_CAPABILITY_ROUTE,
Packit Service 0535c1
            NmstatePlugin.PLUGIN_CAPABILITY_ROUTE_RULE,
Packit Service 0535c1
            NmstatePlugin.PLUGIN_CAPABILITY_DNS,
Packit Service 0535c1
        ]
Packit Service 0535c1
Packit Service 0535c1
    def get_interfaces(self):
Packit Service 0535c1
        info = []
Packit Service 0535c1
        capabilities = self.capabilities
Packit Service 0535c1
Packit Service 0535c1
        devices_info = [
Packit Service 0535c1
            (dev, nm_device.get_device_common_info(dev))
Packit Service 0535c1
            for dev in nm_device.list_devices(self.client)
Packit Service 0535c1
        ]
Packit Service 0535c1
Packit Service 0535c1
        for dev, devinfo in devices_info:
Packit Service 0535c1
            type_id = devinfo["type_id"]
Packit Service 0535c1
Packit Service 0535c1
            iface_info = nm_translator.Nm2Api.get_common_device_info(devinfo)
Packit Service 0535c1
Packit Service 0535c1
            act_con = nm_connection.get_device_active_connection(dev)
Packit Service 0535c1
            iface_info[Interface.IPV4] = nm_ipv4.get_info(act_con)
Packit Service 0535c1
            iface_info[Interface.IPV6] = nm_ipv6.get_info(act_con)
Packit Service 0535c1
            iface_info.update(nm_wired.get_info(dev))
Packit Service 0535c1
            iface_info.update(nm_user.get_info(self.context, dev))
Packit Service 0535c1
            iface_info.update(nm_lldp.get_info(self.client, dev))
Packit Service 0535c1
            iface_info.update(nm_vlan.get_info(dev))
Packit Service 0535c1
            iface_info.update(nm_vxlan.get_info(dev))
Packit Service 0535c1
            iface_info.update(nm_bridge.get_info(self.context, dev))
Packit Service 0535c1
            iface_info.update(nm_team.get_info(dev))
Packit Service 0535c1
Packit Service 0535c1
            if nm_bond.is_bond_type_id(type_id):
Packit Service 0535c1
                bondinfo = nm_bond.get_bond_info(dev)
Packit Service 0535c1
                iface_info.update(_ifaceinfo_bond(bondinfo))
Packit Service 0535c1
            elif NmstatePlugin.OVS_CAPABILITY in capabilities:
Packit Service 0535c1
                if nm_ovs.is_ovs_bridge_type_id(type_id):
Packit Service 0535c1
                    iface_info["bridge"] = nm_ovs.get_ovs_info(
Packit Service 0535c1
                        self.context, dev, devices_info
Packit Service 0535c1
                    )
Packit Service 0535c1
                    iface_info = _remove_ovs_bridge_unsupported_entries(
Packit Service 0535c1
                        iface_info
Packit Service 0535c1
                    )
Packit Service 0535c1
                elif nm_ovs.is_ovs_interface_type_id(type_id):
Packit Service 0535c1
                    iface_info.update(nm_ovs.get_interface_info(act_con))
Packit Service 0535c1
                elif nm_ovs.is_ovs_port_type_id(type_id):
Packit Service 0535c1
                    continue
Packit Service 0535c1
Packit Service 0535c1
            info.append(iface_info)
Packit Service 0535c1
Packit Service 0535c1
        info.sort(key=itemgetter("name"))
Packit Service 0535c1
Packit Service 0535c1
        return info
Packit Service 0535c1
Packit Service 0535c1
    def get_routes(self):
Packit Service 0535c1
        return {
Packit Service 0535c1
            Route.RUNNING: (
Packit Service 0535c1
                nm_ipv4.get_route_running(self.client)
Packit Service 0535c1
                + nm_ipv6.get_route_running(self.client)
Packit Service 0535c1
            ),
Packit Service 0535c1
            Route.CONFIG: (
Packit Service 0535c1
                nm_ipv4.get_route_config(self.client)
Packit Service 0535c1
                + nm_ipv6.get_route_config(self.client)
Packit Service 0535c1
            ),
Packit Service 0535c1
        }
Packit Service 0535c1
Packit Service 0535c1
    def get_route_rules(self):
Packit Service 0535c1
        return {
Packit Service 0535c1
            RouteRule.CONFIG: (
Packit Service 0535c1
                nm_ipv4.get_routing_rule_config(self.client)
Packit Service 0535c1
                + nm_ipv6.get_routing_rule_config(self.client)
Packit Service 0535c1
            )
Packit Service 0535c1
        }
Packit Service 0535c1
Packit Service 0535c1
    def get_dns_client_config(self):
Packit Service 0535c1
        return {
Packit Service 0535c1
            DNS.RUNNING: nm_dns.get_running(self.client),
Packit Service 0535c1
            DNS.CONFIG: nm_dns.get_config(
Packit Service 0535c1
                nm_ipv4.acs_and_ip_profiles(self.client),
Packit Service 0535c1
                nm_ipv6.acs_and_ip_profiles(self.client),
Packit Service 0535c1
            ),
Packit Service 0535c1
        }
Packit Service 0535c1
Packit Service 0535c1
    def refresh_content(self):
Packit Service 0535c1
        self._ctx.refresh_content()
Packit Service 0535c1
Packit Service 0535c1
    def apply_changes(self, net_state, save_to_disk):
Packit Service 0535c1
        nm_applier.apply_changes(self.context, net_state, save_to_disk)
Packit Service 0535c1
Packit Service 0535c1
    def _load_checkpoint(self, checkpoint_path):
Packit Service 0535c1
        if checkpoint_path:
Packit Service 0535c1
            if self._checkpoint:
Packit Service 0535c1
                # Old checkpoint might timeout, hence it's legal to load
Packit Service 0535c1
                # another one.
Packit Service 0535c1
                self._checkpoint.clean_up()
Packit Service 0535c1
            candidates = get_checkpoints(self._ctx.client)
Packit Service 0535c1
            if checkpoint_path in candidates:
Packit Service 0535c1
                self._checkpoint = CheckPoint(
Packit Service 0535c1
                    nm_context=self._ctx, dbuspath=checkpoint_path
Packit Service 0535c1
                )
Packit Service 0535c1
            else:
Packit Service 0535c1
                raise NmstateValueError("No checkpoint specified or found")
Packit Service 0535c1
        else:
Packit Service 0535c1
            if not self._checkpoint:
Packit Service 0535c1
                # Get latest one
Packit Service 0535c1
                candidates = get_checkpoints(self._ctx.client)
Packit Service 0535c1
                if candidates:
Packit Service 0535c1
                    self._checkpoint = CheckPoint(
Packit Service 0535c1
                        nm_context=self._ctx, dbuspath=candidates[0]
Packit Service 0535c1
                    )
Packit Service 0535c1
                else:
Packit Service 0535c1
                    raise NmstateValueError("No checkpoint specified or found")
Packit Service 0535c1
Packit Service 0535c1
    def create_checkpoint(self, timeout=60):
Packit Service 0535c1
        self._checkpoint = CheckPoint.create(self._ctx, timeout)
Packit Service 0535c1
        return str(self._checkpoint)
Packit Service 0535c1
Packit Service 0535c1
    def rollback_checkpoint(self, checkpoint=None):
Packit Service 0535c1
        self._load_checkpoint(checkpoint)
Packit Service 0535c1
        self._checkpoint.rollback()
Packit Service 0535c1
        self._checkpoint = None
Packit Service 0535c1
Packit Service 0535c1
    def destroy_checkpoint(self, checkpoint=None):
Packit Service 0535c1
        self._load_checkpoint(checkpoint)
Packit Service 0535c1
        self._checkpoint.destroy()
Packit Service 0535c1
        self._checkpoint = None
Packit Service 0535c1
Packit Service 0535c1
    def _check_version_mismatch(self):
Packit Service 0535c1
        nm_client_version = self._ctx.client.get_version()
Packit Service 0535c1
        nm_utils_version = _nm_utils_decode_version()
Packit Service 0535c1
Packit Service 0535c1
        if nm_client_version is None:
Packit Service 0535c1
            logging.warning("NetworkManager is not running")
Packit Service 0535c1
        elif StrictVersion(nm_client_version) != StrictVersion(
Packit Service 0535c1
            nm_utils_version
Packit Service 0535c1
        ):
Packit Service 0535c1
            logging.warning(
Packit Service 0535c1
                "libnm version %s mismatches NetworkManager version %s",
Packit Service 0535c1
                nm_utils_version,
Packit Service 0535c1
                nm_client_version,
Packit Service 0535c1
            )
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _ifaceinfo_bond(devinfo):
Packit Service 0535c1
    # TODO: What about unmanaged devices?
Packit Service 0535c1
    bondinfo = nm_translator.Nm2Api.get_bond_info(devinfo)
Packit Service 0535c1
    if "link-aggregation" in bondinfo:
Packit Service 0535c1
        return bondinfo
Packit Service 0535c1
    return {}
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _remove_ovs_bridge_unsupported_entries(iface_info):
Packit Service 0535c1
    """
Packit Service 0535c1
    OVS bridges are not supporting several common interface key entries.
Packit Service 0535c1
    These entries are removed explicitly.
Packit Service 0535c1
    """
Packit Service 0535c1
    iface_info.pop(Interface.IPV4, None)
Packit Service 0535c1
    iface_info.pop(Interface.IPV6, None)
Packit Service 0535c1
    iface_info.pop(Interface.MTU, None)
Packit Service 0535c1
Packit Service 0535c1
    return iface_info
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _nm_utils_decode_version():
Packit Service 0535c1
    return f"{NM.MAJOR_VERSION}.{NM.MINOR_VERSION}.{NM.MICRO_VERSION}"