diff --git a/pyanaconda/ntp.py b/pyanaconda/ntp.py
index eed4b34307c..cde27258aaa 100644
--- a/pyanaconda/ntp.py
+++ b/pyanaconda/ntp.py
@@ -40,7 +40,9 @@
#example line:
#server 0.fedora.pool.ntp.org iburst
-SRV_LINE_REGEXP = re.compile(r"^\s*(server|pool)\s*([-a-zA-Z.0-9]+)\s*[a-zA-Z]+\s*$")
+SRV_LINE_REGEXP = re.compile(r"^\s*(server|pool)\s*([-a-zA-Z.0-9]+)\s?([a-zA-Z0-9\s]*)$")
+SRV_NOARG_OPTIONS = ["burst", "iburst", "nts", "prefer", "require", "trust", "noselect", "xleave"]
+SRV_ARG_OPTIONS = ["key", "minpoll", "maxpoll"]
#treat pools as four servers with the same name
SERVERS_PER_POOL = 4
@@ -95,18 +97,24 @@ def get_ntp_servers_summary(servers, states):
return summary
-def ntp_server_working(server_hostname):
+def ntp_server_working(server_hostname, nts_enabled):
"""Tries to do an NTP request to the server (timeout may take some time).
+ If NTS is enabled, try making a TCP connection to the NTS-KE port instead.
+
: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_hostname)
+ # ntplib doesn't support NTS
+ if nts_enabled:
+ s = socket.create_connection((server_hostname, 4460), 2)
+ s.close()
+ else:
+ client = ntplib.NTPClient()
+ client.request(server_hostname)
except ntplib.NTPException:
return False
# address related error
@@ -143,7 +151,23 @@ def get_servers_from_config(conf_file_path=NTP_CONFIG_FILE):
server = TimeSourceData()
server.type = match.group(1).upper()
server.hostname = match.group(2)
- server.options = ["iburst"]
+ server.options = []
+
+ words = match.group(3).lower().split()
+ skip_argument = False
+
+ for i in range(len(words)):
+ if skip_argument:
+ skip_argument = False
+ continue
+ if words[i] in SRV_NOARG_OPTIONS:
+ server.options.append(words[i])
+ elif words[i] in SRV_ARG_OPTIONS and i + 1 < len(words):
+ server.options.append(' '.join(words[i:i+2]))
+ skip_argument = True
+ else:
+ log.debug("Unknown NTP server option %s", words[i])
+
servers.append(server)
except IOError as ioerr:
@@ -306,8 +330,9 @@ def check_status(self, server):
:param TimeSourceData server: an NTP server
"""
- # Get a hostname.
+ # Get a hostname and NTS option.
hostname = server.hostname
+ nts_enabled = "nts" in server.options
# Reset the current status.
self._set_status(hostname, NTP_SERVER_QUERY)
@@ -316,7 +341,7 @@ def check_status(self, server):
threadMgr.add(AnacondaThread(
prefix=THREAD_NTP_SERVER_CHECK,
target=self._check_status,
- args=(hostname, ))
+ args=(hostname, nts_enabled))
)
def _set_status(self, hostname, status):
@@ -327,13 +352,13 @@ def _set_status(self, hostname, status):
"""
self._cache[hostname] = status
- def _check_status(self, hostname):
+ def _check_status(self, hostname, nts_enabled):
"""Check if an NTP server appears to be working.
:param str hostname: a hostname of an NTP server
"""
log.debug("Checking NTP server %s", hostname)
- result = ntp_server_working(hostname)
+ result = ntp_server_working(hostname, nts_enabled)
if result:
log.debug("NTP server %s appears to be working.", hostname)
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.glade b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
index 49e33776f51..3ebc12a4467 100644
--- a/pyanaconda/ui/gui/spokes/datetime_spoke.glade
+++ b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
@@ -83,6 +83,8 @@
+
+
@@ -220,6 +222,21 @@
3
+
+
+
+ False
+ True
+ 4
+
+
+
+
+
Working
@@ -282,7 +312,7 @@
- 3
+ 4
@@ -293,7 +323,7 @@
True
True
- 4
+ 5
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py
index ea121e7e4de..a8036cdb888 100644
--- a/pyanaconda/ui/gui/spokes/datetime_spoke.py
+++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py
@@ -63,9 +63,10 @@
SERVER_HOSTNAME = 0
SERVER_POOL = 1
-SERVER_WORKING = 2
-SERVER_USE = 3
-SERVER_OBJECT = 4
+SERVER_NTS = 2
+SERVER_WORKING = 3
+SERVER_USE = 4
+SERVER_OBJECT = 5
DEFAULT_TZ = "America/New_York"
@@ -184,6 +185,7 @@ def __init__(self, data, servers, states):
self._serversStore = self.builder.get_object("serversStore")
self._addButton = self.builder.get_object("addButton")
self._poolCheckButton = self.builder.get_object("poolCheckButton")
+ self._ntsCheckButton = self.builder.get_object("ntsCheckButton")
self._serverCheck = self.add_check(self._serverEntry, self._validate_server)
self._serverCheck.update_check_status()
@@ -256,6 +258,7 @@ def _add_row(self, server):
itr = self._serversStore.append([
"",
False,
+ False,
constants.NTP_SERVER_QUERY,
True,
server
@@ -268,6 +271,7 @@ def _refresh_row(self, itr):
server = self._serversStore[itr][SERVER_OBJECT]
self._serversStore.set_value(itr, SERVER_HOSTNAME, server.hostname)
self._serversStore.set_value(itr, SERVER_POOL, server.type == TIME_SOURCE_POOL)
+ self._serversStore.set_value(itr, SERVER_NTS, "nts" in server.options)
def _update_rows(self):
"""Periodically update the status of all rows.
@@ -300,12 +304,16 @@ def on_entry_activated(self, entry, *args):
server.hostname = entry.get_text()
server.options = ["iburst"]
+ if self._ntsCheckButton.get_active():
+ server.options.append("nts")
+
self._servers.append(server)
self._states.check_status(server)
self._add_row(server)
entry.set_text("")
self._poolCheckButton.set_active(False)
+ self._ntsCheckButton.set_active(False)
def on_add_clicked(self, *args):
self._serverEntry.emit("activate")
@@ -326,6 +334,18 @@ def on_pool_toggled(self, renderer, path, *args):
self._refresh_row(itr)
+ def on_nts_toggled(self, renderer, path, *args):
+ itr = self._serversStore.get_iter(path)
+ server = self._serversStore[itr][SERVER_OBJECT]
+
+ if "nts" in server.options:
+ server.options.remove("nts")
+ else:
+ server.options.append("nts")
+
+ self._states.check_status(server)
+ self._refresh_row(itr)
+
def on_server_editing_started(self, renderer, editable, path):
itr = self._serversStore.get_iter(path)
self._active_server = self._serversStore[itr][SERVER_OBJECT]