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>
This commit is contained in:
Gris Ge 2022-01-21 18:24:54 +08:00 committed by Fernando Fernández Mancera
parent f508c27674
commit c98c17a236
7 changed files with 126 additions and 0 deletions

4
.github/run_test.sh vendored
View file

@ -8,10 +8,13 @@ C8_CONTAINER_IMAGE="quay.io/linux-system-roles/c8-network-role"
C7_CONTAINER_IMAGE="quay.io/linux-system-roles/c7-network-role"
PODMAN_OPTS="--systemd=true --privileged"
# FIXME: test_wireless has been removed because is not supported on CI
# container EL7. We need to add this back for EL8 or greater.
read -r -d '' TEST_FILES << EOF || :
tests_802_1x_nm.yml
tests_bond_nm.yml
tests_auto_gateway_nm.yml
tests_bridge_initscripts.yml
tests_bridge_nm.yml
tests_change_indication_on_repeat_run.yml
tests_dummy_nm.yml
@ -22,6 +25,7 @@ tests_ethtool_ring_nm.yml
tests_ipv6_disabled_nm.yml
tests_ipv6_nm.yml
tests_vlan_mtu_nm.yml
tests_switch_provider.yml
EOF
EXEC_PATH=$(dirname "$(realpath "$0")")

View file

@ -2055,6 +2055,16 @@ class Cmd_nm(Cmd):
len(self.connections) * DEFAULT_ACTIVATION_TIMEOUT
)
# On NetworkManger 1.18, If user switch from initscripts provider where
# NM_CONTROLLED=no defined in ifcfg-ethX file, NetworkManager daemon will treat
# that interface as strictly unmanaged, even the follow up deletion of
# ifcfg-ethX file cannot change the NetworManager's unmanaged state of this
# interface. This will prevent any follow up "nm" provider action on this
# interface. To solve that, we instruct NetworkManager to reload the
# configuration.
if self._nm_provider.get_client_version().startswith("1.18."):
self._nm_provider.reload_configuration()
def rollback_transaction(self, idx, action, error):
Cmd.rollback_transaction(self, idx, action, error)
self.on_failure()

View file

@ -60,3 +60,31 @@ class NetworkManagerProvider:
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()

View file

@ -132,6 +132,7 @@ NM_CONDITIONAL_TESTS = {
IGNORE = [
# checked by tests_regression_nm.yml
"playbooks/tests_checkpoint_cleanup.yml",
"playbooks/tests_switch_provider.yml",
]
RUN_PLAYBOOK_WITH_INITSCRIPTS = """# SPDX-License-Identifier: BSD-3-Clause

View file

@ -0,0 +1,7 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- import_playbook: down_profile.yml
- name: Delete the interface when the network provider is initscripts
hosts: all
tasks:
- include_tasks: tasks/delete_interface.yml

View file

@ -0,0 +1,66 @@
# SPDX-License-Identifier: BSD-3-Clause
# This file was generated by ensure_provider_tests.py
---
# set network provider and gather facts
- hosts: all
name: Switch initscripts provider to nm
vars:
interface: LSR-TST-br34
tasks:
- name: set fact to use initscripts network_provider
set_fact:
network_provider: initscripts
tags:
- always
- name: "Create test bridge {{ interface }} via initscripts provider"
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
- name: "Take the profile {{ interface }} down via initscripts provider"
include_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
persistent_state: absent
state: down
type: bridge
# The initscripts should not remove the interface for down/absent
- include_tasks: tasks/assert_device_present.yml
- name: set fact to use nm network_provider
set_fact:
network_provider: nm
tags:
- always
- name: "Create test bridge {{ interface }} via nm provider"
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
- name: "Remove bridge {{ interface }} via nm provider"
include_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
state: down
type: bridge
# NetworkManager should not remove pre-exist interface for down/absent
- include_tasks: tasks/assert_device_present.yml
- include_tasks: tasks/delete_interface.yml
- include_tasks: tasks/assert_device_absent.yml

View file

@ -0,0 +1,10 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- hosts: all
name: Run playbook 'playbooks/tests_switch_provider.yml'
- import_playbook: playbooks/tests_switch_provider.yml
when:
# The test requires or should run with NetworkManager, therefore it cannot
# run on RHEL/CentOS 6
- ansible_distribution_major_version != '6'