Blame SOURCES/network-switch-provider.diff

88a858
From c98c17a236f7db1aabd2b67fad8fff772667ab39 Mon Sep 17 00:00:00 2001
88a858
From: Gris Ge <fge@redhat.com>
88a858
Date: Fri, 21 Jan 2022 18:24:54 +0800
88a858
Subject: [PATCH 1/2] Fix problem when switch provider from initscript to nm
88a858
88a858
Problem:
88a858
88a858
After `tests_bridge_initscripts.yml` passed, the `tests_bridge_nm.yml`
88a858
will fail with NetworkManager 1.18.
88a858
88a858
Root cause:
88a858
88a858
 1. The `absent` and `down` action of initscript provider will not
88a858
    remove the bridge interface which fail the assertion in
88a858
    `tests_bridge_nm.yml`.
88a858
 2. In initscript mode, network role will create ifcfg file with
88a858
    `NM_CONTROLLED=no` instructing NetworkManager to mark the bridge as
88a858
    unmanaged. The follow up `down` and `absent` action of initscript
88a858
    provider will not change the NetworkManager's understanding on
88a858
    unmanaged state of this interface.
88a858
88a858
Fixes:
88a858
 1. We cannot change existing behaviour of initscript on not deleting
88a858
    interface in `down` and `absent` action. So we change the test
88a858
    function `tests/playbooks/down_profile.yml` to delete the interface
88a858
    manually via `ip link del <ifname>` command.
88a858
88a858
 2. Use `NM.Client.reload_connections_async()` to reload the
88a858
    configuration for nm provider on NetworkManager 1.18.
88a858
88a858
Previous test infrastructure is running each test file in a brand new VM
88a858
or container which cause this problem not been found before.
88a858
88a858
Dedicate test case `tests/tests_switch_provider.yml` included.
88a858
88a858
Signed-off-by: Gris Ge <fge@redhat.com>
88a858
---
88a858
 library/network_connections.py                | 10 +++
88a858
 module_utils/network_lsr/nm/provider.py       | 28 ++++++++
88a858
 tests/ensure_provider_tests.py                |  1 +
88a858
 .../down_profile+delete_interface.yml         |  7 ++
88a858
 tests/playbooks/tests_switch_provider.yml     | 66 +++++++++++++++++++
88a858
 tests/tests_switch_provider.yml               | 10 +++
88a858
 7 files changed, 126 insertions(+)
88a858
 create mode 100644 tests/playbooks/down_profile+delete_interface.yml
88a858
 create mode 100644 tests/playbooks/tests_switch_provider.yml
88a858
 create mode 100644 tests/tests_switch_provider.yml
88a858
88a858
diff --git a/library/network_connections.py b/library/network_connections.py
88a858
index c810b4b..706b198 100644
88a858
--- a/library/network_connections.py
88a858
+++ b/library/network_connections.py
88a858
@@ -2055,6 +2055,16 @@ class Cmd_nm(Cmd):
88a858
                 len(self.connections) * DEFAULT_ACTIVATION_TIMEOUT
88a858
             )
88a858
 
88a858
+        # On NetworkManger 1.18, If user switch from initscripts provider where
88a858
+        # NM_CONTROLLED=no defined in ifcfg-ethX file, NetworkManager daemon will treat
88a858
+        # that interface as strictly unmanaged, even the follow up deletion of
88a858
+        # ifcfg-ethX file cannot change the NetworManager's unmanaged state of this
88a858
+        # interface. This will prevent any follow up "nm" provider action on this
88a858
+        # interface.  To solve that, we instruct NetworkManager to reload the
88a858
+        # configuration.
88a858
+        if self._nm_provider.get_client_version().startswith("1.18."):
88a858
+            self._nm_provider.reload_configuration()
88a858
+
88a858
     def rollback_transaction(self, idx, action, error):
88a858
         Cmd.rollback_transaction(self, idx, action, error)
88a858
         self.on_failure()
88a858
diff --git a/module_utils/network_lsr/nm/provider.py b/module_utils/network_lsr/nm/provider.py
88a858
index 567c9d1..9d3d491 100644
88a858
--- a/module_utils/network_lsr/nm/provider.py
88a858
+++ b/module_utils/network_lsr/nm/provider.py
88a858
@@ -60,3 +60,31 @@ class NetworkManagerProvider:
88a858
     def get_connections(self):
88a858
         nm_client = client.get_client()
88a858
         return nm_client.get_connections()
88a858
+
88a858
+    def get_client_version(self):
88a858
+        nm_client = client.get_client()
88a858
+        return nm_client.get_version()
88a858
+
88a858
+    def reload_configuration(self):
88a858
+        timeout = 10
88a858
+        nm_client = client.get_client()
88a858
+        main_loop = client.get_mainloop(timeout)
88a858
+        logging.debug("Reloading configuration with timeout %s", timeout)
88a858
+        nm_client.reload_connections_async(
88a858
+            main_loop.cancellable, _reload_config_callback, main_loop
88a858
+        )
88a858
+        main_loop.run()
88a858
+
88a858
+
88a858
+def _reload_config_callback(nm_client, result, main_loop):
88a858
+    try:
88a858
+        success = nm_client.reload_connections_finish(result)
88a858
+    except client.GLib.Error as e:
88a858
+        logging.warn("Failed to reload configuration: %s", e)
88a858
+        main_loop.quit()
88a858
+        return
88a858
+    if success:
88a858
+        logging.debug("Reloading configuration finished")
88a858
+    else:
88a858
+        logging.warn("Failed to reload configuration, no error message")
88a858
+    main_loop.quit()
88a858
diff --git a/tests/ensure_provider_tests.py b/tests/ensure_provider_tests.py
88a858
index e989eed..02844e9 100755
88a858
--- a/tests/ensure_provider_tests.py
88a858
+++ b/tests/ensure_provider_tests.py
88a858
@@ -132,6 +132,7 @@ NM_CONDITIONAL_TESTS = {
88a858
 IGNORE = [
88a858
     # checked by tests_regression_nm.yml
88a858
     "playbooks/tests_checkpoint_cleanup.yml",
88a858
+    "playbooks/tests_switch_provider.yml",
88a858
 ]
88a858
 
88a858
 RUN_PLAYBOOK_WITH_INITSCRIPTS = """# SPDX-License-Identifier: BSD-3-Clause
88a858
diff --git a/tests/playbooks/down_profile+delete_interface.yml b/tests/playbooks/down_profile+delete_interface.yml
88a858
new file mode 100644
88a858
index 0000000..1f5b5d3
88a858
--- /dev/null
88a858
+++ b/tests/playbooks/down_profile+delete_interface.yml
88a858
@@ -0,0 +1,7 @@
88a858
+# SPDX-License-Identifier: BSD-3-Clause
88a858
+---
88a858
+- import_playbook: down_profile.yml
88a858
+- name: Delete the interface when the network provider is initscripts
88a858
+  hosts: all
88a858
+  tasks:
88a858
+    - include_tasks: tasks/delete_interface.yml
88a858
diff --git a/tests/playbooks/tests_switch_provider.yml b/tests/playbooks/tests_switch_provider.yml
88a858
new file mode 100644
88a858
index 0000000..f2d165c
88a858
--- /dev/null
88a858
+++ b/tests/playbooks/tests_switch_provider.yml
88a858
@@ -0,0 +1,66 @@
88a858
+# SPDX-License-Identifier: BSD-3-Clause
88a858
+# This file was generated by ensure_provider_tests.py
88a858
+---
88a858
+# set network provider and gather facts
88a858
+- hosts: all
88a858
+  name: Switch initscripts provider to nm
88a858
+  vars:
88a858
+    interface: LSR-TST-br34
88a858
+  tasks:
88a858
+    - name: set fact to use initscripts network_provider
88a858
+      set_fact:
88a858
+        network_provider: initscripts
88a858
+      tags:
88a858
+        - always
88a858
+    - name: "Create test bridge {{ interface }} via initscripts provider"
88a858
+      include_role:
88a858
+        name: linux-system-roles.network
88a858
+      vars:
88a858
+        network_connections:
88a858
+          - name: "{{ interface }}"
88a858
+            state: up
88a858
+            type: bridge
88a858
+            ip:
88a858
+              dhcp4: false
88a858
+              auto6: false
88a858
+    - include_tasks: tasks/assert_device_present.yml
88a858
+    - name: "Take the profile {{ interface }} down via initscripts provider"
88a858
+      include_role:
88a858
+        name: linux-system-roles.network
88a858
+      vars:
88a858
+        network_connections:
88a858
+          - name: "{{ interface }}"
88a858
+            persistent_state: absent
88a858
+            state: down
88a858
+            type: bridge
88a858
+    # The initscripts should not remove the interface for down/absent
88a858
+    - include_tasks: tasks/assert_device_present.yml
88a858
+    - name: set fact to use nm network_provider
88a858
+      set_fact:
88a858
+        network_provider: nm
88a858
+      tags:
88a858
+        - always
88a858
+    - name: "Create test bridge {{ interface }} via nm provider"
88a858
+      include_role:
88a858
+        name: linux-system-roles.network
88a858
+      vars:
88a858
+        network_connections:
88a858
+          - name: "{{ interface }}"
88a858
+            state: up
88a858
+            type: bridge
88a858
+            ip:
88a858
+              dhcp4: false
88a858
+              auto6: false
88a858
+    - include_tasks: tasks/assert_device_present.yml
88a858
+    - name: "Remove bridge {{ interface }} via nm provider"
88a858
+      include_role:
88a858
+        name: linux-system-roles.network
88a858
+      vars:
88a858
+        network_connections:
88a858
+          - name: "{{ interface }}"
88a858
+            state: down
88a858
+            type: bridge
88a858
+    # NetworkManager should not remove pre-exist interface for down/absent
88a858
+    - include_tasks: tasks/assert_device_present.yml
88a858
+    - include_tasks: tasks/delete_interface.yml
88a858
+    - include_tasks: tasks/assert_device_absent.yml
88a858
diff --git a/tests/tests_switch_provider.yml b/tests/tests_switch_provider.yml
88a858
new file mode 100644
88a858
index 0000000..562fbf2
88a858
--- /dev/null
88a858
+++ b/tests/tests_switch_provider.yml
88a858
@@ -0,0 +1,10 @@
88a858
+# SPDX-License-Identifier: BSD-3-Clause
88a858
+---
88a858
+- hosts: all
88a858
+  name: Run playbook 'playbooks/tests_switch_provider.yml'
88a858
+
88a858
+- import_playbook: playbooks/tests_switch_provider.yml
88a858
+  when:
88a858
+    # The test requires or should run with NetworkManager, therefore it cannot
88a858
+    # run on RHEL/CentOS 6
88a858
+    - ansible_distribution_major_version != '6'
88a858
-- 
88a858
2.34.1
88a858