Blame libnmstate/nm/active_connection.py

Packit Service 0535c1
#
Packit Service 0535c1
# Copyright (c) 2019-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
Packit Service 0535c1
import logging
Packit Service 0535c1
Packit Service 0535c1
from libnmstate.error import NmstateLibnmError
Packit Service 0535c1
Packit Service 0535c1
from .common import GLib
Packit Service 0535c1
from .common import GObject
Packit Service 0535c1
from .common import NM
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
NM_AC_STATE_CHANGED_SIGNAL = "state-changed"
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
class ActivationError(Exception):
Packit Service 0535c1
    pass
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
class ActiveConnection:
Packit Service 0535c1
    def __init__(self, context=None, nm_ac_con=None):
Packit Service 0535c1
        self._ctx = context
Packit Service 0535c1
        self._act_con = nm_ac_con
Packit Service 0535c1
Packit Service 0535c1
        nmdevs = None
Packit Service 0535c1
        if nm_ac_con:
Packit Service 0535c1
            nmdevs = nm_ac_con.get_devices()
Packit Service 0535c1
        self._nmdev = nmdevs[0] if nmdevs else None
Packit Service 0535c1
Packit Service 0535c1
    def import_by_device(self, nmdev=None):
Packit Service 0535c1
        assert self._act_con is None
Packit Service 0535c1
Packit Service 0535c1
        if nmdev:
Packit Service 0535c1
            self._nmdev = nmdev
Packit Service 0535c1
        if self._nmdev:
Packit Service 0535c1
            self._act_con = self._nmdev.get_active_connection()
Packit Service 0535c1
Packit Service 0535c1
    def deactivate(self):
Packit Service 0535c1
        """
Packit Service 0535c1
        Deactivating the current active connection,
Packit Service 0535c1
        The profile itself is not removed.
Packit Service 0535c1
Packit Service 0535c1
        For software devices, deactivation removes the devices from the kernel.
Packit Service 0535c1
        """
Packit Service 0535c1
        act_connection = self._nmdev.get_active_connection()
Packit Service 0535c1
        if (
Packit Service 0535c1
            not act_connection
Packit Service 0535c1
            or act_connection.props.state
Packit Service 0535c1
            == NM.ActiveConnectionState.DEACTIVATED
Packit Service 0535c1
        ):
Packit Service 0535c1
            return
Packit Service 0535c1
Packit Service 0535c1
        if self._act_con != act_connection:
Packit Service 0535c1
            raise NmstateLibnmError(
Packit Service 0535c1
                "When deactivating active connection, the newly get "
Packit Service 0535c1
                f"NM.ActiveConnection {act_connection}"
Packit Service 0535c1
                f"is different from original request: {self._act_con}"
Packit Service 0535c1
            )
Packit Service 0535c1
Packit Service 0535c1
        action = f"Deactivate profile: {self.devname}"
Packit Service 0535c1
        self._ctx.register_async(action)
Packit Service 0535c1
        handler_id = act_connection.connect(
Packit Service 0535c1
            NM_AC_STATE_CHANGED_SIGNAL,
Packit Service 0535c1
            self._wait_state_changed_callback,
Packit Service 0535c1
            action,
Packit Service 0535c1
        )
Packit Service 0535c1
        if act_connection.props.state != NM.ActiveConnectionState.DEACTIVATING:
Packit Service 0535c1
            user_data = (handler_id, action)
Packit Service 0535c1
            self._ctx.client.deactivate_connection_async(
Packit Service 0535c1
                act_connection,
Packit Service 0535c1
                self._ctx.cancellable,
Packit Service 0535c1
                self._deactivate_connection_callback,
Packit Service 0535c1
                user_data,
Packit Service 0535c1
            )
Packit Service 0535c1
Packit Service 0535c1
    def _wait_state_changed_callback(self, act_con, state, reason, action):
Packit Service 0535c1
        if self._ctx.is_cancelled():
Packit Service 0535c1
            return
Packit Service 0535c1
        if act_con.props.state == NM.ActiveConnectionState.DEACTIVATED:
Packit Service 0535c1
            logging.debug(
Packit Service 0535c1
                "Connection deactivation succeeded on %s", self.devname,
Packit Service 0535c1
            )
Packit Service 0535c1
            self._ctx.finish_async(action)
Packit Service 0535c1
Packit Service 0535c1
    def _deactivate_connection_callback(self, src_object, result, user_data):
Packit Service 0535c1
        handler_id, action = user_data
Packit Service 0535c1
        if self._ctx.is_cancelled():
Packit Service 0535c1
            if self._act_con:
Packit Service 0535c1
                self._act_con.handler_disconnect(handler_id)
Packit Service 0535c1
            return
Packit Service 0535c1
Packit Service 0535c1
        try:
Packit Service 0535c1
            success = src_object.deactivate_connection_finish(result)
Packit Service 0535c1
        except GLib.Error as e:
Packit Service 0535c1
            if e.matches(
Packit Service 0535c1
                NM.ManagerError.quark(), NM.ManagerError.CONNECTIONNOTACTIVE
Packit Service 0535c1
            ):
Packit Service 0535c1
                success = True
Packit Service 0535c1
                logging.debug(
Packit Service 0535c1
                    "Connection is not active on {}, no need to "
Packit Service 0535c1
                    "deactivate".format(self.devname)
Packit Service 0535c1
                )
Packit Service 0535c1
            else:
Packit Service 0535c1
                if self._act_con:
Packit Service 0535c1
                    self._act_con.handler_disconnect(handler_id)
Packit Service 0535c1
                self._ctx.fail(
Packit Service 0535c1
                    NmstateLibnmError(f"{action} failed: error={e}")
Packit Service 0535c1
                )
Packit Service 0535c1
                return
Packit Service 0535c1
        except Exception as e:
Packit Service 0535c1
            if self._act_con:
Packit Service 0535c1
                self._act_con.handler_disconnect(handler_id)
Packit Service 0535c1
            self._ctx.fail(
Packit Service 0535c1
                NmstateLibnmError(
Packit Service 0535c1
                    f"BUG: Unexpected error when activating {self.devname} "
Packit Service 0535c1
                    f"error={e}"
Packit Service 0535c1
                )
Packit Service 0535c1
            )
Packit Service 0535c1
            return
Packit Service 0535c1
Packit Service 0535c1
        if not success:
Packit Service 0535c1
            if self._act_con:
Packit Service 0535c1
                self._act_con.handler_disconnect(handler_id)
Packit Service 0535c1
            self._ctx.fail(
Packit Service 0535c1
                NmstateLibnmError(
Packit Service 0535c1
                    f"{action} failed: error='None returned from "
Packit Service 0535c1
                    "deactivate_connection_finish()'"
Packit Service 0535c1
                )
Packit Service 0535c1
            )
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def nm_active_connection(self):
Packit Service 0535c1
        return self._act_con
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def devname(self):
Packit Service 0535c1
        if self._nmdev:
Packit Service 0535c1
            return self._nmdev.get_iface()
Packit Service 0535c1
        else:
Packit Service 0535c1
            return None
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def nmdevice(self):
Packit Service 0535c1
        return self._nmdev
Packit Service 0535c1
Packit Service 0535c1
    @nmdevice.setter
Packit Service 0535c1
    def nmdevice(self, nmdev):
Packit Service 0535c1
        assert self._nmdev is None
Packit Service 0535c1
        self._nmdev = nmdev
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _is_device_master_type(nmdev):
Packit Service 0535c1
    if nmdev:
Packit Service 0535c1
        is_master_type = (
Packit Service 0535c1
            GObject.type_is_a(nmdev, NM.DeviceBond)
Packit Service 0535c1
            or GObject.type_is_a(nmdev, NM.DeviceBridge)
Packit Service 0535c1
            or GObject.type_is_a(nmdev, NM.DeviceTeam)
Packit Service 0535c1
            or GObject.type_is_a(nmdev, NM.DeviceOvsBridge)
Packit Service 0535c1
        )
Packit Service 0535c1
        return is_master_type
Packit Service 0535c1
    return False