From 20a20b60fb2338558cb5270819bdbb73c86afd59 Mon Sep 17 00:00:00 2001 From: Till Maas Date: Fri, 17 Apr 2020 22:27:14 +0200 Subject: [PATCH] Module/NM: Try to reapply connections --- library/network_connections.py | 37 ++++++++++++++++ tests/ensure_non_running_provider.py | 1 + tests/playbooks/tests_reapply.yml | 66 ++++++++++++++++++++++++++++ tests/tests_reapply_nm.yml | 17 +++++++ 4 files changed, 121 insertions(+) create mode 100644 tests/playbooks/tests_reapply.yml create mode 100644 tests/tests_reapply_nm.yml diff --git a/library/network_connections.py b/library/network_connections.py index 77718df..05275b3 100644 --- a/library/network_connections.py +++ b/library/network_connections.py @@ -1414,6 +1414,13 @@ class NMUtil: finally: ac.handler_disconnect(ac_id) + def reapply(self, device, connection=None): + version_id = 0 + flags = 0 + return Util.call_async_method( + device, "reapply", [connection, version_id, flags] + ) + ############################################################################### @@ -2144,6 +2151,9 @@ class Cmd_nm(Cmd): ) self.connections_data_set_changed(idx) if self.check_mode == CheckMode.REAL_RUN: + if self._try_reapply(idx, con): + return + try: ac = self.nmutil.connection_activate(con) except MyError as e: @@ -2158,6 +2168,33 @@ class Cmd_nm(Cmd): except MyError as e: self.log_error(idx, "up connection failed while waiting: %s" % (e)) + def _try_reapply(self, idx, con): + """ Try to reapply a connection + + If there is exactly one active connection with the same UUID activated + on exactly one device, ask the device to reapply the connection. + + :returns: `True`, when the connection was reapplied, `False` otherwise + :rtype: bool + """ + NM = Util.NM() + + acons = list(self.nmutil.active_connection_list(connections=[con])) + if len(acons) != 1: + return False + + active_connection = acons[0] + if active_connection.get_state() == NM.ActiveConnectionState.ACTIVATED: + devices = active_connection.get_devices() + if len(devices) == 1: + try: + self.nmutil.reapply(devices[0]) + self.log_info(idx, "connection reapplied") + return True + except MyError as error: + self.log_info(idx, "connection reapply failed: %s" % (error)) + return False + def run_action_down(self, idx): connection = self.connections[idx] diff --git a/tests/ensure_non_running_provider.py b/tests/ensure_non_running_provider.py index 426a908..2fb2176 100755 --- a/tests/ensure_non_running_provider.py +++ b/tests/ensure_non_running_provider.py @@ -21,6 +21,7 @@ IGNORE = [ "tests_ethtool_features_initscripts.yml", "tests_ethtool_features_nm.yml", "tests_helpers-and-asserts.yml", + "tests_reapply_nm.yml", "tests_regression_nm.yml", "tests_states.yml", "tests_unit.yml", diff --git a/tests/playbooks/tests_reapply.yml b/tests/playbooks/tests_reapply.yml new file mode 100644 index 0000000..b4f6629 --- /dev/null +++ b/tests/playbooks/tests_reapply.yml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: BSD-3-Clause +# This test should check whether the NMDevice.reapply method is called by the +# role. This is probably a good candidate to test with pytest directly instead +# of via Ansible. Until there is better test support for this, just check the +# log output for the respective log message. +--- +- hosts: all + vars: + interface: rpltstbr + profile: "{{ interface }}" + network_provider: nm + pre_tasks: + - debug: + msg: Inside states tests + - include_tasks: tasks/show-interfaces.yml + - include_tasks: tasks/assert-device_absent.yml + roles: + - linux-system-roles.network + tasks: + - block: + # create test profile + - include_role: + name: linux-system-roles.network + vars: + network_connections: + - name: "{{ interface }}" + state: up + type: bridge + ip: + dhcp4: false + auto6: false + - include_tasks: tasks/assert-device_present.yml + - include_tasks: tasks/assert-profile_present.yml + # Use internal module to get output + - network_connections: + provider: nm + connections: + - name: "{{ interface }}" + state: up + type: bridge + ip: + address: + - 192.0.2.72/31 + dhcp4: false + auto6: false + ignore_errors: true + register: test_module_run + - debug: + var: test_module_run + - name: Assert that reapply is found in log output + assert: + fail_msg: Reapply not found in log output + that: "{{ 'connection reapplied' in test_module_run.warnings[2] }}" + always: + - block: + # Use internal module directly for speedup + - network_connections: + provider: nm + connections: + - name: "{{ interface }}" + persistent_state: absent + state: down + - command: ip link del "{{ interface }}" + ignore_errors: true + tags: + - "tests::cleanup" diff --git a/tests/tests_reapply_nm.yml b/tests/tests_reapply_nm.yml new file mode 100644 index 0000000..81f3570 --- /dev/null +++ b/tests/tests_reapply_nm.yml @@ -0,0 +1,17 @@ +--- +# set network provider and gather facts +- hosts: all + tasks: + - name: Set network provider to 'nm' + set_fact: + network_provider: nm + +# workaround for: https://github.com/ansible/ansible/issues/27973 +# There is no way in Ansible to abort a playbook hosts with specific OS +# releases Therefore we include the playbook with the tests only if the hosts +# would support it. +# The test should run with NetworkManager, therefore it cannot run on +# RHEL/CentOS 6 +- import_playbook: playbooks/tests_reapply.yml + when: + - ansible_distribution_major_version != '6'