289 lines
10 KiB
Diff
289 lines
10 KiB
Diff
From c4dd229113c70a7c402e4488ab0a30e4605e8d60 Mon Sep 17 00:00:00 2001
|
|
From: Lubomir Rintel <lkundrak@v3.sk>
|
|
Date: Mon, 26 Sep 2022 10:58:31 +0200
|
|
Subject: [PATCH 68/75] Add NetworkManagerConnectionScanner actor
|
|
|
|
This scans the NetworkManager connection profiles in form of keyfiles at
|
|
/etc/NetworkManager/system-connections and produces a
|
|
NetworkManagerConnection whenever for each one.
|
|
|
|
This doesn't need the NetworkManager daemon to be actually running,
|
|
but needs GObject introspection to be available. The reason for that is
|
|
that libnm is used (via Gir) to strip the secrets.
|
|
|
|
Add requirement for
|
|
NetworkManager-libnm
|
|
python3-gobject-base
|
|
packages. Both are available for all architectures on RHEL 8 and 9.
|
|
Currently require them only on RHEL 8 as they are not used in the
|
|
code anywhere for RHEL 9 and they seem to be used only for upgrade
|
|
RHEL 8 to RHEL 9.
|
|
|
|
Bump leapp-repository-dependencies to 9
|
|
---
|
|
packaging/leapp-repository.spec | 7 +-
|
|
.../other_specs/leapp-el7toel8-deps.spec | 3 +-
|
|
.../networkmanagerconnectionscanner/actor.py | 18 +++
|
|
.../networkmanagerconnectionscanner.py | 65 +++++++++++
|
|
...it_test_networkmanagerconnectionscanner.py | 105 ++++++++++++++++++
|
|
5 files changed, 196 insertions(+), 2 deletions(-)
|
|
create mode 100644 repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/actor.py
|
|
create mode 100644 repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/libraries/networkmanagerconnectionscanner.py
|
|
create mode 100644 repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py
|
|
|
|
diff --git a/packaging/leapp-repository.spec b/packaging/leapp-repository.spec
|
|
index 044e7275..8d6376ea 100644
|
|
--- a/packaging/leapp-repository.spec
|
|
+++ b/packaging/leapp-repository.spec
|
|
@@ -2,7 +2,7 @@
|
|
%global repositorydir %{leapp_datadir}/repositories
|
|
%global custom_repositorydir %{leapp_datadir}/custom-repositories
|
|
|
|
-%define leapp_repo_deps 8
|
|
+%define leapp_repo_deps 9
|
|
|
|
%if 0%{?rhel} == 7
|
|
%define leapp_python_sitelib %{python2_sitelib}
|
|
@@ -176,6 +176,11 @@ Requires: kmod
|
|
# and missing dracut could be killing situation for us :)
|
|
Requires: dracut
|
|
|
|
+# Required to scan NetworkManagerConnection (e.g. to recognize secrets)
|
|
+# NM is requested to be used on RHEL 8+ systems
|
|
+Requires: NetworkManager-libnm
|
|
+Requires: python3-gobject-base
|
|
+
|
|
%endif
|
|
##################################################
|
|
# end requirement
|
|
diff --git a/packaging/other_specs/leapp-el7toel8-deps.spec b/packaging/other_specs/leapp-el7toel8-deps.spec
|
|
index 822b6f63..4a181ee1 100644
|
|
--- a/packaging/other_specs/leapp-el7toel8-deps.spec
|
|
+++ b/packaging/other_specs/leapp-el7toel8-deps.spec
|
|
@@ -9,7 +9,7 @@
|
|
%endif
|
|
|
|
|
|
-%define leapp_repo_deps 8
|
|
+%define leapp_repo_deps 9
|
|
%define leapp_framework_deps 5
|
|
|
|
# NOTE: the Version contains the %{rhel} macro just for the convenience to
|
|
@@ -68,6 +68,7 @@ Requires: cpio
|
|
# just to be sure that /etc/modprobe.d is present
|
|
Requires: kmod
|
|
|
|
+
|
|
%description -n %{lrdname}
|
|
%{summary}
|
|
|
|
diff --git a/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/actor.py b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/actor.py
|
|
new file mode 100644
|
|
index 00000000..6ee66b52
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/actor.py
|
|
@@ -0,0 +1,18 @@
|
|
+from leapp.actors import Actor
|
|
+from leapp.libraries.actor import networkmanagerconnectionscanner
|
|
+from leapp.models import NetworkManagerConnection
|
|
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
|
|
+
|
|
+
|
|
+class NetworkManagerConnectionScanner(Actor):
|
|
+ """
|
|
+ Scan NetworkManager connection keyfiles
|
|
+ """
|
|
+
|
|
+ name = "network_manager_connection_scanner"
|
|
+ consumes = ()
|
|
+ produces = (NetworkManagerConnection,)
|
|
+ tags = (IPUWorkflowTag, FactsPhaseTag,)
|
|
+
|
|
+ def process(self):
|
|
+ networkmanagerconnectionscanner.process()
|
|
diff --git a/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/libraries/networkmanagerconnectionscanner.py b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/libraries/networkmanagerconnectionscanner.py
|
|
new file mode 100644
|
|
index 00000000..b148de6b
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/libraries/networkmanagerconnectionscanner.py
|
|
@@ -0,0 +1,65 @@
|
|
+import errno
|
|
+import os
|
|
+
|
|
+from leapp.exceptions import StopActorExecutionError
|
|
+from leapp.libraries.common import utils
|
|
+from leapp.libraries.stdlib import api
|
|
+from leapp.models import NetworkManagerConnection, NetworkManagerConnectionProperty, NetworkManagerConnectionSetting
|
|
+
|
|
+libnm_available = False
|
|
+err_details = None
|
|
+try:
|
|
+ import gi
|
|
+ try:
|
|
+ gi.require_version("NM", "1.0")
|
|
+ from gi.repository import GLib, NM
|
|
+ libnm_available = True
|
|
+ except ValueError:
|
|
+ err_details = 'NetworkManager-libnm package is not available'
|
|
+except ImportError:
|
|
+ err_details = 'python3-gobject-base package is not available'
|
|
+
|
|
+NM_CONN_DIR = "/etc/NetworkManager/system-connections"
|
|
+
|
|
+
|
|
+def process_file(filename):
|
|
+ # We're running this through libnm in order to clear the secrets.
|
|
+ # We don't know what keys are secret, but libnm does.
|
|
+ keyfile = GLib.KeyFile()
|
|
+ keyfile.load_from_file(filename, GLib.KeyFileFlags.NONE)
|
|
+ con = NM.keyfile_read(keyfile, NM_CONN_DIR, NM.KeyfileHandlerFlags.NONE)
|
|
+ con.clear_secrets()
|
|
+ keyfile = NM.keyfile_write(con, NM.KeyfileHandlerFlags.NONE)
|
|
+ cp = utils.parse_config(keyfile.to_data()[0])
|
|
+
|
|
+ settings = []
|
|
+ for setting_name in cp.sections():
|
|
+ properties = []
|
|
+ for name, value in cp.items(setting_name, raw=True):
|
|
+ properties.append(NetworkManagerConnectionProperty(name=name, value=value))
|
|
+ settings.append(
|
|
+ NetworkManagerConnectionSetting(name=setting_name, properties=properties)
|
|
+ )
|
|
+ api.produce(NetworkManagerConnection(filename=filename, settings=settings))
|
|
+
|
|
+
|
|
+def process_dir(directory):
|
|
+ try:
|
|
+ keyfiles = os.listdir(directory)
|
|
+ except OSError as e:
|
|
+ if e.errno == errno.ENOENT:
|
|
+ return
|
|
+ raise
|
|
+
|
|
+ for f in keyfiles:
|
|
+ process_file(os.path.join(NM_CONN_DIR, f))
|
|
+
|
|
+
|
|
+def process():
|
|
+ if libnm_available:
|
|
+ process_dir(NM_CONN_DIR)
|
|
+ else:
|
|
+ raise StopActorExecutionError(
|
|
+ message='Failed to read NetworkManager connections',
|
|
+ details=err_details
|
|
+ )
|
|
diff --git a/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py
|
|
new file mode 100644
|
|
index 00000000..46af07c1
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py
|
|
@@ -0,0 +1,105 @@
|
|
+import errno
|
|
+import textwrap
|
|
+
|
|
+import pytest
|
|
+import six
|
|
+
|
|
+from leapp.libraries.actor import networkmanagerconnectionscanner as nmconnscanner
|
|
+from leapp.libraries.common.testutils import make_OSError, produce_mocked
|
|
+from leapp.libraries.stdlib import api
|
|
+from leapp.models import NetworkManagerConnection
|
|
+
|
|
+_builtins_open = "builtins.open" if six.PY3 else "__builtin__.open"
|
|
+
|
|
+
|
|
+def _listdir_nm_conn(path):
|
|
+ if path == nmconnscanner.NM_CONN_DIR:
|
|
+ return ["conn1.nmconnection"]
|
|
+ raise make_OSError(errno.ENOENT)
|
|
+
|
|
+
|
|
+def _listdir_nm_conn2(path):
|
|
+ if path == nmconnscanner.NM_CONN_DIR:
|
|
+ return ["conn1.nmconnection", "conn2.nmconnection"]
|
|
+ raise make_OSError(errno.ENOENT)
|
|
+
|
|
+
|
|
+def _load_from_file(keyfile, filename, flags):
|
|
+ if filename.endswith(".nmconnection"):
|
|
+ return keyfile.load_from_data(textwrap.dedent("""
|
|
+ [connection]
|
|
+ type=wifi
|
|
+ id=conn1
|
|
+ uuid=a1bc695d-c548-40e8-9c7f-205a6587135d
|
|
+
|
|
+ [wifi]
|
|
+ mode=infrastructure
|
|
+ ssid=wifi
|
|
+
|
|
+ [wifi-security]
|
|
+ auth-alg=open
|
|
+ key-mgmt=none
|
|
+ wep-key-type=1
|
|
+ wep-key0=abcde
|
|
+ """), nmconnscanner.GLib.MAXSIZE, flags)
|
|
+ raise make_OSError(errno.ENOENT)
|
|
+
|
|
+
|
|
+@pytest.mark.skipif(not nmconnscanner.libnm_available, reason="NetworkManager g-ir not installed")
|
|
+def test_no_conf(monkeypatch):
|
|
+ """
|
|
+ No report if there are no keyfiles
|
|
+ """
|
|
+
|
|
+ monkeypatch.setattr(nmconnscanner.os, "listdir", lambda _: ())
|
|
+ monkeypatch.setattr(api, "produce", produce_mocked())
|
|
+ nmconnscanner.process()
|
|
+ assert not api.produce.called
|
|
+
|
|
+
|
|
+@pytest.mark.skipif(not nmconnscanner.libnm_available, reason="NetworkManager g-ir not installed")
|
|
+def test_nm_conn(monkeypatch):
|
|
+ """
|
|
+ Check a basic keyfile
|
|
+ """
|
|
+
|
|
+ monkeypatch.setattr(nmconnscanner.os, "listdir", _listdir_nm_conn)
|
|
+ monkeypatch.setattr(api, "produce", produce_mocked())
|
|
+ monkeypatch.setattr(nmconnscanner.GLib.KeyFile, "load_from_file", _load_from_file)
|
|
+ nmconnscanner.process()
|
|
+
|
|
+ assert api.produce.called == 1
|
|
+ assert len(api.produce.model_instances) == 1
|
|
+ nm_conn = api.produce.model_instances[0]
|
|
+ assert isinstance(nm_conn, NetworkManagerConnection)
|
|
+ assert nm_conn.filename == "/etc/NetworkManager/system-connections/conn1.nmconnection"
|
|
+ assert len(nm_conn.settings) == 3
|
|
+ assert nm_conn.settings[0].name == "connection"
|
|
+ assert len(nm_conn.settings[0].properties) == 4
|
|
+ assert nm_conn.settings[0].properties[0].name == "id"
|
|
+ assert nm_conn.settings[0].properties[0].value == "conn1"
|
|
+ assert nm_conn.settings[2].name == "wifi-security"
|
|
+
|
|
+ # It's important that wek-key0 is gone
|
|
+ assert len(nm_conn.settings[2].properties) == 3
|
|
+ assert nm_conn.settings[2].properties[0].name == "auth-alg"
|
|
+ assert nm_conn.settings[2].properties[0].value == "open"
|
|
+ assert nm_conn.settings[2].properties[1].name != "wep-key0"
|
|
+ assert nm_conn.settings[2].properties[2].name != "wep-key0"
|
|
+
|
|
+
|
|
+@pytest.mark.skipif(not nmconnscanner.libnm_available, reason="NetworkManager g-ir not installed")
|
|
+def test_nm_conn2(monkeypatch):
|
|
+ """
|
|
+ Check a pair of keyfiles
|
|
+ """
|
|
+
|
|
+ monkeypatch.setattr(nmconnscanner.os, "listdir", _listdir_nm_conn2)
|
|
+ monkeypatch.setattr(api, "produce", produce_mocked())
|
|
+ monkeypatch.setattr(nmconnscanner.GLib.KeyFile, "load_from_file", _load_from_file)
|
|
+ nmconnscanner.process()
|
|
+
|
|
+ assert api.produce.called == 2
|
|
+ assert len(api.produce.model_instances) == 2
|
|
+ assert api.produce.model_instances[0].filename.endswith("/conn1.nmconnection")
|
|
+ assert api.produce.model_instances[1].filename.endswith("/conn2.nmconnection")
|
|
--
|
|
2.39.0
|
|
|