network/module_utils/network_lsr/nm/provider.py
Gris Ge c98c17a236 Fix problem when switch provider from initscript to nm
Problem:

After `tests_bridge_initscripts.yml` passed, the `tests_bridge_nm.yml`
will fail with NetworkManager 1.18.

Root cause:

 1. The `absent` and `down` action of initscript provider will not
    remove the bridge interface which fail the assertion in
    `tests_bridge_nm.yml`.
 2. In initscript mode, network role will create ifcfg file with
    `NM_CONTROLLED=no` instructing NetworkManager to mark the bridge as
    unmanaged. The follow up `down` and `absent` action of initscript
    provider will not change the NetworkManager's understanding on
    unmanaged state of this interface.

Fixes:
 1. We cannot change existing behaviour of initscript on not deleting
    interface in `down` and `absent` action. So we change the test
    function `tests/playbooks/down_profile.yml` to delete the interface
    manually via `ip link del <ifname>` command.

 2. Use `NM.Client.reload_connections_async()` to reload the
    configuration for nm provider on NetworkManager 1.18.

Previous test infrastructure is running each test file in a brand new VM
or container which cause this problem not been found before.

Dedicate test case `tests/tests_switch_provider.yml` included.

Signed-off-by: Gris Ge <fge@redhat.com>
2022-01-28 17:47:13 +01:00

90 lines
3.1 KiB
Python

# SPDX-License-Identifier: BSD-3-Clause
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import logging
# Relative import is not support by ansible 2.8 yet
# pylint: disable=import-error, no-name-in-module
from ansible.module_utils.network_lsr.nm import active_connection # noqa:E501
from ansible.module_utils.network_lsr.nm import client # noqa:E501
from ansible.module_utils.network_lsr.nm import connection # noqa:E501
# pylint: enable=import-error, no-name-in-module
class NetworkManagerProvider:
def deactivate_connection(self, connection_name, timeout, check_mode):
"""
Return True if changed.
"""
nm_client = client.get_client()
changed = False
for nm_ac in nm_client.get_active_connections():
nm_profile = nm_ac.get_connection()
if nm_profile and nm_profile.get_id() == connection_name:
changed |= active_connection.deactivate_active_connection(
nm_ac, timeout, check_mode
)
if not changed:
logging.info("No active connection for %s", connection_name)
return changed
def volatilize_connection_by_uuid(self, uuid, timeout, check_mode):
"""
Mark NM.RemoteConnection as volatile(delete on deactivation) via Update2,
if not supported, delete the profile.
Return True if changed.
"""
nm_client = client.get_client()
changed = False
for nm_profile in nm_client.get_connections():
if nm_profile and nm_profile.get_uuid() == uuid:
if hasattr(nm_profile, "update2"):
changed |= connection.volatilize_remote_connection(
nm_profile, timeout, check_mode
)
else:
changed |= connection.delete_remote_connection(
nm_profile, timeout, check_mode
)
if not changed:
logging.info("No connection with UUID %s to volatilize", uuid)
return changed
def get_connections(self):
nm_client = client.get_client()
return nm_client.get_connections()
def get_client_version(self):
nm_client = client.get_client()
return nm_client.get_version()
def reload_configuration(self):
timeout = 10
nm_client = client.get_client()
main_loop = client.get_mainloop(timeout)
logging.debug("Reloading configuration with timeout %s", timeout)
nm_client.reload_connections_async(
main_loop.cancellable, _reload_config_callback, main_loop
)
main_loop.run()
def _reload_config_callback(nm_client, result, main_loop):
try:
success = nm_client.reload_connections_finish(result)
except client.GLib.Error as e:
logging.warn("Failed to reload configuration: %s", e)
main_loop.quit()
return
if success:
logging.debug("Reloading configuration finished")
else:
logging.warn("Failed to reload configuration, no error message")
main_loop.quit()