From a645a1b8d17310533ef2d9232855c1852558e2b8 Mon Sep 17 00:00:00 2001 From: Vendula Poncova Date: Fri, 3 Jul 2020 12:04:04 +0200 Subject: [PATCH] Use the structure for time sources in ntp.py Modify ntp.py to work with TimeSourceData instead of strings and clean up its functions a little. --- pyanaconda/ntp.py | 174 +++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 101 deletions(-) diff --git a/pyanaconda/ntp.py b/pyanaconda/ntp.py index 16eece65e4..1b74ac9433 100644 --- a/pyanaconda/ntp.py +++ b/pyanaconda/ntp.py @@ -31,6 +31,7 @@ from pyanaconda import isys from pyanaconda.threading import threadMgr, AnacondaThread from pyanaconda.core.constants import THREAD_SYNC_TIME_BASENAME +from pyanaconda.modules.common.structures.timezone import TimeSourceData NTP_CONFIG_FILE = "/etc/chrony.conf" @@ -47,21 +48,18 @@ class NTPconfigError(Exception): pass -def ntp_server_working(server): - """ - Tries to do an NTP request to the $server (timeout may take some time). +def ntp_server_working(server_hostname): + """Tries to do an NTP request to the server (timeout may take some time). - :param server: hostname or IP address of an NTP server - :type server: string + :param server_hostname: a host name or an IP address of an NTP server + :type server_hostname: string :return: True if the given server is reachable and working, False otherwise :rtype: bool - """ - client = ntplib.NTPClient() try: - client.request(server) + client.request(server_hostname) except ntplib.NTPException: return False # address related error @@ -75,118 +73,89 @@ def ntp_server_working(server): return True -def pools_servers_to_internal(pools, servers): - ret = [] - for pool in pools: - ret.extend(SERVERS_PER_POOL * [pool]) - ret.extend(servers) - - return ret - - -def internal_to_pools_and_servers(pools_servers): - server_nums = dict() - pools = [] - servers = [] - - for item in pools_servers: - server_nums[item] = server_nums.get(item, 0) + 1 - - for item in server_nums.keys(): - if server_nums[item] >= SERVERS_PER_POOL: - pools.extend((server_nums[item] // SERVERS_PER_POOL) * [item]) - servers.extend((server_nums[item] % SERVERS_PER_POOL) * [item]) - else: - servers.extend(server_nums[item] * [item]) +def get_servers_from_config(conf_file_path=NTP_CONFIG_FILE): + """Get NTP servers from a configuration file. - return (pools, servers) - - -def get_servers_from_config(conf_file_path=NTP_CONFIG_FILE, - srv_regexp=SRV_LINE_REGEXP): - """ Goes through the chronyd's configuration file looking for lines starting with 'server'. + :param conf_file_path: a path to the chronyd's configuration file :return: servers found in the chronyd's configuration - :rtype: list - + :rtype: a list of TimeSourceData instances """ - - pools = list() - servers = list() + servers = [] try: with open(conf_file_path, "r") as conf_file: for line in conf_file: - match = srv_regexp.match(line) - if match: - if match.group(1) == "pool": - pools.append(match.group(2)) - else: - servers.append(match.group(2)) + match = SRV_LINE_REGEXP.match(line) + + if not match: + continue + + server = TimeSourceData() + server.type = match.group(1).upper() + server.hostname = match.group(2) + server.options = ["iburst"] + servers.append(server) except IOError as ioerr: - msg = "Cannot open config file %s for reading (%s)" % (conf_file_path, - ioerr.strerror) - raise NTPconfigError(msg) + msg = "Cannot open config file {} for reading ({})." + raise NTPconfigError(msg.format(conf_file_path, ioerr.strerror)) - return (pools, servers) + return servers -def save_servers_to_config(pools, servers, conf_file_path=NTP_CONFIG_FILE, - srv_regexp=SRV_LINE_REGEXP, out_file_path=None): - """ +def save_servers_to_config(servers, conf_file_path=NTP_CONFIG_FILE, out_file_path=None): + """Save NTP servers to a configuration file. + Replaces the pools and servers defined in the chronyd's configuration file with the given ones. If the out_file is not None, then it is used for the resulting config. - :type pools: iterable - :type servers: iterable - :param out_file_path: path to the file used for the resulting config - + :param servers: a list of NTP servers and pools + :type servers: a list of TimeSourceData instances + :param conf_file_path: a path to the chronyd's configuration file + :param out_file_path: a path to the file used for the resulting config """ + temp_path = None try: old_conf_file = open(conf_file_path, "r") - except IOError as ioerr: - msg = "Cannot open config file %s for reading (%s)" % (conf_file_path, - ioerr.strerror) - raise NTPconfigError(msg) + msg = "Cannot open config file {} for reading ({})." + raise NTPconfigError(msg.format(conf_file_path, ioerr.strerror)) - try: - if out_file_path: + if out_file_path: + try: new_conf_file = open(out_file_path, "w") - else: - (fildes, temp_path) = tempfile.mkstemp() - new_conf_file = os.fdopen(fildes, "w") - - except IOError as ioerr: - if out_file_path: - msg = "Cannot open new config file %s "\ - "for writing (%s)" % (out_file_path, ioerr.strerror) - else: - msg = "Cannot open temporary file %s "\ - "for writing (%s)" % (temp_path, ioerr.strerror) - - raise NTPconfigError(msg) + except IOError as ioerr: + msg = "Cannot open new config file {} for writing ({})." + raise NTPconfigError(msg.format(out_file_path, ioerr.strerror)) + else: + try: + (fields, temp_path) = tempfile.mkstemp() + new_conf_file = os.fdopen(fields, "w") + except IOError as ioerr: + msg = "Cannot open temporary file {} for writing ({})." + raise NTPconfigError(msg.format(temp_path, ioerr.strerror)) heading = "# These servers were defined in the installation:\n" - #write info about the origin of the following lines + # write info about the origin of the following lines new_conf_file.write(heading) - #write new servers and pools - for pool in pools: - new_conf_file.write("pool " + pool + " iburst\n") - + # write new servers and pools for server in servers: - new_conf_file.write("server " + server + " iburst\n") + args = [server.type.lower(), server.hostname] + server.options + line = " ".join(args) + "\n" + new_conf_file.write(line) - #copy non-server lines from the old config and skip our heading + new_conf_file.write("\n") + + # copy non-server lines from the old config and skip our heading for line in old_conf_file: - if not srv_regexp.match(line) and line != heading: + if not SRV_LINE_REGEXP.match(line) and line != heading: new_conf_file.write(line) old_conf_file.close() @@ -199,28 +168,27 @@ def save_servers_to_config(pools, servers, conf_file_path=NTP_CONFIG_FILE, os.unlink(temp_path) except OSError as oserr: - msg = "Cannot replace the old config with "\ - "the new one (%s)" % (oserr.strerror) + msg = "Cannot replace the old config with the new one ({})." + raise NTPconfigError(msg.format(oserr.strerror)) - raise NTPconfigError(msg) +def _one_time_sync(server, callback=None): + """Synchronize the system time with a given NTP server. -def one_time_sync(server, callback=None): - """ Synchronize the system time with a given NTP server. Note that this function is blocking and will not return until the time gets synced or querying server fails (may take some time before timeouting). - :param server: NTP server + :param server: an NTP server + :type server: an instance of TimeSourceData :param callback: callback function to run after sync or failure :type callback: a function taking one boolean argument (success) :return: True if the sync was successful, False otherwise - """ client = ntplib.NTPClient() try: - results = client.request(server) + results = client.request(server.hostname) isys.set_system_time(int(results.tx_time)) success = True except ntplib.NTPException: @@ -235,22 +203,26 @@ def one_time_sync(server, callback=None): def one_time_sync_async(server, callback=None): - """ + """Asynchronously synchronize the system time with a given NTP server. + Asynchronously synchronize the system time with a given NTP server. This function is non-blocking it starts a new thread for synchronization and returns. Use callback argument to specify the function called when the new thread finishes if needed. - :param server: NTP server + :param server: an NTP server + :type server: an instance of TimeSourceData :param callback: callback function to run after sync or failure :type callback: a function taking one boolean argument (success) - """ + thread_name = "%s_%s" % (THREAD_SYNC_TIME_BASENAME, server.hostname) - thread_name = "%s_%s" % (THREAD_SYNC_TIME_BASENAME, server) + # syncing with the same server running if threadMgr.get(thread_name): - #syncing with the same server running return - threadMgr.add(AnacondaThread(name=thread_name, target=one_time_sync, - args=(server, callback))) + threadMgr.add(AnacondaThread( + name=thread_name, + target=_one_time_sync, + args=(server, callback) + )) -- 2.23.0