407 lines
17 KiB
Diff
407 lines
17 KiB
Diff
From 4bc1b7305199fffc78439ab1ad1cdb8272988d52 Mon Sep 17 00:00:00 2001
|
|
From: Vendula Poncova <vponcova@redhat.com>
|
|
Date: Fri, 3 Jul 2020 12:21:11 +0200
|
|
Subject: [PATCH] Use the structure for time sources in the Timezone module
|
|
|
|
Modify the Timezone module to work with the DBus structures for time sources
|
|
instead of the strings. Rename the DBus property NTPServers to TimeSources.
|
|
---
|
|
pyanaconda/modules/timezone/installation.py | 14 ++-
|
|
pyanaconda/modules/timezone/timezone.py | 44 ++++---
|
|
.../modules/timezone/timezone_interface.py | 34 +++---
|
|
.../pyanaconda_tests/module_timezone_test.py | 107 ++++++++++++++----
|
|
4 files changed, 141 insertions(+), 58 deletions(-)
|
|
|
|
diff --git a/pyanaconda/modules/timezone/installation.py b/pyanaconda/modules/timezone/installation.py
|
|
index 6383df1103..c3ea4d7179 100644
|
|
--- a/pyanaconda/modules/timezone/installation.py
|
|
+++ b/pyanaconda/modules/timezone/installation.py
|
|
@@ -145,12 +145,14 @@ def run(self):
|
|
return
|
|
|
|
chronyd_conf_path = os.path.normpath(self._sysroot + ntp.NTP_CONFIG_FILE)
|
|
- pools, servers = ntp.internal_to_pools_and_servers(self._ntp_servers)
|
|
|
|
if os.path.exists(chronyd_conf_path):
|
|
log.debug("Modifying installed chrony configuration")
|
|
try:
|
|
- ntp.save_servers_to_config(pools, servers, conf_file_path=chronyd_conf_path)
|
|
+ ntp.save_servers_to_config(
|
|
+ self._ntp_servers,
|
|
+ conf_file_path=chronyd_conf_path
|
|
+ )
|
|
except ntp.NTPconfigError as ntperr:
|
|
log.warning("Failed to save NTP configuration: %s", ntperr)
|
|
|
|
@@ -160,9 +162,11 @@ def run(self):
|
|
log.debug("Creating chrony configuration based on the "
|
|
"configuration from installation environment")
|
|
try:
|
|
- ntp.save_servers_to_config(pools, servers,
|
|
- conf_file_path=ntp.NTP_CONFIG_FILE,
|
|
- out_file_path=chronyd_conf_path)
|
|
+ ntp.save_servers_to_config(
|
|
+ self._ntp_servers,
|
|
+ conf_file_path=ntp.NTP_CONFIG_FILE,
|
|
+ out_file_path=chronyd_conf_path
|
|
+ )
|
|
except ntp.NTPconfigError as ntperr:
|
|
log.warning("Failed to save NTP configuration without chrony package: %s",
|
|
ntperr)
|
|
diff --git a/pyanaconda/modules/timezone/timezone.py b/pyanaconda/modules/timezone/timezone.py
|
|
index 0678072978..ff89d1ea77 100644
|
|
--- a/pyanaconda/modules/timezone/timezone.py
|
|
+++ b/pyanaconda/modules/timezone/timezone.py
|
|
@@ -18,10 +18,12 @@
|
|
# Red Hat, Inc.
|
|
#
|
|
from pyanaconda.core.configuration.anaconda import conf
|
|
+from pyanaconda.core.constants import TIME_SOURCE_SERVER
|
|
from pyanaconda.core.dbus import DBus
|
|
from pyanaconda.core.signal import Signal
|
|
from pyanaconda.modules.common.base import KickstartService
|
|
from pyanaconda.modules.common.constants.services import TIMEZONE
|
|
+from pyanaconda.modules.common.structures.timezone import TimeSourceData
|
|
from pyanaconda.timezone import NTP_PACKAGE
|
|
from pyanaconda.modules.common.containers import TaskContainer
|
|
from pyanaconda.modules.common.structures.requirement import Requirement
|
|
@@ -48,8 +50,8 @@ def __init__(self):
|
|
self.ntp_enabled_changed = Signal()
|
|
self._ntp_enabled = True
|
|
|
|
- self.ntp_servers_changed = Signal()
|
|
- self._ntp_servers = []
|
|
+ self.time_sources_changed = Signal()
|
|
+ self._time_sources = []
|
|
|
|
# FIXME: temporary workaround until PAYLOAD module is available
|
|
self._ntp_excluded = False
|
|
@@ -70,7 +72,17 @@ def process_kickstart(self, data):
|
|
self.set_timezone(data.timezone.timezone)
|
|
self.set_is_utc(data.timezone.isUtc)
|
|
self.set_ntp_enabled(not data.timezone.nontp)
|
|
- self.set_ntp_servers(data.timezone.ntpservers)
|
|
+
|
|
+ servers = []
|
|
+
|
|
+ for hostname in data.timezone.ntpservers:
|
|
+ server = TimeSourceData()
|
|
+ server.type = TIME_SOURCE_SERVER
|
|
+ server.hostname = hostname
|
|
+ server.options = ["iburst"]
|
|
+ servers.append(server)
|
|
+
|
|
+ self.set_time_sources(servers)
|
|
|
|
def setup_kickstart(self, data):
|
|
"""Set up the kickstart data."""
|
|
@@ -78,8 +90,12 @@ def setup_kickstart(self, data):
|
|
data.timezone.isUtc = self.is_utc
|
|
data.timezone.nontp = not self.ntp_enabled
|
|
|
|
- if self.ntp_enabled:
|
|
- data.timezone.ntpservers = list(self.ntp_servers)
|
|
+ if not self.ntp_enabled:
|
|
+ return
|
|
+
|
|
+ data.timezone.ntpservers = [
|
|
+ server.hostname for server in self.time_sources
|
|
+ ]
|
|
|
|
@property
|
|
def timezone(self):
|
|
@@ -115,15 +131,15 @@ def set_ntp_enabled(self, ntp_enabled):
|
|
log.debug("NTP is set to %s.", ntp_enabled)
|
|
|
|
@property
|
|
- def ntp_servers(self):
|
|
- """Return a list of NTP servers."""
|
|
- return self._ntp_servers
|
|
+ def time_sources(self):
|
|
+ """Return a list of time sources."""
|
|
+ return self._time_sources
|
|
|
|
- def set_ntp_servers(self, servers):
|
|
- """Set NTP servers."""
|
|
- self._ntp_servers = list(servers)
|
|
- self.ntp_servers_changed.emit()
|
|
- log.debug("NTP servers are set to %s.", servers)
|
|
+ def set_time_sources(self, servers):
|
|
+ """Set time sources."""
|
|
+ self._time_sources = list(servers)
|
|
+ self.time_sources_changed.emit()
|
|
+ log.debug("Time sources are set to: %s", servers)
|
|
|
|
def collect_requirements(self):
|
|
"""Return installation requirements for this module.
|
|
@@ -168,6 +184,6 @@ def install_with_tasks(self):
|
|
ConfigureNTPTask(
|
|
sysroot=conf.target.system_root,
|
|
ntp_enabled=self.ntp_enabled,
|
|
- ntp_servers=self.ntp_servers
|
|
+ ntp_servers=self.time_sources
|
|
)
|
|
]
|
|
diff --git a/pyanaconda/modules/timezone/timezone_interface.py b/pyanaconda/modules/timezone/timezone_interface.py
|
|
index 03c5003f1e..f36e0b3723 100644
|
|
--- a/pyanaconda/modules/timezone/timezone_interface.py
|
|
+++ b/pyanaconda/modules/timezone/timezone_interface.py
|
|
@@ -17,13 +17,15 @@
|
|
# License and may only be used or replicated with the express permission of
|
|
# Red Hat, Inc.
|
|
#
|
|
-from pyanaconda.modules.common.constants.services import TIMEZONE
|
|
-from pyanaconda.modules.common.containers import TaskContainer
|
|
from dasbus.server.property import emits_properties_changed
|
|
from dasbus.typing import * # pylint: disable=wildcard-import
|
|
-from pyanaconda.modules.common.base import KickstartModuleInterface
|
|
from dasbus.server.interface import dbus_interface
|
|
|
|
+from pyanaconda.modules.common.base import KickstartModuleInterface
|
|
+from pyanaconda.modules.common.constants.services import TIMEZONE
|
|
+from pyanaconda.modules.common.containers import TaskContainer
|
|
+from pyanaconda.modules.common.structures.timezone import TimeSourceData
|
|
+
|
|
|
|
@dbus_interface(TIMEZONE.interface_name)
|
|
class TimezoneInterface(KickstartModuleInterface):
|
|
@@ -34,7 +36,7 @@ def connect_signals(self):
|
|
self.watch_property("Timezone", self.implementation.timezone_changed)
|
|
self.watch_property("IsUTC", self.implementation.is_utc_changed)
|
|
self.watch_property("NTPEnabled", self.implementation.ntp_enabled_changed)
|
|
- self.watch_property("NTPServers", self.implementation.ntp_servers_changed)
|
|
+ self.watch_property("TimeSources", self.implementation.time_sources_changed)
|
|
|
|
@property
|
|
def Timezone(self) -> Str:
|
|
@@ -91,22 +93,26 @@ def SetNTPEnabled(self, ntp_enabled: Bool):
|
|
self.implementation.set_ntp_enabled(ntp_enabled)
|
|
|
|
@property
|
|
- def NTPServers(self) -> List[Str]:
|
|
- """A list of NTP servers.
|
|
+ def TimeSources(self) -> List[Structure]:
|
|
+ """A list of time sources.
|
|
|
|
- :return: a list of servers
|
|
+ :return: a list of time source data
|
|
+ :rtype: a list of structures of the type TimeSourceData
|
|
"""
|
|
- return self.implementation.ntp_servers
|
|
+ return TimeSourceData.to_structure_list(
|
|
+ self.implementation.time_sources
|
|
+ )
|
|
|
|
@emits_properties_changed
|
|
- def SetNTPServers(self, servers: List[Str]):
|
|
- """Set the NTP servers.
|
|
+ def SetTimeSources(self, sources: List[Structure]):
|
|
+ """Set the time sources.
|
|
|
|
- Example: [ntp.cesnet.cz]
|
|
-
|
|
- :param servers: a list of servers
|
|
+ :param sources: a list of time sources
|
|
+ :type sources: a list of structures of the type TimeSourceData
|
|
"""
|
|
- self.implementation.set_ntp_servers(servers)
|
|
+ self.implementation.set_time_sources(
|
|
+ TimeSourceData.from_structure_list(sources)
|
|
+ )
|
|
|
|
def ConfigureNTPServiceEnablementWithTask(self, ntp_excluded: Bool) -> ObjPath:
|
|
"""Enable or disable NTP service.
|
|
diff --git a/tests/nosetests/pyanaconda_tests/module_timezone_test.py b/tests/nosetests/pyanaconda_tests/module_timezone_test.py
|
|
index f991f1e992..bb751d6f4b 100644
|
|
--- a/tests/nosetests/pyanaconda_tests/module_timezone_test.py
|
|
+++ b/tests/nosetests/pyanaconda_tests/module_timezone_test.py
|
|
@@ -23,8 +23,13 @@
|
|
from shutil import copytree, copyfile
|
|
from unittest.mock import Mock, patch
|
|
|
|
+from dasbus.structure import compare_data
|
|
+from dasbus.typing import * # pylint: disable=wildcard-import
|
|
+
|
|
+from pyanaconda.core.constants import TIME_SOURCE_SERVER, TIME_SOURCE_POOL
|
|
from pyanaconda.modules.common.constants.services import TIMEZONE
|
|
from pyanaconda.modules.common.errors.installation import TimezoneConfigurationError
|
|
+from pyanaconda.modules.common.structures.timezone import TimeSourceData
|
|
from pyanaconda.modules.timezone.installation import ConfigureNTPTask, ConfigureTimezoneTask, \
|
|
ConfigureNTPServiceEnablementTask
|
|
from pyanaconda.modules.common.structures.kickstart import KickstartReport
|
|
@@ -33,7 +38,7 @@
|
|
from pyanaconda.ntp import NTP_CONFIG_FILE, NTPconfigError
|
|
from tests.nosetests.pyanaconda_tests import check_kickstart_interface, \
|
|
patch_dbus_publish_object, PropertiesChangedCallback, check_task_creation, \
|
|
- patch_dbus_get_proxy, check_task_creation_list
|
|
+ patch_dbus_get_proxy, check_task_creation_list, check_dbus_property
|
|
from pyanaconda.timezone import NTP_SERVICE
|
|
|
|
|
|
@@ -50,6 +55,14 @@ def setUp(self):
|
|
self.callback = PropertiesChangedCallback()
|
|
self.timezone_interface.PropertiesChanged.connect(self.callback)
|
|
|
|
+ def _check_dbus_property(self, *args, **kwargs):
|
|
+ check_dbus_property(
|
|
+ self,
|
|
+ TIMEZONE,
|
|
+ self.timezone_interface,
|
|
+ *args, **kwargs
|
|
+ )
|
|
+
|
|
def kickstart_properties_test(self):
|
|
"""Test kickstart properties."""
|
|
self.assertEqual(self.timezone_interface.KickstartCommands, ["timezone"])
|
|
@@ -76,12 +89,24 @@ def ntp_property_test(self):
|
|
self.assertEqual(self.timezone_interface.NTPEnabled, False)
|
|
self.callback.assert_called_once_with(TIMEZONE.interface_name, {'NTPEnabled': False}, [])
|
|
|
|
- def ntp_servers_property_test(self):
|
|
- """Test the NTPServers property."""
|
|
- self.timezone_interface.SetNTPServers(["ntp.cesnet.cz"])
|
|
- self.assertEqual(self.timezone_interface.NTPServers, ["ntp.cesnet.cz"])
|
|
- self.callback.assert_called_once_with(
|
|
- TIMEZONE.interface_name, {'NTPServers': ["ntp.cesnet.cz"]}, [])
|
|
+ def time_sources_property_test(self):
|
|
+ """Test the TimeSources property."""
|
|
+ server = {
|
|
+ "type": get_variant(Str, TIME_SOURCE_SERVER),
|
|
+ "hostname": get_variant(Str, "ntp.cesnet.cz"),
|
|
+ "options": get_variant(List[Str], ["iburst"]),
|
|
+ }
|
|
+
|
|
+ pool = {
|
|
+ "type": get_variant(Str, TIME_SOURCE_POOL),
|
|
+ "hostname": get_variant(Str, "0.fedora.pool.ntp.org"),
|
|
+ "options": get_variant(List[Str], []),
|
|
+ }
|
|
+
|
|
+ self._check_dbus_property(
|
|
+ "TimeSources",
|
|
+ [server, pool]
|
|
+ )
|
|
|
|
def _test_kickstart(self, ks_in, ks_out):
|
|
check_kickstart_interface(self, self.timezone_interface, ks_in, ks_out)
|
|
@@ -162,10 +187,19 @@ def install_with_tasks_configured_test(self, publisher):
|
|
self.timezone_interface.SetNTPEnabled(False)
|
|
# --nontp and --ntpservers are mutually exclusive in kicstart but
|
|
# there is no such enforcement in the module so for testing this is ok
|
|
- self.timezone_interface.SetNTPServers([
|
|
- "clock1.example.com",
|
|
- "clock2.example.com",
|
|
- ])
|
|
+
|
|
+ server = TimeSourceData()
|
|
+ server.type = TIME_SOURCE_SERVER
|
|
+ server.hostname = "clock1.example.com"
|
|
+ server.options = ["iburst"]
|
|
+
|
|
+ pool = TimeSourceData()
|
|
+ pool.type = TIME_SOURCE_POOL
|
|
+ pool.hostname = "clock2.example.com"
|
|
+
|
|
+ self.timezone_interface.SetTimeSources(
|
|
+ TimeSourceData.to_structure_list([server, pool])
|
|
+ )
|
|
|
|
task_classes = [
|
|
ConfigureTimezoneTask,
|
|
@@ -182,10 +216,9 @@ def install_with_tasks_configured_test(self, publisher):
|
|
# ConfigureNTPTask
|
|
obj = task_objs[1]
|
|
self.assertEqual(obj.implementation._ntp_enabled, False)
|
|
- self.assertEqual(obj.implementation._ntp_servers, [
|
|
- "clock1.example.com",
|
|
- "clock2.example.com",
|
|
- ])
|
|
+ self.assertEqual(len(obj.implementation._ntp_servers), 2)
|
|
+ self.assertTrue(compare_data(obj.implementation._ntp_servers[0], server))
|
|
+ self.assertTrue(compare_data(obj.implementation._ntp_servers[1], pool))
|
|
|
|
@patch_dbus_publish_object
|
|
def configure_ntp_service_enablement_default_test(self, publisher):
|
|
@@ -354,13 +387,13 @@ class NTPTasksTestCase(unittest.TestCase):
|
|
|
|
def ntp_task_success_test(self):
|
|
"""Test the success cases for NTP setup D-Bus task."""
|
|
- self._test_ntp_inputs(False, False, ["unique.ntp.server", "another.unique.server"])
|
|
- self._test_ntp_inputs(False, True, ["unique.ntp.server", "another.unique.server"])
|
|
+ self._test_ntp_inputs(False, False)
|
|
+ self._test_ntp_inputs(False, True)
|
|
|
|
def ntp_overwrite_test(self):
|
|
"""Test overwriting existing config for NTP setup D-Bus task."""
|
|
- self._test_ntp_inputs(True, True, ["unique.ntp.server", "another.unique.server"])
|
|
- self._test_ntp_inputs(True, False, ["unique.ntp.server", "another.unique.server"])
|
|
+ self._test_ntp_inputs(True, True)
|
|
+ self._test_ntp_inputs(True, False)
|
|
|
|
def ntp_save_failure_test(self):
|
|
"""Test failure when saving NTP config in D-Bus task."""
|
|
@@ -368,6 +401,25 @@ def ntp_save_failure_test(self):
|
|
self._test_ntp_exception(True)
|
|
self._test_ntp_exception(False)
|
|
|
|
+ def _get_test_sources(self):
|
|
+ """Get a list of sources"""
|
|
+ server = TimeSourceData()
|
|
+ server.type = TIME_SOURCE_SERVER
|
|
+ server.hostname = "unique.ntp.server"
|
|
+ server.options = ["iburst"]
|
|
+
|
|
+ pool = TimeSourceData()
|
|
+ pool.type = TIME_SOURCE_POOL
|
|
+ pool.hostname = "another.unique.server"
|
|
+
|
|
+ return [server, pool]
|
|
+
|
|
+ def _get_expected_lines(self):
|
|
+ return [
|
|
+ "server unique.ntp.server iburst\n",
|
|
+ "pool another.unique.server\n"
|
|
+ ]
|
|
+
|
|
@patch("pyanaconda.modules.timezone.installation.ntp.save_servers_to_config",
|
|
side_effect=NTPconfigError)
|
|
def _test_ntp_exception(self, make_chronyd, mock_save):
|
|
@@ -376,11 +428,14 @@ def _test_ntp_exception(self, make_chronyd, mock_save):
|
|
with self.assertLogs("anaconda.modules.timezone.installation", level="WARNING"):
|
|
self._execute_task(sysroot, True, ["ntp.example.com"])
|
|
|
|
- def _test_ntp_inputs(self, make_chronyd, ntp_enabled, ntp_servers):
|
|
+ def _test_ntp_inputs(self, make_chronyd, ntp_enabled):
|
|
+ ntp_servers = self._get_test_sources()
|
|
+ expected_lines = self._get_expected_lines()
|
|
+
|
|
with tempfile.TemporaryDirectory() as sysroot:
|
|
self._setup_environment(sysroot, make_chronyd)
|
|
self._execute_task(sysroot, ntp_enabled, ntp_servers)
|
|
- self._validate_ntp_config(sysroot, make_chronyd, ntp_enabled, ntp_servers)
|
|
+ self._validate_ntp_config(sysroot, make_chronyd, ntp_enabled, expected_lines)
|
|
|
|
def _setup_environment(self, sysroot, make_chronyd):
|
|
os.mkdir(sysroot + "/etc")
|
|
@@ -395,12 +450,14 @@ def _execute_task(self, sysroot, ntp_enabled, ntp_servers):
|
|
)
|
|
task.run()
|
|
|
|
- def _validate_ntp_config(self, sysroot, was_present, was_enabled, expected_servers):
|
|
+ def _validate_ntp_config(self, sysroot, was_present, was_enabled, expected_lines):
|
|
if was_enabled:
|
|
with open(sysroot + NTP_CONFIG_FILE) as fobj:
|
|
- all_lines = "\n".join(fobj.readlines())
|
|
- for server in expected_servers:
|
|
- self.assertIn(server, all_lines)
|
|
+ all_lines = fobj.readlines()
|
|
+
|
|
+ for line in expected_lines:
|
|
+ self.assertIn(line, all_lines)
|
|
+
|
|
elif not was_present:
|
|
self.assertFalse(os.path.exists(sysroot + NTP_CONFIG_FILE))
|
|
|
|
--
|
|
2.23.0
|