sync from sp2
This commit is contained in:
parent
d0844800c7
commit
836efdb1c0
@ -1,7 +1,7 @@
|
|||||||
%define _empty_manifest_terminate_build 0
|
%define _empty_manifest_terminate_build 0
|
||||||
Name: anaconda
|
Name: anaconda
|
||||||
Version: 36.16.5
|
Version: 36.16.5
|
||||||
Release: 15
|
Release: 18
|
||||||
Summary: Graphical system installer
|
Summary: Graphical system installer
|
||||||
License: GPLv2+ and MIT
|
License: GPLv2+ and MIT
|
||||||
URL: http://fedoraproject.org/wiki/Anaconda
|
URL: http://fedoraproject.org/wiki/Anaconda
|
||||||
@ -37,10 +37,17 @@ Patch9015: bugfix-change-gnome-kiosk-to-use-metacity.patch
|
|||||||
Patch9016: bugfix-add-log-and-background.patch
|
Patch9016: bugfix-add-log-and-background.patch
|
||||||
Patch9017: bugfix-add-SM3-with-tui.patch
|
Patch9017: bugfix-add-SM3-with-tui.patch
|
||||||
Patch9018: bugfix-change-product-name-do-not-with-upper.patch
|
Patch9018: bugfix-change-product-name-do-not-with-upper.patch
|
||||||
|
Patch6003: backport-dracut-handle-compressed-kernel-modules.patch
|
||||||
|
Patch6004: backport-Ignore-SIGINT-in-D-Bus-launcher-and-x11-too.patch
|
||||||
|
Patch6005: backport-network-use-separate-main-conext-for-NM-client-in-threads.patch
|
||||||
|
Patch6006: backport-Sort-RPM-versions-via-rpm.labelCompare-and-not-via-p.patch
|
||||||
|
|
||||||
Patch9019: bugfix-adapt-active-connection-without-interface-name.patch
|
Patch9019: bugfix-adapt-active-connection-without-interface-name.patch
|
||||||
|
|
||||||
Patch9020: bugfix-password-tooltip-text-adapt-language.patch
|
Patch9020: bugfix-password-tooltip-text-adapt-language.patch
|
||||||
|
|
||||||
|
Patch9021: bugfix-revert-Unify-GRUB-configuration-file-location-across-all-platforms.patch
|
||||||
|
|
||||||
%define dasbusver 1.3
|
%define dasbusver 1.3
|
||||||
%define dbusver 1.2.3
|
%define dbusver 1.2.3
|
||||||
%define dnfver 3.6.0
|
%define dnfver 3.6.0
|
||||||
@ -282,6 +289,27 @@ update-desktop-database &> /dev/null || :
|
|||||||
%{_prefix}/libexec/anaconda/dd_*
|
%{_prefix}/libexec/anaconda/dd_*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Jun 09 2023 sunhai <sunhai10@huawei.com> - 36.16.5-18
|
||||||
|
- Type:bugfix
|
||||||
|
- ID:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC: set grub configuration file is as original
|
||||||
|
|
||||||
|
* Fri Jun 09 2023 sunhai <sunhai10@huawei.com> - 36.16.5-17
|
||||||
|
- Type:bugfix
|
||||||
|
- ID:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC: Ignore SIGINT in D Bus launcher and x11 too
|
||||||
|
network use separate main conext for NM client in threads
|
||||||
|
dracut handle compressed kernel modules
|
||||||
|
Sort RPM versions via rpm.labelCompare
|
||||||
|
|
||||||
|
* Sat Jun 03 2023 sunhai <sunhai10@huawei.com> - 36.16.5-16
|
||||||
|
- Type:bugfix
|
||||||
|
- ID:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC: fix gui hostname warn info
|
||||||
|
|
||||||
* Tue May 16 2023 Chenxi Mao <chenxi.mao@suse.com> - 36.16.5-15
|
* Tue May 16 2023 Chenxi Mao <chenxi.mao@suse.com> - 36.16.5-15
|
||||||
- Type:bugfix
|
- Type:bugfix
|
||||||
- ID:NA
|
- ID:NA
|
||||||
|
|||||||
76
backport-Ignore-SIGINT-in-D-Bus-launcher-and-x11-too.patch
Normal file
76
backport-Ignore-SIGINT-in-D-Bus-launcher-and-x11-too.patch
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
From d8060d01a01e3d5b187ae4388f10b0d0c2c0c4f3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: iasunsea <iasunsea@sina.com>
|
||||||
|
Date: Tue, 6 Dec 2022 18:24:50 +0800
|
||||||
|
Subject: [PATCH] Ignore SIGINT in D-Bus launcher and x11 too
|
||||||
|
|
||||||
|
When we do install, especially use TUI to install, we some time have take
|
||||||
|
a mistake to put "CTRL+C", then there will be stop with traceback. And we
|
||||||
|
know the main process have shielded SIGINT, so we to shield subprocesses also.
|
||||||
|
|
||||||
|
Conflict:NA
|
||||||
|
Reference:https://github.com/rhinstaller/anaconda/commit/d8060d01a01e3d5b187ae4388f10b0d0c2c0c4f3
|
||||||
|
---
|
||||||
|
pyanaconda/core/startup/dbus_launcher.py | 6 ++++++
|
||||||
|
pyanaconda/display.py | 8 +++++++-
|
||||||
|
2 files changed, 13 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/core/startup/dbus_launcher.py b/pyanaconda/core/startup/dbus_launcher.py
|
||||||
|
index 2881c28..a866df0 100644
|
||||||
|
--- a/pyanaconda/core/startup/dbus_launcher.py
|
||||||
|
+++ b/pyanaconda/core/startup/dbus_launcher.py
|
||||||
|
@@ -24,6 +24,7 @@
|
||||||
|
# Author(s): Jiri Konecny <jkonecny@redhat.com>
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
+import signal
|
||||||
|
from subprocess import TimeoutExpired
|
||||||
|
|
||||||
|
from pyanaconda.core.configuration.anaconda import conf
|
||||||
|
@@ -109,6 +110,10 @@ class AnacondaDBusLauncher(object):
|
||||||
|
"--syslog",
|
||||||
|
"--config-file={}".format(ANACONDA_BUS_CONF_FILE)
|
||||||
|
]
|
||||||
|
+
|
||||||
|
+ def dbus_preexec():
|
||||||
|
+ # to set dbus subprocess SIGINT handler
|
||||||
|
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
|
||||||
|
self._log_file = open('/tmp/dbus.log', 'a')
|
||||||
|
self._dbus_daemon_process = startProgram(
|
||||||
|
@@ -117,6 +122,7 @@ class AnacondaDBusLauncher(object):
|
||||||
|
env_add={"LANG": DEFAULT_LANG},
|
||||||
|
env_prune=["LANGUAGE", "LC_ALL", "LC_MESSAGES"],
|
||||||
|
reset_lang=False,
|
||||||
|
+ preexec_fn=dbus_preexec
|
||||||
|
)
|
||||||
|
|
||||||
|
if self._dbus_daemon_process.poll() is not None:
|
||||||
|
diff --git a/pyanaconda/display.py b/pyanaconda/display.py
|
||||||
|
index ddf24fb..ed163e7 100644
|
||||||
|
--- a/pyanaconda/display.py
|
||||||
|
+++ b/pyanaconda/display.py
|
||||||
|
@@ -24,6 +24,7 @@ import subprocess
|
||||||
|
import time
|
||||||
|
import textwrap
|
||||||
|
import pkgutil
|
||||||
|
+import signal
|
||||||
|
|
||||||
|
from pyanaconda.core.configuration.anaconda import conf
|
||||||
|
from pyanaconda.core.process_watchers import WatchProcesses
|
||||||
|
@@ -192,8 +193,13 @@ def do_startup_x11_actions():
|
||||||
|
else:
|
||||||
|
xdg_data_dirs = datadir + '/window-manager:/usr/share'
|
||||||
|
|
||||||
|
+ def x11_preexec():
|
||||||
|
+ # to set GUI subprocess SIGINT handler
|
||||||
|
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
+
|
||||||
|
childproc = util.startProgram(["metacity", "--display", ":1", "--sm-disable"],
|
||||||
|
- env_add={'XDG_DATA_DIRS': xdg_data_dirs})
|
||||||
|
+ env_add={'XDG_DATA_DIRS': xdg_data_dirs},
|
||||||
|
+ preexec_fn=x11_preexec)
|
||||||
|
WatchProcesses.watch_process(childproc, "metacity")
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
2.23.0
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
From 1742188518c9af7e3cd060a26f3a3b1e4cb61e91 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
|
||||||
|
Date: Fri, 3 Feb 2023 21:46:15 +0100
|
||||||
|
Subject: [PATCH] Sort RPM versions via rpm.labelCompare() and not via
|
||||||
|
packaging.version.LegacyVersion()
|
||||||
|
|
||||||
|
Packaging 22+ removed the long-deprecated packaging.version.LegacyVersion class.
|
||||||
|
The packaging.version library is intended to parse Python (PEP 440) versions,
|
||||||
|
not arbitrary versions and definitively not RPM versions.
|
||||||
|
|
||||||
|
Even if LegacyVersion was still available, it may produce incorrect results
|
||||||
|
if the version contains ~, ^ or other characters with special meaning in RPM.
|
||||||
|
|
||||||
|
This assumes the Python rpm module is always available.
|
||||||
|
If that assumption is wrong
|
||||||
|
the logic from rpm.labelCompare() needs to be reimplemented instead.
|
||||||
|
|
||||||
|
Reference:https://github.com/rhinstaller/anaconda/commit/1742188518c9af7e3cd060a26f3a3b1e4cb61e91
|
||||||
|
Conflict:NA
|
||||||
|
---
|
||||||
|
pyanaconda/core/payload.py | 5 +++++
|
||||||
|
pyanaconda/modules/payloads/base/utils.py | 13 ++-----------
|
||||||
|
pyanaconda/modules/storage/checker/utils.py | 4 ++--
|
||||||
|
3 files changed, 9 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/core/payload.py b/pyanaconda/core/payload.py
|
||||||
|
index 17277b7..7817150 100644
|
||||||
|
--- a/pyanaconda/core/payload.py
|
||||||
|
+++ b/pyanaconda/core/payload.py
|
||||||
|
@@ -15,11 +15,16 @@
|
||||||
|
# License and may only be used or replicated with the express permission of
|
||||||
|
# Red Hat, Inc.
|
||||||
|
#
|
||||||
|
+from functools import cmp_to_key
|
||||||
|
from urllib.parse import quote, unquote
|
||||||
|
|
||||||
|
+import rpm
|
||||||
|
+
|
||||||
|
from pyanaconda.core.i18n import _
|
||||||
|
from pyanaconda.core.regexes import URL_PARSE
|
||||||
|
|
||||||
|
+rpm_version_key = cmp_to_key(rpm.labelCompare)
|
||||||
|
+
|
||||||
|
|
||||||
|
def parse_nfs_url(nfs_url):
|
||||||
|
"""Parse NFS URL into components.
|
||||||
|
diff --git a/pyanaconda/modules/payloads/base/utils.py b/pyanaconda/modules/payloads/base/utils.py
|
||||||
|
index 738ae66..5f19b57 100644
|
||||||
|
--- a/pyanaconda/modules/payloads/base/utils.py
|
||||||
|
+++ b/pyanaconda/modules/payloads/base/utils.py
|
||||||
|
@@ -17,13 +17,11 @@
|
||||||
|
# License and may only be used or replicated with the express permission of
|
||||||
|
# Red Hat, Inc.
|
||||||
|
#
|
||||||
|
-import functools
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
|
||||||
|
-from packaging.version import LegacyVersion as parse_version
|
||||||
|
-
|
||||||
|
from pyanaconda.anaconda_loggers import get_module_logger
|
||||||
|
+from pyanaconda.core.payload import rpm_version_key
|
||||||
|
log = get_module_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -70,11 +68,4 @@ def get_dir_size(directory):
|
||||||
|
|
||||||
|
def sort_kernel_version_list(kernel_version_list):
|
||||||
|
"""Sort the given kernel version list."""
|
||||||
|
- kernel_version_list.sort(key=functools.cmp_to_key(_compare_versions))
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-def _compare_versions(v1, v2):
|
||||||
|
- """Compare two version number strings."""
|
||||||
|
- first_version = parse_version(v1)
|
||||||
|
- second_version = parse_version(v2)
|
||||||
|
- return (first_version > second_version) - (first_version < second_version)
|
||||||
|
+ kernel_version_list.sort(key=rpm_version_key)
|
||||||
|
diff --git a/pyanaconda/modules/storage/checker/utils.py b/pyanaconda/modules/storage/checker/utils.py
|
||||||
|
index 180c351..9ccd398 100644
|
||||||
|
--- a/pyanaconda/modules/storage/checker/utils.py
|
||||||
|
+++ b/pyanaconda/modules/storage/checker/utils.py
|
||||||
|
@@ -20,7 +20,6 @@ gi.require_version("BlockDev", "2.0")
|
||||||
|
from gi.repository import BlockDev as blockdev
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
-from packaging.version import LegacyVersion as parse_version
|
||||||
|
|
||||||
|
from blivet import arch, util
|
||||||
|
from blivet.devicefactory import get_device_type
|
||||||
|
@@ -34,6 +33,7 @@ from pyanaconda.core.constants import productName, STORAGE_REFORMAT_BLOCKLIST, \
|
||||||
|
STORAGE_LUKS2_MIN_RAM, STORAGE_ROOT_DEVICE_TYPES, STORAGE_REQ_PARTITION_SIZES, \
|
||||||
|
STORAGE_MUST_NOT_BE_ON_ROOT
|
||||||
|
from pyanaconda.core.i18n import _
|
||||||
|
+from pyanaconda.core.payload import rpm_version_key
|
||||||
|
from pyanaconda.core.storage import DEVICE_TEXT_MAP
|
||||||
|
from pyanaconda.modules.storage.platform import platform
|
||||||
|
|
||||||
|
@@ -259,7 +259,7 @@ def _check_opal_firmware_kernel_version(detected_version, required_version):
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if detected_version and required_version:
|
||||||
|
- return parse_version(detected_version) >= parse_version(required_version)
|
||||||
|
+ return rpm_version_key(detected_version) >= rpm_version_key(required_version)
|
||||||
|
except Exception as e: # pylint: disable=broad-except
|
||||||
|
log.warning("Couldn't check the firmware kernel version: %s", str(e))
|
||||||
|
|
||||||
|
--
|
||||||
|
2.23.0
|
||||||
47
backport-dracut-handle-compressed-kernel-modules.patch
Normal file
47
backport-dracut-handle-compressed-kernel-modules.patch
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
From c4a388d3956088c96631b72f0631db2a380127b0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mikhail Novosyolov <m.novosyolov@rosalinux.ru>
|
||||||
|
Date: Fri, 10 Jun 2022 22:03:43 +0300
|
||||||
|
Subject: [PATCH] dracut: handle compressed kernel modules
|
||||||
|
|
||||||
|
Compressed kernel modules could not be loaded.
|
||||||
|
Now both compressed and not compressed ones will be loaded.
|
||||||
|
|
||||||
|
$ uname -r
|
||||||
|
5.10.74-generic-2rosa2021.1-x86_64
|
||||||
|
$ ls -1v /lib/modules/$(uname -r)/kernel/drivers/scsi/device_handler/
|
||||||
|
scsi_dh_alua.ko.zst
|
||||||
|
scsi_dh_emc.ko.zst
|
||||||
|
scsi_dh_hp_sw.ko.zst
|
||||||
|
scsi_dh_rdac.ko.zst
|
||||||
|
|
||||||
|
Replaces https://github.com/rhinstaller/anaconda/pull/3501
|
||||||
|
Noted by slava86@
|
||||||
|
Reference:https://github.com/rhinstaller/anaconda/commit/c4a388d3956088c96631b72f0631db2a380127b0
|
||||||
|
Conflict:NA
|
||||||
|
---
|
||||||
|
dracut/anaconda-modprobe.sh | 9 +++++----
|
||||||
|
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dracut/anaconda-modprobe.sh b/dracut/anaconda-modprobe.sh
|
||||||
|
index 97ee53bcb1..3640b4d42f 100755
|
||||||
|
--- a/dracut/anaconda-modprobe.sh
|
||||||
|
+++ b/dracut/anaconda-modprobe.sh
|
||||||
|
@@ -14,11 +14,12 @@ MODULE_LIST="cramfs squashfs iscsi_tcp "
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
SCSI_MODULES=/lib/modules/$KERNEL/kernel/drivers/scsi/device_handler/
|
||||||
|
-for m in "$SCSI_MODULES"/*.ko; do
|
||||||
|
+for m in "$SCSI_MODULES"/*.ko*; do
|
||||||
|
# Shell spew to work around not having basename
|
||||||
|
- # Trim the paths off the prefix, then the . suffix
|
||||||
|
- a="${m##*/}"
|
||||||
|
- MODULE_LIST+=" ${a%.*}"
|
||||||
|
+ m="${m##*/}"
|
||||||
|
+ # Handle *.ko, *.ko.zst, *.ko.gz, *.ko.xz etc.
|
||||||
|
+ IFS='.ko' read -r -a m <<< "$m"
|
||||||
|
+ MODULE_LIST+=" ${m[0]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
shopt -u nullglob
|
||||||
|
--
|
||||||
|
2.23.0
|
||||||
@ -0,0 +1,824 @@
|
|||||||
|
From 3972b5dadcadd355d2ff25eae601bc35c336c45a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Radek Vykydal <rvykydal@redhat.com>
|
||||||
|
Date: Thu, 29 Sep 2022 12:38:55 +0200
|
||||||
|
Subject: [PATCH] network: use separate main conext for NM client in threads
|
||||||
|
|
||||||
|
Resolves: rhbz#1931389
|
||||||
|
|
||||||
|
Create a special NM client with separate main context for calling NM
|
||||||
|
client from installation tasks which run in separate threads.
|
||||||
|
|
||||||
|
Based on a pull request by t.feng <t.feng94 at foxmail.com> who deserves
|
||||||
|
the biggest credit, and upated with suggestions by poncovka <vponcova at
|
||||||
|
redhat.com>
|
||||||
|
|
||||||
|
The created client should be used only in a limited scope as documented
|
||||||
|
in nm_client_in_thread docstring. If we want to extend it and address
|
||||||
|
potential issues with client instance releasing and reusing we'd need to
|
||||||
|
follow recommendations from Thomas Haller's kind reviews:
|
||||||
|
|
||||||
|
<snip>
|
||||||
|
|
||||||
|
first of all, initializing a NMClient instance takes relatively long,
|
||||||
|
because it makes D-Bus calls and the round trip time adds up. Btw, if
|
||||||
|
you'd pass
|
||||||
|
instance_flags=NM.ClientInstanceFlags.NO_AUTO_FETCH_PERMISSIONS it can
|
||||||
|
make it faster, see here. If it's too slow, then the solution would be
|
||||||
|
to re-use the nmclient instance or use async initialization and do stuff
|
||||||
|
in parallel. Both is more complicated however, so not necessary unless
|
||||||
|
we find that it's a problem.
|
||||||
|
|
||||||
|
What is maybe more a problem is that each GMainContext consumes at least
|
||||||
|
one file descriptor. When you use the sync nm_client_new() method, then
|
||||||
|
NMClient has an additional internal GMainContext, so possibly there are
|
||||||
|
2 or more file descriptors involved. The way to "stop" NMClient is by
|
||||||
|
unrefing it. However, with all async operations in glib, they cannot
|
||||||
|
complete right away. That is because when NMClient gets unrefed, it will
|
||||||
|
cancel all (internally) pending operations, but even when you cancel a
|
||||||
|
glib operation, the callback still will be invoked with the cancellation
|
||||||
|
error. And callbacks only get invoked by iterating/running the
|
||||||
|
mainloop/maincontext. This means, if you have a short-running
|
||||||
|
application (e.g. not a GUI) and a reasonable small number of NMClient
|
||||||
|
instances, then you don't need to care. Otherwise, you unfortunately
|
||||||
|
need to make sure that the GMainContext is still iterated just long
|
||||||
|
enough, for all operations to be cancelled. That's slightly cumbersome,
|
||||||
|
and you can use nm_client_get_context_busy_watcher() to find that out.
|
||||||
|
|
||||||
|
Btw, what you also cannot do, is having a NMClient instance alive and
|
||||||
|
just not iterating the GMainContext anymore. NMClient will subscribe to
|
||||||
|
D-Bus events, and those come (because GDBus has a separate worker
|
||||||
|
thread) and will be enqueued in the GMainContext. This applies to all
|
||||||
|
applications that register DBus signals via GDBus: you must iterate the
|
||||||
|
context enough, so that those events get eventually processed. I think
|
||||||
|
this does not apply to you here, but it would apply, if you try to keep
|
||||||
|
the nmclient instance alive and reuse later.
|
||||||
|
|
||||||
|
</snip>
|
||||||
|
|
||||||
|
Reference:https://github.com/rhinstaller/anaconda/commit/3972b5dadcadd355d2ff25eae601bc35c336c45a
|
||||||
|
Conflict:NA
|
||||||
|
---
|
||||||
|
pyanaconda/core/glib.py | 109 +++++++++++-
|
||||||
|
pyanaconda/modules/network/initialization.py | 56 +++---
|
||||||
|
pyanaconda/modules/network/installation.py | 19 +-
|
||||||
|
pyanaconda/modules/network/network.py | 26 +--
|
||||||
|
pyanaconda/modules/network/nm_client.py | 167 +++++++++++-------
|
||||||
|
5 files changed, 254 insertions(+), 123 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/core/glib.py b/pyanaconda/core/glib.py
|
||||||
|
index 03c598db43..32925384bb 100644
|
||||||
|
--- a/pyanaconda/core/glib.py
|
||||||
|
+++ b/pyanaconda/core/glib.py
|
||||||
|
@@ -24,34 +24,42 @@
|
||||||
|
|
||||||
|
import gi
|
||||||
|
gi.require_version("GLib", "2.0")
|
||||||
|
+gi.require_version("Gio", "2.0")
|
||||||
|
|
||||||
|
from gi.repository.GLib import markup_escape_text, format_size_full, \
|
||||||
|
timeout_add_seconds, timeout_add, idle_add, \
|
||||||
|
io_add_watch, child_watch_add, \
|
||||||
|
- source_remove, \
|
||||||
|
+ source_remove, timeout_source_new, \
|
||||||
|
spawn_close_pid, spawn_async_with_pipes, \
|
||||||
|
MainLoop, MainContext, \
|
||||||
|
GError, Variant, VariantType, Bytes, \
|
||||||
|
IOCondition, IOChannel, SpawnFlags, \
|
||||||
|
MAXUINT
|
||||||
|
+from gi.repository.Gio import Cancellable
|
||||||
|
+
|
||||||
|
+from pyanaconda.anaconda_loggers import get_module_logger
|
||||||
|
+log = get_module_logger(__name__)
|
||||||
|
+
|
||||||
|
|
||||||
|
__all__ = ["create_main_loop", "create_new_context",
|
||||||
|
"markup_escape_text", "format_size_full",
|
||||||
|
"timeout_add_seconds", "timeout_add", "idle_add",
|
||||||
|
"io_add_watch", "child_watch_add",
|
||||||
|
- "source_remove",
|
||||||
|
+ "source_remove", "timeout_source_new",
|
||||||
|
"spawn_close_pid", "spawn_async_with_pipes",
|
||||||
|
"GError", "Variant", "VariantType", "Bytes",
|
||||||
|
"IOCondition", "IOChannel", "SpawnFlags",
|
||||||
|
- "MAXUINT"]
|
||||||
|
+ "MAXUINT", "Cancellable"]
|
||||||
|
|
||||||
|
|
||||||
|
-def create_main_loop():
|
||||||
|
+def create_main_loop(main_context=None):
|
||||||
|
"""Create GLib main loop.
|
||||||
|
|
||||||
|
+ :param main_context: main context to be used for the loop
|
||||||
|
+ :type main_context: GLib.MainContext
|
||||||
|
:returns: GLib.MainLoop instance.
|
||||||
|
"""
|
||||||
|
- return MainLoop()
|
||||||
|
+ return MainLoop(main_context)
|
||||||
|
|
||||||
|
|
||||||
|
def create_new_context():
|
||||||
|
@@ -59,3 +67,94 @@ def create_new_context():
|
||||||
|
|
||||||
|
:returns: GLib.MainContext."""
|
||||||
|
return MainContext.new()
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+class GLibCallResult():
|
||||||
|
+ """Result of GLib async finish callback."""
|
||||||
|
+ def __init__(self):
|
||||||
|
+ self.received_data = None
|
||||||
|
+ self.error_message = ""
|
||||||
|
+ self.timeout = False
|
||||||
|
+
|
||||||
|
+ @property
|
||||||
|
+ def succeeded(self):
|
||||||
|
+ """The async call has succeeded."""
|
||||||
|
+ return not self.failed
|
||||||
|
+
|
||||||
|
+ @property
|
||||||
|
+ def failed(self):
|
||||||
|
+ """The async call has failed."""
|
||||||
|
+ return bool(self.error_message) or self.timeout
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def sync_call_glib(context, async_call, async_call_finish, timeout, *call_args):
|
||||||
|
+ """Call GLib asynchronous method synchronously with timeout.
|
||||||
|
+
|
||||||
|
+ :param context: context for the new loop in which the method will be called
|
||||||
|
+ :type context: GMainContext
|
||||||
|
+ :param async_call: asynchronous GLib method to be called
|
||||||
|
+ :type async_call: GLib method
|
||||||
|
+ :param async_call_finish: finish method of the asynchronous call
|
||||||
|
+ :type async_call_finish: GLib method
|
||||||
|
+ :param timeout: timeout for the loop in seconds (0 == no timeout)
|
||||||
|
+ :type timeout: int
|
||||||
|
+
|
||||||
|
+ *call_args should hold all positional arguments preceding the cancellable argument
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ info = async_call.get_symbol()
|
||||||
|
+ result = GLibCallResult()
|
||||||
|
+
|
||||||
|
+ loop = create_main_loop(context)
|
||||||
|
+ callbacks = [loop.quit]
|
||||||
|
+
|
||||||
|
+ def _stop_loop():
|
||||||
|
+ log.debug("sync_call_glib[%s]: quit", info)
|
||||||
|
+ while callbacks:
|
||||||
|
+ callback = callbacks.pop()
|
||||||
|
+ callback()
|
||||||
|
+
|
||||||
|
+ def _cancellable_cb():
|
||||||
|
+ log.debug("sync_call_glib[%s]: cancelled", info)
|
||||||
|
+
|
||||||
|
+ cancellable = Cancellable()
|
||||||
|
+ cancellable_id = cancellable.connect(_cancellable_cb)
|
||||||
|
+ callbacks.append(lambda: cancellable.disconnect(cancellable_id))
|
||||||
|
+
|
||||||
|
+ def _timeout_cb(user_data):
|
||||||
|
+ log.debug("sync_call_glib[%s]: timeout", info)
|
||||||
|
+ result.timeout = True
|
||||||
|
+ cancellable.cancel()
|
||||||
|
+ return False
|
||||||
|
+
|
||||||
|
+ timeout_source = timeout_source_new(int(timeout * 1000))
|
||||||
|
+ timeout_source.set_callback(_timeout_cb)
|
||||||
|
+ timeout_source.attach(context)
|
||||||
|
+ callbacks.append(timeout_source.destroy)
|
||||||
|
+
|
||||||
|
+ def _finish_cb(source_object, async_result):
|
||||||
|
+ log.debug("sync_call_glib[%s]: call %s",
|
||||||
|
+ info,
|
||||||
|
+ async_call_finish.get_symbol())
|
||||||
|
+ try:
|
||||||
|
+ result.received_data = async_call_finish(async_result)
|
||||||
|
+ except Exception as e: # pylint: disable=broad-except
|
||||||
|
+ result.error_message = str(e)
|
||||||
|
+ finally:
|
||||||
|
+ _stop_loop()
|
||||||
|
+
|
||||||
|
+ context.push_thread_default()
|
||||||
|
+
|
||||||
|
+ log.debug("sync_call_glib[%s]: call", info)
|
||||||
|
+ try:
|
||||||
|
+ async_call(
|
||||||
|
+ *call_args,
|
||||||
|
+ cancellable=cancellable,
|
||||||
|
+ callback=_finish_cb
|
||||||
|
+ )
|
||||||
|
+ loop.run()
|
||||||
|
+ finally:
|
||||||
|
+ _stop_loop()
|
||||||
|
+ context.pop_thread_default()
|
||||||
|
+
|
||||||
|
+ return result
|
||||||
|
diff --git a/pyanaconda/modules/network/initialization.py b/pyanaconda/modules/network/initialization.py
|
||||||
|
index c7f0ba4cf8..bf1ffd12af 100644
|
||||||
|
--- a/pyanaconda/modules/network/initialization.py
|
||||||
|
+++ b/pyanaconda/modules/network/initialization.py
|
||||||
|
@@ -25,7 +25,7 @@ from pyanaconda.modules.network.network_interface import NetworkInitializationTa
|
||||||
|
from pyanaconda.modules.network.nm_client import get_device_name_from_network_data, \
|
||||||
|
update_connection_from_ksdata, add_connection_from_ksdata, bound_hwaddr_of_device, \
|
||||||
|
update_connection_values, commit_changes_with_autoconnection_blocked, \
|
||||||
|
- get_config_file_connection_of_device, clone_connection_sync
|
||||||
|
+ get_config_file_connection_of_device, clone_connection_sync, nm_client_in_thread
|
||||||
|
from pyanaconda.modules.network.device_configuration import supported_wired_device_types, \
|
||||||
|
virtual_device_types
|
||||||
|
from pyanaconda.modules.network.utils import guard_by_system_configuration
|
||||||
|
@@ -40,11 +40,9 @@ from gi.repository import NM
|
||||||
|
class ApplyKickstartTask(Task):
|
||||||
|
"""Task for application of kickstart network configuration."""
|
||||||
|
|
||||||
|
- def __init__(self, nm_client, network_data, supported_devices, bootif, ifname_option_values):
|
||||||
|
+ def __init__(self, network_data, supported_devices, bootif, ifname_option_values):
|
||||||
|
"""Create a new task.
|
||||||
|
|
||||||
|
- :param nm_client: NetworkManager client used as configuration backend
|
||||||
|
- :type nm_client: NM.Client
|
||||||
|
:param network_data: kickstart network data to be applied
|
||||||
|
:type: list(NetworkData)
|
||||||
|
:param supported_devices: list of names of supported network devices
|
||||||
|
@@ -55,7 +53,6 @@ class ApplyKickstartTask(Task):
|
||||||
|
:type ifname_option_values: list(str)
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
- self._nm_client = nm_client
|
||||||
|
self._network_data = network_data
|
||||||
|
self._supported_devices = supported_devices
|
||||||
|
self._bootif = bootif
|
||||||
|
@@ -76,13 +73,17 @@ class ApplyKickstartTask(Task):
|
||||||
|
:returns: names of devices to which kickstart was applied
|
||||||
|
:rtype: list(str)
|
||||||
|
"""
|
||||||
|
+ with nm_client_in_thread() as nm_client:
|
||||||
|
+ return self._run(nm_client)
|
||||||
|
+
|
||||||
|
+ def _run(self, nm_client):
|
||||||
|
applied_devices = []
|
||||||
|
|
||||||
|
if not self._network_data:
|
||||||
|
log.debug("%s: No kickstart data.", self.name)
|
||||||
|
return applied_devices
|
||||||
|
|
||||||
|
- if not self._nm_client:
|
||||||
|
+ if not nm_client:
|
||||||
|
log.debug("%s: No NetworkManager available.", self.name)
|
||||||
|
return applied_devices
|
||||||
|
|
||||||
|
@@ -92,7 +93,7 @@ class ApplyKickstartTask(Task):
|
||||||
|
log.info("%s: Wireless devices configuration is not supported.", self.name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
- device_name = get_device_name_from_network_data(self._nm_client,
|
||||||
|
+ device_name = get_device_name_from_network_data(nm_client,
|
||||||
|
network_data,
|
||||||
|
self._supported_devices,
|
||||||
|
self._bootif)
|
||||||
|
@@ -102,28 +103,28 @@ class ApplyKickstartTask(Task):
|
||||||
|
|
||||||
|
applied_devices.append(device_name)
|
||||||
|
|
||||||
|
- connection = self._find_initramfs_connection_of_iface(device_name)
|
||||||
|
+ connection = self._find_initramfs_connection_of_iface(nm_client, device_name)
|
||||||
|
|
||||||
|
if connection:
|
||||||
|
# if the device was already configured in initramfs update the settings
|
||||||
|
log.debug("%s: updating connection %s of device %s",
|
||||||
|
self.name, connection.get_uuid(), device_name)
|
||||||
|
update_connection_from_ksdata(
|
||||||
|
- self._nm_client,
|
||||||
|
+ nm_client,
|
||||||
|
connection,
|
||||||
|
network_data,
|
||||||
|
device_name,
|
||||||
|
ifname_option_values=self._ifname_option_values
|
||||||
|
)
|
||||||
|
if network_data.activate:
|
||||||
|
- device = self._nm_client.get_device_by_iface(device_name)
|
||||||
|
- self._nm_client.activate_connection_async(connection, device, None, None)
|
||||||
|
+ device = nm_client.get_device_by_iface(device_name)
|
||||||
|
+ nm_client.activate_connection_async(connection, device, None, None)
|
||||||
|
log.debug("%s: activating updated connection %s with device %s",
|
||||||
|
self.name, connection.get_uuid(), device_name)
|
||||||
|
else:
|
||||||
|
log.debug("%s: adding connection for %s", self.name, device_name)
|
||||||
|
add_connection_from_ksdata(
|
||||||
|
- self._nm_client,
|
||||||
|
+ nm_client,
|
||||||
|
network_data,
|
||||||
|
device_name,
|
||||||
|
activate=network_data.activate,
|
||||||
|
@@ -132,8 +133,8 @@ class ApplyKickstartTask(Task):
|
||||||
|
|
||||||
|
return applied_devices
|
||||||
|
|
||||||
|
- def _find_initramfs_connection_of_iface(self, iface):
|
||||||
|
- device = self._nm_client.get_device_by_iface(iface)
|
||||||
|
+ def _find_initramfs_connection_of_iface(self, nm_client, iface):
|
||||||
|
+ device = nm_client.get_device_by_iface(iface)
|
||||||
|
if device:
|
||||||
|
cons = device.get_available_connections()
|
||||||
|
for con in cons:
|
||||||
|
@@ -145,18 +146,15 @@ class ApplyKickstartTask(Task):
|
||||||
|
class DumpMissingConfigFilesTask(Task):
|
||||||
|
"""Task for dumping of missing config files."""
|
||||||
|
|
||||||
|
- def __init__(self, nm_client, default_network_data, ifname_option_values):
|
||||||
|
+ def __init__(self, default_network_data, ifname_option_values):
|
||||||
|
"""Create a new task.
|
||||||
|
|
||||||
|
- :param nm_client: NetworkManager client used as configuration backend
|
||||||
|
- :type nm_client: NM.Client
|
||||||
|
:param default_network_data: kickstart network data of default device configuration
|
||||||
|
:type default_network_data: NetworkData
|
||||||
|
:param ifname_option_values: list of ifname boot option values
|
||||||
|
:type ifname_option_values: list(str)
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
- self._nm_client = nm_client
|
||||||
|
self._default_network_data = default_network_data
|
||||||
|
self._ifname_option_values = ifname_option_values
|
||||||
|
|
||||||
|
@@ -186,7 +184,7 @@ class DumpMissingConfigFilesTask(Task):
|
||||||
|
return con
|
||||||
|
return None
|
||||||
|
|
||||||
|
- def _update_connection(self, con, iface):
|
||||||
|
+ def _update_connection(self, nm_client, con, iface):
|
||||||
|
log.debug("%s: updating id and binding (interface-name) of connection %s for %s",
|
||||||
|
self.name, con.get_uuid(), iface)
|
||||||
|
s_con = con.get_setting_connection()
|
||||||
|
@@ -196,7 +194,7 @@ class DumpMissingConfigFilesTask(Task):
|
||||||
|
if s_wired:
|
||||||
|
# By default connections are bound to interface name
|
||||||
|
s_wired.set_property(NM.SETTING_WIRED_MAC_ADDRESS, None)
|
||||||
|
- bound_mac = bound_hwaddr_of_device(self._nm_client, iface, self._ifname_option_values)
|
||||||
|
+ bound_mac = bound_hwaddr_of_device(nm_client, iface, self._ifname_option_values)
|
||||||
|
if bound_mac:
|
||||||
|
s_wired.set_property(NM.SETTING_WIRED_MAC_ADDRESS, bound_mac)
|
||||||
|
log.debug("%s: iface %s bound to mac address %s by ifname boot option",
|
||||||
|
@@ -216,19 +214,23 @@ class DumpMissingConfigFilesTask(Task):
|
||||||
|
:returns: names of devices for which config file was created
|
||||||
|
:rtype: list(str)
|
||||||
|
"""
|
||||||
|
+ with nm_client_in_thread() as nm_client:
|
||||||
|
+ return self._run(nm_client)
|
||||||
|
+
|
||||||
|
+ def _run(self, nm_client):
|
||||||
|
new_configs = []
|
||||||
|
|
||||||
|
- if not self._nm_client:
|
||||||
|
+ if not nm_client:
|
||||||
|
log.debug("%s: No NetworkManager available.", self.name)
|
||||||
|
return new_configs
|
||||||
|
|
||||||
|
dumped_device_types = supported_wired_device_types + virtual_device_types
|
||||||
|
- for device in self._nm_client.get_devices():
|
||||||
|
+ for device in nm_client.get_devices():
|
||||||
|
if device.get_device_type() not in dumped_device_types:
|
||||||
|
continue
|
||||||
|
|
||||||
|
iface = device.get_iface()
|
||||||
|
- if get_config_file_connection_of_device(self._nm_client, iface):
|
||||||
|
+ if get_config_file_connection_of_device(nm_client, iface):
|
||||||
|
continue
|
||||||
|
|
||||||
|
cons = device.get_available_connections()
|
||||||
|
@@ -259,10 +261,10 @@ class DumpMissingConfigFilesTask(Task):
|
||||||
|
# Try to clone the persistent connection for the device
|
||||||
|
# from the connection which should be a generic (not bound
|
||||||
|
# to iface) connection created by NM in initramfs
|
||||||
|
- con = clone_connection_sync(self._nm_client, cons[0], con_id=iface)
|
||||||
|
+ con = clone_connection_sync(nm_client, cons[0], con_id=iface)
|
||||||
|
|
||||||
|
if con:
|
||||||
|
- self._update_connection(con, iface)
|
||||||
|
+ self._update_connection(nm_client, con, iface)
|
||||||
|
# Update some values of connection generated in initramfs so it
|
||||||
|
# can be used as persistent configuration.
|
||||||
|
if has_initramfs_con:
|
||||||
|
@@ -285,7 +287,7 @@ class DumpMissingConfigFilesTask(Task):
|
||||||
|
)
|
||||||
|
log.debug("%s: dumping connection %s to config file for %s",
|
||||||
|
self.name, con.get_uuid(), iface)
|
||||||
|
- commit_changes_with_autoconnection_blocked(con)
|
||||||
|
+ commit_changes_with_autoconnection_blocked(con, nm_client)
|
||||||
|
else:
|
||||||
|
log.debug("%s: none of the connections can be dumped as persistent",
|
||||||
|
self.name)
|
||||||
|
@@ -298,7 +300,7 @@ class DumpMissingConfigFilesTask(Task):
|
||||||
|
if has_initramfs_con:
|
||||||
|
network_data.onboot = True
|
||||||
|
add_connection_from_ksdata(
|
||||||
|
- self._nm_client,
|
||||||
|
+ nm_client,
|
||||||
|
network_data,
|
||||||
|
iface,
|
||||||
|
activate=False,
|
||||||
|
diff --git a/pyanaconda/modules/network/installation.py b/pyanaconda/modules/network/installation.py
|
||||||
|
index 3ac65e0df0..d91eb51ae7 100644
|
||||||
|
--- a/pyanaconda/modules/network/installation.py
|
||||||
|
+++ b/pyanaconda/modules/network/installation.py
|
||||||
|
@@ -23,7 +23,7 @@ from pyanaconda.modules.common.errors.installation import NetworkInstallationErr
|
||||||
|
from pyanaconda.modules.common.task import Task
|
||||||
|
from pyanaconda.anaconda_loggers import get_module_logger
|
||||||
|
from pyanaconda.modules.network.nm_client import update_connection_values, \
|
||||||
|
- commit_changes_with_autoconnection_blocked
|
||||||
|
+ commit_changes_with_autoconnection_blocked, nm_client_in_thread
|
||||||
|
from pyanaconda.modules.network.utils import guard_by_system_configuration
|
||||||
|
from pyanaconda.modules.network.nm_client import get_config_file_connection_of_device
|
||||||
|
from pyanaconda.modules.network.config_file import IFCFG_DIR, KEYFILE_DIR
|
||||||
|
@@ -281,16 +281,13 @@ Name={}
|
||||||
|
class ConfigureActivationOnBootTask(Task):
|
||||||
|
"""Task for configuration of automatic activation of devices on boot"""
|
||||||
|
|
||||||
|
- def __init__(self, nm_client, onboot_ifaces):
|
||||||
|
+ def __init__(self, onboot_ifaces):
|
||||||
|
"""Create a new task.
|
||||||
|
|
||||||
|
- :param nm_client: NetworkManager client used as configuration backend
|
||||||
|
- :type nm_client: NM.Client
|
||||||
|
:param onboot_ifaces: interfaces that should be autoactivated on boot
|
||||||
|
:type onboot_ifaces: list(str)
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
- self._nm_client = nm_client
|
||||||
|
self._onboot_ifaces = onboot_ifaces
|
||||||
|
|
||||||
|
@property
|
||||||
|
@@ -299,18 +296,22 @@ class ConfigureActivationOnBootTask(Task):
|
||||||
|
|
||||||
|
@guard_by_system_configuration(return_value=None)
|
||||||
|
def run(self):
|
||||||
|
- if not self._nm_client:
|
||||||
|
+ with nm_client_in_thread() as nm_client:
|
||||||
|
+ return self._run(nm_client)
|
||||||
|
+
|
||||||
|
+ def _run(self, nm_client):
|
||||||
|
+ if not nm_client:
|
||||||
|
log.debug("%s: No NetworkManager available.", self.name)
|
||||||
|
return None
|
||||||
|
|
||||||
|
for iface in self._onboot_ifaces:
|
||||||
|
- con_uuid = get_config_file_connection_of_device(self._nm_client, iface)
|
||||||
|
+ con_uuid = get_config_file_connection_of_device(nm_client, iface)
|
||||||
|
if con_uuid:
|
||||||
|
- con = self._nm_client.get_connection_by_uuid(con_uuid)
|
||||||
|
+ con = nm_client.get_connection_by_uuid(con_uuid)
|
||||||
|
update_connection_values(
|
||||||
|
con,
|
||||||
|
[("connection", NM.SETTING_CONNECTION_AUTOCONNECT, True)]
|
||||||
|
)
|
||||||
|
- commit_changes_with_autoconnection_blocked(con)
|
||||||
|
+ commit_changes_with_autoconnection_blocked(con, nm_client)
|
||||||
|
else:
|
||||||
|
log.warning("Configure ONBOOT: can't find config for %s", iface)
|
||||||
|
diff --git a/pyanaconda/modules/network/network.py b/pyanaconda/modules/network/network.py
|
||||||
|
index 445c9d8b46..a905ee31d6 100644
|
||||||
|
--- a/pyanaconda/modules/network/network.py
|
||||||
|
+++ b/pyanaconda/modules/network/network.py
|
||||||
|
@@ -23,7 +23,7 @@ from pyanaconda.core.async_utils import run_in_loop
|
||||||
|
from pyanaconda.core.configuration.anaconda import conf
|
||||||
|
from pyanaconda.core.configuration.network import NetworkOnBoot
|
||||||
|
from pyanaconda.core.kernel import kernel_arguments
|
||||||
|
-from pyanaconda.core.dbus import DBus, SystemBus
|
||||||
|
+from pyanaconda.core.dbus import DBus
|
||||||
|
from pyanaconda.core.signal import Signal
|
||||||
|
from pyanaconda.modules.common.base import KickstartService
|
||||||
|
from pyanaconda.modules.common.containers import TaskContainer
|
||||||
|
@@ -37,7 +37,7 @@ from pyanaconda.modules.network.firewall import FirewallModule
|
||||||
|
from pyanaconda.modules.network.device_configuration import DeviceConfigurations, \
|
||||||
|
supported_device_types, supported_wired_device_types
|
||||||
|
from pyanaconda.modules.network.nm_client import devices_ignore_ipv6, get_connections_dump, \
|
||||||
|
- get_dracut_arguments_from_connection, get_kickstart_network_data
|
||||||
|
+ get_dracut_arguments_from_connection, get_kickstart_network_data, get_new_nm_client
|
||||||
|
from pyanaconda.modules.network.config_file import get_config_files_content, \
|
||||||
|
is_config_file_for_system
|
||||||
|
from pyanaconda.modules.network.installation import NetworkInstallationTask, \
|
||||||
|
@@ -70,17 +70,12 @@ class NetworkService(KickstartService):
|
||||||
|
self._hostname_service_proxy = self._get_hostname_proxy()
|
||||||
|
|
||||||
|
self.connected_changed = Signal()
|
||||||
|
- self.nm_client = None
|
||||||
|
# TODO fallback solution - use Gio/GNetworkMonitor ?
|
||||||
|
- if SystemBus.check_connection():
|
||||||
|
- nm_client = NM.Client.new(None)
|
||||||
|
- if nm_client.get_nm_running():
|
||||||
|
- self.nm_client = nm_client
|
||||||
|
- self.nm_client.connect("notify::%s" % NM.CLIENT_STATE, self._nm_state_changed)
|
||||||
|
- initial_state = self.nm_client.get_state()
|
||||||
|
- self.set_connected(self._nm_state_connected(initial_state))
|
||||||
|
- else:
|
||||||
|
- log.debug("NetworkManager is not running.")
|
||||||
|
+ self.nm_client = get_new_nm_client()
|
||||||
|
+ if self.nm_client:
|
||||||
|
+ self.nm_client.connect("notify::%s" % NM.CLIENT_STATE, self._nm_state_changed)
|
||||||
|
+ initial_state = self.nm_client.get_state()
|
||||||
|
+ self.set_connected(self._nm_state_connected(initial_state))
|
||||||
|
|
||||||
|
self._original_network_data = []
|
||||||
|
self._device_configurations = None
|
||||||
|
@@ -393,7 +388,6 @@ class NetworkService(KickstartService):
|
||||||
|
all_onboot_ifaces = list(set(onboot_ifaces + onboot_ifaces_by_policy))
|
||||||
|
|
||||||
|
task = ConfigureActivationOnBootTask(
|
||||||
|
- self.nm_client,
|
||||||
|
all_onboot_ifaces
|
||||||
|
)
|
||||||
|
task.succeeded_signal.connect(lambda: self.log_task_result(task))
|
||||||
|
@@ -616,8 +610,7 @@ class NetworkService(KickstartService):
|
||||||
|
:returns: a task applying the kickstart
|
||||||
|
"""
|
||||||
|
supported_devices = [dev_info.device_name for dev_info in self.get_supported_devices()]
|
||||||
|
- task = ApplyKickstartTask(self.nm_client,
|
||||||
|
- self._original_network_data,
|
||||||
|
+ task = ApplyKickstartTask(self._original_network_data,
|
||||||
|
supported_devices,
|
||||||
|
self.bootif,
|
||||||
|
self.ifname_option_values)
|
||||||
|
@@ -645,8 +638,7 @@ class NetworkService(KickstartService):
|
||||||
|
"""
|
||||||
|
data = self.get_kickstart_handler()
|
||||||
|
default_network_data = data.NetworkData(onboot=False, ipv6="auto")
|
||||||
|
- task = DumpMissingConfigFilesTask(self.nm_client,
|
||||||
|
- default_network_data,
|
||||||
|
+ task = DumpMissingConfigFilesTask(default_network_data,
|
||||||
|
self.ifname_option_values)
|
||||||
|
task.succeeded_signal.connect(lambda: self.log_task_result(task, check_result=True))
|
||||||
|
return task
|
||||||
|
diff --git a/pyanaconda/modules/network/nm_client.py b/pyanaconda/modules/network/nm_client.py
|
||||||
|
index 3cc28ec48e..421ef1e0d9 100644
|
||||||
|
--- a/pyanaconda/modules/network/nm_client.py
|
||||||
|
+++ b/pyanaconda/modules/network/nm_client.py
|
||||||
|
@@ -21,18 +21,20 @@
|
||||||
|
import gi
|
||||||
|
gi.require_version("NM", "1.0")
|
||||||
|
from gi.repository import NM
|
||||||
|
+from contextlib import contextmanager
|
||||||
|
|
||||||
|
import socket
|
||||||
|
-from queue import Queue, Empty
|
||||||
|
from pykickstart.constants import BIND_TO_MAC
|
||||||
|
+from pyanaconda.core.glib import create_new_context, GError, sync_call_glib
|
||||||
|
from pyanaconda.modules.network.constants import NM_CONNECTION_UUID_LENGTH, \
|
||||||
|
- CONNECTION_ACTIVATION_TIMEOUT, NM_CONNECTION_TYPE_WIFI, NM_CONNECTION_TYPE_ETHERNET, \
|
||||||
|
+ CONNECTION_ADDING_TIMEOUT, NM_CONNECTION_TYPE_WIFI, NM_CONNECTION_TYPE_ETHERNET, \
|
||||||
|
NM_CONNECTION_TYPE_VLAN, NM_CONNECTION_TYPE_BOND, NM_CONNECTION_TYPE_TEAM, \
|
||||||
|
- NM_CONNECTION_TYPE_BRIDGE, NM_CONNECTION_TYPE_INFINIBAND, CONNECTION_ADDING_TIMEOUT
|
||||||
|
+ NM_CONNECTION_TYPE_BRIDGE, NM_CONNECTION_TYPE_INFINIBAND
|
||||||
|
from pyanaconda.modules.network.kickstart import default_ks_vlan_interface_name
|
||||||
|
from pyanaconda.modules.network.utils import is_s390, get_s390_settings, netmask2prefix, \
|
||||||
|
prefix2netmask
|
||||||
|
from pyanaconda.modules.network.config_file import is_config_file_for_system
|
||||||
|
+from pyanaconda.core.dbus import SystemBus
|
||||||
|
|
||||||
|
from pyanaconda.anaconda_loggers import get_module_logger
|
||||||
|
log = get_module_logger(__name__)
|
||||||
|
@@ -51,6 +53,51 @@ NM_BRIDGE_DUMPED_SETTINGS_DEFAULTS = {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+@contextmanager
|
||||||
|
+def nm_client_in_thread():
|
||||||
|
+ """Create NM Client with new GMainContext to be run in thread.
|
||||||
|
+
|
||||||
|
+ Expected to be used only in installer environment for a few
|
||||||
|
+ one-shot isolated network configuration tasks.
|
||||||
|
+ Destroying of the created NM Client instance and release of
|
||||||
|
+ related resources is not implemented.
|
||||||
|
+
|
||||||
|
+ For more information see NetworkManager example examples/python/gi/gmaincontext.py
|
||||||
|
+ """
|
||||||
|
+ mainctx = create_new_context()
|
||||||
|
+ mainctx.push_thread_default()
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ yield get_new_nm_client()
|
||||||
|
+ finally:
|
||||||
|
+ mainctx.pop_thread_default()
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def get_new_nm_client():
|
||||||
|
+ """Get new instance of NMClient.
|
||||||
|
+
|
||||||
|
+ :returns: an instance of NetworkManager NMClient or None if system bus
|
||||||
|
+ is not available or NM is not running
|
||||||
|
+ :rtype: NM.NMClient
|
||||||
|
+ """
|
||||||
|
+ if not SystemBus.check_connection():
|
||||||
|
+ log.debug("get new NM Client failed: SystemBus connection check failed.")
|
||||||
|
+ return None
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ nm_client = NM.Client.new(None)
|
||||||
|
+ except GError as e:
|
||||||
|
+ log.debug("get new NM Client constructor failed: %s", e)
|
||||||
|
+ return None
|
||||||
|
+
|
||||||
|
+ if not nm_client.get_nm_running():
|
||||||
|
+ log.debug("get new NM Client failed: NetworkManager is not running.")
|
||||||
|
+ return None
|
||||||
|
+
|
||||||
|
+ log.debug("get new NM Client succeeded.")
|
||||||
|
+ return nm_client
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def get_iface_from_connection(nm_client, uuid):
|
||||||
|
"""Get the name of device that would be used for the connection.
|
||||||
|
|
||||||
|
@@ -268,7 +315,7 @@ def _add_existing_virtual_device_to_bridge(nm_client, device_name, bridge_spec):
|
||||||
|
bridge_spec),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
- commit_changes_with_autoconnection_blocked(port_connection)
|
||||||
|
+ commit_changes_with_autoconnection_blocked(port_connection, nm_client)
|
||||||
|
return port_connection.get_uuid()
|
||||||
|
|
||||||
|
|
||||||
|
@@ -532,7 +579,7 @@ def add_connection_from_ksdata(nm_client, network_data, device_name, activate=Fa
|
||||||
|
connection.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS))
|
||||||
|
added_connection = add_connection_sync(
|
||||||
|
nm_client,
|
||||||
|
- connection,
|
||||||
|
+ connection
|
||||||
|
)
|
||||||
|
|
||||||
|
if not added_connection:
|
||||||
|
@@ -557,37 +604,39 @@ def add_connection_from_ksdata(nm_client, network_data, device_name, activate=Fa
|
||||||
|
def add_connection_sync(nm_client, connection):
|
||||||
|
"""Add a connection synchronously and optionally activate asynchronously.
|
||||||
|
|
||||||
|
+ Synchronous run is implemented by running a blocking GMainLoop with
|
||||||
|
+ GMainContext belonging to the nm_client created for the calling Task.
|
||||||
|
+
|
||||||
|
+ :param nm_client: NetoworkManager client
|
||||||
|
+ :type nm_client: NM.NMClient
|
||||||
|
:param connection: connection to be added
|
||||||
|
:type connection: NM.SimpleConnection
|
||||||
|
:return: added connection or None on timeout
|
||||||
|
:rtype: NM.RemoteConnection
|
||||||
|
"""
|
||||||
|
- sync_queue = Queue()
|
||||||
|
-
|
||||||
|
- def finish_callback(nm_client, result, sync_queue):
|
||||||
|
- con, result = nm_client.add_connection2_finish(result)
|
||||||
|
- log.debug("connection %s added:\n%s", con.get_uuid(),
|
||||||
|
- con.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS))
|
||||||
|
- sync_queue.put(con)
|
||||||
|
-
|
||||||
|
- nm_client.add_connection2(
|
||||||
|
+ result = sync_call_glib(
|
||||||
|
+ nm_client.get_main_context(),
|
||||||
|
+ nm_client.add_connection2,
|
||||||
|
+ nm_client.add_connection2_finish,
|
||||||
|
+ CONNECTION_ADDING_TIMEOUT,
|
||||||
|
connection.to_dbus(NM.ConnectionSerializationFlags.ALL),
|
||||||
|
(NM.SettingsAddConnection2Flags.TO_DISK |
|
||||||
|
NM.SettingsAddConnection2Flags.BLOCK_AUTOCONNECT),
|
||||||
|
None,
|
||||||
|
- False,
|
||||||
|
- None,
|
||||||
|
- finish_callback,
|
||||||
|
- sync_queue
|
||||||
|
+ False
|
||||||
|
)
|
||||||
|
|
||||||
|
- try:
|
||||||
|
- ret = sync_queue.get(timeout=CONNECTION_ADDING_TIMEOUT)
|
||||||
|
- except Empty:
|
||||||
|
- log.error("Adding of connection %s timed out.", connection.get_uuid())
|
||||||
|
- ret = None
|
||||||
|
+ if result.failed:
|
||||||
|
+ log.error("adding of a connection %s failed: %s",
|
||||||
|
+ connection.get_uuid(),
|
||||||
|
+ result.error_message)
|
||||||
|
+ return None
|
||||||
|
+
|
||||||
|
+ con, _res = result.received_data
|
||||||
|
+ log.debug("connection %s added:\n%s", connection.get_uuid(),
|
||||||
|
+ connection.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS))
|
||||||
|
|
||||||
|
- return ret
|
||||||
|
+ return con
|
||||||
|
|
||||||
|
|
||||||
|
def create_port_connection(port_type, port_idx, port, controller, autoconnect, settings=None):
|
||||||
|
@@ -713,7 +762,7 @@ def update_connection_from_ksdata(nm_client, connection, network_data, device_na
|
||||||
|
else:
|
||||||
|
bind_connection(nm_client, connection, network_data.bindto, device_name)
|
||||||
|
|
||||||
|
- commit_changes_with_autoconnection_blocked(connection)
|
||||||
|
+ commit_changes_with_autoconnection_blocked(connection, nm_client)
|
||||||
|
|
||||||
|
log.debug("updated connection %s:\n%s", connection.get_uuid(),
|
||||||
|
connection.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS))
|
||||||
|
@@ -1013,42 +1062,47 @@ def get_connections_dump(nm_client):
|
||||||
|
return "\n".join(con_dumps)
|
||||||
|
|
||||||
|
|
||||||
|
-def commit_changes_with_autoconnection_blocked(connection, save_to_disk=True):
|
||||||
|
+def commit_changes_with_autoconnection_blocked(connection, nm_client, save_to_disk=True):
|
||||||
|
"""Implementation of NM CommitChanges() method with blocked autoconnection.
|
||||||
|
|
||||||
|
- Update2() API is used to implement the functionality (called synchronously).
|
||||||
|
-
|
||||||
|
+ Update2() API is used to implement the functionality.
|
||||||
|
Prevents autoactivation of the connection on its update which would happen
|
||||||
|
with CommitChanges if "autoconnect" is set True.
|
||||||
|
|
||||||
|
+ Synchronous run is implemented by running a blocking GMainLoop with
|
||||||
|
+ GMainContext belonging to the nm_client created for the calling Task.
|
||||||
|
+
|
||||||
|
:param connection: NetworkManager connection
|
||||||
|
:type connection: NM.RemoteConnection
|
||||||
|
+ :param nm_client: NetoworkManager client
|
||||||
|
+ :type nm_client: NM.NMClient
|
||||||
|
:param save_to_disk: should the changes be written also to disk?
|
||||||
|
:type save_to_disk: bool
|
||||||
|
:return: on success result of the Update2() call, None of failure
|
||||||
|
:rtype: GVariant of type "a{sv}" or None
|
||||||
|
"""
|
||||||
|
- sync_queue = Queue()
|
||||||
|
-
|
||||||
|
- def finish_callback(connection, result, sync_queue):
|
||||||
|
- ret = connection.update2_finish(result)
|
||||||
|
- sync_queue.put(ret)
|
||||||
|
-
|
||||||
|
flags = NM.SettingsUpdate2Flags.BLOCK_AUTOCONNECT
|
||||||
|
if save_to_disk:
|
||||||
|
flags |= NM.SettingsUpdate2Flags.TO_DISK
|
||||||
|
-
|
||||||
|
con2 = NM.SimpleConnection.new_clone(connection)
|
||||||
|
- connection.update2(
|
||||||
|
+
|
||||||
|
+ result = sync_call_glib(
|
||||||
|
+ nm_client.get_main_context(),
|
||||||
|
+ connection.update2,
|
||||||
|
+ connection.update2_finish,
|
||||||
|
+ CONNECTION_ADDING_TIMEOUT,
|
||||||
|
con2.to_dbus(NM.ConnectionSerializationFlags.ALL),
|
||||||
|
flags,
|
||||||
|
- None,
|
||||||
|
- None,
|
||||||
|
- finish_callback,
|
||||||
|
- sync_queue
|
||||||
|
+ None
|
||||||
|
)
|
||||||
|
|
||||||
|
- return sync_queue.get()
|
||||||
|
+ if result.failed:
|
||||||
|
+ log.error("comitting changes of connection %s failed: %s",
|
||||||
|
+ connection.get_uuid(),
|
||||||
|
+ result.error_message)
|
||||||
|
+ return None
|
||||||
|
+
|
||||||
|
+ return result.received_data
|
||||||
|
|
||||||
|
|
||||||
|
def clone_connection_sync(nm_client, connection, con_id=None, uuid=None):
|
||||||
|
@@ -1063,36 +1117,19 @@ def clone_connection_sync(nm_client, connection, con_id=None, uuid=None):
|
||||||
|
:return: NetworkManager connection or None on timeout
|
||||||
|
:rtype: NM.RemoteConnection
|
||||||
|
"""
|
||||||
|
- sync_queue = Queue()
|
||||||
|
-
|
||||||
|
- def finish_callback(nm_client, result, sync_queue):
|
||||||
|
- con, result = nm_client.add_connection2_finish(result)
|
||||||
|
- log.debug("connection %s cloned:\n%s", con.get_uuid(),
|
||||||
|
- con.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS))
|
||||||
|
- sync_queue.put(con)
|
||||||
|
-
|
||||||
|
cloned_connection = NM.SimpleConnection.new_clone(connection)
|
||||||
|
s_con = cloned_connection.get_setting_connection()
|
||||||
|
s_con.props.uuid = uuid or NM.utils_uuid_generate()
|
||||||
|
s_con.props.id = con_id or "{}-clone".format(connection.get_id())
|
||||||
|
- nm_client.add_connection2(
|
||||||
|
- cloned_connection.to_dbus(NM.ConnectionSerializationFlags.ALL),
|
||||||
|
- (NM.SettingsAddConnection2Flags.TO_DISK |
|
||||||
|
- NM.SettingsAddConnection2Flags.BLOCK_AUTOCONNECT),
|
||||||
|
- None,
|
||||||
|
- False,
|
||||||
|
- None,
|
||||||
|
- finish_callback,
|
||||||
|
- sync_queue
|
||||||
|
- )
|
||||||
|
|
||||||
|
- try:
|
||||||
|
- ret = sync_queue.get(timeout=CONNECTION_ACTIVATION_TIMEOUT)
|
||||||
|
- except Empty:
|
||||||
|
- log.error("Cloning of a connection timed out.")
|
||||||
|
- ret = None
|
||||||
|
+ log.debug("cloning connection %s", connection.get_uuid())
|
||||||
|
+ added_connection = add_connection_sync(nm_client, cloned_connection)
|
||||||
|
|
||||||
|
- return ret
|
||||||
|
+ if added_connection:
|
||||||
|
+ log.debug("connection was cloned into %s", added_connection.get_uuid())
|
||||||
|
+ else:
|
||||||
|
+ log.debug("connection cloning failed")
|
||||||
|
+ return added_connection
|
||||||
|
|
||||||
|
|
||||||
|
def get_dracut_arguments_from_connection(nm_client, connection, iface, target_ip,
|
||||||
|
--
|
||||||
|
2.23.0
|
||||||
@ -11,9 +11,9 @@ diff --git a/pyanaconda/modules/network/initialization.py b/pyanaconda/modules/n
|
|||||||
index c7f0ba4..85a1da7 100644
|
index c7f0ba4..85a1da7 100644
|
||||||
--- a/pyanaconda/modules/network/initialization.py
|
--- a/pyanaconda/modules/network/initialization.py
|
||||||
+++ b/pyanaconda/modules/network/initialization.py
|
+++ b/pyanaconda/modules/network/initialization.py
|
||||||
@@ -135,6 +135,9 @@ class ApplyKickstartTask(Task):
|
@@ -136,6 +136,9 @@ class ApplyKickstartTask(Task):
|
||||||
def _find_initramfs_connection_of_iface(self, iface):
|
def _find_initramfs_connection_of_iface(self, nm_client, iface):
|
||||||
device = self._nm_client.get_device_by_iface(iface)
|
device = nm_client.get_device_by_iface(iface)
|
||||||
if device:
|
if device:
|
||||||
+ active_connection = device.get_active_connection()
|
+ active_connection = device.get_active_connection()
|
||||||
+ if active_connection:
|
+ if active_connection:
|
||||||
|
|||||||
@ -0,0 +1,104 @@
|
|||||||
|
From d5d6b1498db9f9e3378c11421caa523556c04752 Mon Sep 17 00:00:00 2001
|
||||||
|
From: sun_hai_10 <sunhai10@huawei.com>
|
||||||
|
Date: Tue, 28 Mar 2023 14:22:39 +0800
|
||||||
|
Subject: [PATCH] revert Unify GRUB configuration file location across all platforms
|
||||||
|
Reference:https://github.com/rhinstaller/anaconda/commit/15c3b2044367d375db6739e8b8f419ef3e17cae7
|
||||||
|
---
|
||||||
|
pyanaconda/modules/storage/bootloader/efi.py | 38 +------------------
|
||||||
|
.../modules/storage/bootloader/utils.py | 8 +++-
|
||||||
|
2 files changed, 9 insertions(+), 37 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/modules/storage/bootloader/efi.py b/pyanaconda/modules/storage/bootloader/efi.py
|
||||||
|
index 1b47e24..6135699 100644
|
||||||
|
--- a/pyanaconda/modules/storage/bootloader/efi.py
|
||||||
|
+++ b/pyanaconda/modules/storage/bootloader/efi.py
|
||||||
|
@@ -35,11 +35,7 @@ class EFIBase(object):
|
||||||
|
"""A base class for EFI-based boot loaders."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
- def efi_config_dir(self):
|
||||||
|
- return "/boot/" + self._efi_config_dir
|
||||||
|
-
|
||||||
|
- @property
|
||||||
|
- def _efi_config_dir(self):
|
||||||
|
+ def _config_dir(self):
|
||||||
|
return "efi/EFI/{}".format(conf.bootloader.efi_dir)
|
||||||
|
|
||||||
|
def efibootmgr(self, *args, **kwargs):
|
||||||
|
@@ -62,7 +58,7 @@ class EFIBase(object):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def efi_dir_as_efifs_dir(self):
|
||||||
|
- ret = self._efi_config_dir.replace('efi/', '')
|
||||||
|
+ ret = self._config_dir.replace('efi/', '')
|
||||||
|
return "\\" + ret.replace('/', '\\')
|
||||||
|
|
||||||
|
def _add_single_efi_boot_target(self, partition):
|
||||||
|
@@ -164,36 +160,6 @@ class EFIGRUB(EFIBase, GRUB2):
|
||||||
|
return self._packages32 + self._packages_common
|
||||||
|
return self._packages64 + self._packages_common
|
||||||
|
|
||||||
|
- @property
|
||||||
|
- def efi_config_file(self):
|
||||||
|
- """ Full path to EFI configuration file. """
|
||||||
|
- return "%s/%s" % (self.efi_config_dir, self._config_file)
|
||||||
|
-
|
||||||
|
- def write_config(self):
|
||||||
|
- config_path = "%s%s" % (conf.target.system_root, self.efi_config_file)
|
||||||
|
-
|
||||||
|
- with open(config_path, "w") as fd:
|
||||||
|
- grub_dir = self.config_dir
|
||||||
|
- if self.stage2_device.format.type != "btrfs":
|
||||||
|
- fs_uuid = self.stage2_device.format.uuid
|
||||||
|
- else:
|
||||||
|
- fs_uuid = self.stage2_device.format.vol_uuid
|
||||||
|
-
|
||||||
|
- if fs_uuid is None:
|
||||||
|
- raise BootLoaderError("Could not get stage2 filesystem UUID")
|
||||||
|
-
|
||||||
|
- grub_dir = util.execWithCapture("grub2-mkrelpath", [grub_dir],
|
||||||
|
- root=conf.target.system_root)
|
||||||
|
- if not grub_dir:
|
||||||
|
- raise BootLoaderError("Could not get GRUB directory path")
|
||||||
|
-
|
||||||
|
- fd.write("search --no-floppy --fs-uuid --set=dev %s\n" % fs_uuid)
|
||||||
|
- fd.write("set prefix=($dev)%s\n" % grub_dir)
|
||||||
|
- fd.write("export $prefix\n")
|
||||||
|
- fd.write("configfile $prefix/grub.cfg\n")
|
||||||
|
-
|
||||||
|
- super().write_config()
|
||||||
|
-
|
||||||
|
|
||||||
|
class Aarch64EFIGRUB(EFIGRUB):
|
||||||
|
_serial_consoles = ["ttyAMA", "ttyS"]
|
||||||
|
diff --git a/pyanaconda/modules/storage/bootloader/utils.py b/pyanaconda/modules/storage/bootloader/utils.py
|
||||||
|
index 27fc2a0..84e45b6 100644
|
||||||
|
--- a/pyanaconda/modules/storage/bootloader/utils.py
|
||||||
|
+++ b/pyanaconda/modules/storage/bootloader/utils.py
|
||||||
|
@@ -19,6 +19,7 @@ import os
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
|
from pyanaconda.modules.common.errors.installation import BootloaderInstallationError
|
||||||
|
+from pyanaconda.modules.storage.bootloader.efi import EFIBase
|
||||||
|
from pyanaconda.modules.storage.bootloader.image import LinuxBootLoaderImage
|
||||||
|
from pyanaconda.core.configuration.anaconda import conf
|
||||||
|
from pyanaconda.core.util import execWithRedirect
|
||||||
|
@@ -244,9 +245,14 @@ def create_bls_entries(sysroot, storage, kernel_versions):
|
||||||
|
# Update the bootloader configuration to make sure that the BLS
|
||||||
|
# entries will have the correct kernel cmdline and not the value
|
||||||
|
# taken from /proc/cmdline, that is used to boot the live image.
|
||||||
|
+ if isinstance(storage.bootloader, EFIBase):
|
||||||
|
+ grub_cfg_path = "/etc/grub2-efi.cfg"
|
||||||
|
+ else:
|
||||||
|
+ grub_cfg_path = "/etc/grub2.cfg"
|
||||||
|
+
|
||||||
|
rc = execWithRedirect(
|
||||||
|
"grub2-mkconfig",
|
||||||
|
- ["-o", "/etc/grub2.cfg"],
|
||||||
|
+ ["-o", grub_cfg_path],
|
||||||
|
root=sysroot
|
||||||
|
)
|
||||||
|
|
||||||
|
--
|
||||||
|
2.23.0
|
||||||
|
|
||||||
@ -4,19 +4,20 @@ Date: Thu, 18 Jun 2020 17:13:47 +0800
|
|||||||
Subject: [PATCH] fix hostname info
|
Subject: [PATCH] fix hostname info
|
||||||
|
|
||||||
---
|
---
|
||||||
po/zh_CN.po | 5 +++--
|
po/zh_CN.po | 6 +++---
|
||||||
pyanaconda/core/regexes.py | 2 +-
|
pyanaconda/core/regexes.py | 2 +-
|
||||||
pyanaconda/network.py | 3 ++-
|
pyanaconda/network.py | 4 ++--
|
||||||
3 files changed, 6 insertions(+), 4 deletions(-)
|
3 files changed, 6 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
diff --git a/po/zh_CN.po b/po/zh_CN.po
|
diff --git a/po/zh_CN.po b/po/zh_CN.po
|
||||||
index e31f0b2..c02ce1e 100644
|
index 18b0925..c2216e6 100644
|
||||||
--- a/po/zh_CN.po
|
--- a/po/zh_CN.po
|
||||||
+++ b/po/zh_CN.po
|
+++ b/po/zh_CN.po
|
||||||
@@ -4090,10 +4090,11 @@ msgstr "本地主机名不能以英文句号“.”结尾。"
|
@@ -4089,11 +4089,11 @@ msgstr "本地主机名不能以英文句号“.”结尾。"
|
||||||
|
#: pyanaconda/network.py:119
|
||||||
msgid ""
|
msgid ""
|
||||||
"Host names can only contain the characters 'a-z', 'A-Z', '0-9', '-', or '.', "
|
"Host names can only contain the characters 'a-z', 'A-Z', '0-9', '-', or '.', "
|
||||||
"parts between periods must contain something and cannot start or end with "
|
-"parts between periods must contain something and cannot start or end with "
|
||||||
-"'-'."
|
-"'-'."
|
||||||
+"parts between periods must contain something being 63 or fewer "
|
+"parts between periods must contain something being 63 or fewer "
|
||||||
+"characters and cannot start or end with '.' and '-'."
|
+"characters and cannot start or end with '.' and '-'."
|
||||||
@ -41,13 +42,14 @@ index cc00702..388d1ff 100644
|
|||||||
# URL Hostname
|
# URL Hostname
|
||||||
# This matches any hostname, IPv4 literal or properly encased IPv6 literal
|
# This matches any hostname, IPv4 literal or properly encased IPv6 literal
|
||||||
diff --git a/pyanaconda/network.py b/pyanaconda/network.py
|
diff --git a/pyanaconda/network.py b/pyanaconda/network.py
|
||||||
index 38fe957..c52cf1d 100644
|
index 38fe957..8f04d63 100644
|
||||||
--- a/pyanaconda/network.py
|
--- a/pyanaconda/network.py
|
||||||
+++ b/pyanaconda/network.py
|
+++ b/pyanaconda/network.py
|
||||||
@@ -115,7 +115,8 @@ def is_valid_hostname(hostname, local=False):
|
@@ -114,8 +114,8 @@ def is_valid_hostname(hostname, local=False):
|
||||||
|
if not re.match('^' + HOSTNAME_PATTERN_WITHOUT_ANCHORS + '$', hostname):
|
||||||
return (False, _("Host names can only contain the characters 'a-z', "
|
return (False, _("Host names can only contain the characters 'a-z', "
|
||||||
"'A-Z', '0-9', '-', or '.', parts between periods "
|
"'A-Z', '0-9', '-', or '.', parts between periods "
|
||||||
"must contain something and cannot start or end with "
|
- "must contain something and cannot start or end with "
|
||||||
- "'-'."))
|
- "'-'."))
|
||||||
+ "must contain something being 63 or fewer "
|
+ "must contain something being 63 or fewer "
|
||||||
+ "characters and cannot start or end with '.' and '-'."))
|
+ "characters and cannot start or end with '.' and '-'."))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user