|
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}"
|