[PATCH] Use tiny, fast and thread-safe ntplib module instead of ntpdate

Vratislav Podzimek vpodzime at redhat.com
Fri Jul 26 11:41:04 UTC 2013


ntpdate is quite a big and slow binary that is not further developed and
basically nobody but us uses it. ntplib is a tiny, fast and thread-safe module
provided by the python-ntplib package containing only the tiny module.

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 anaconda.spec.in            |  2 +-
 pyanaconda/isys/__init__.py | 11 +++++++++++
 pyanaconda/isys/isys.c      | 19 +++++++++++++++++++
 pyanaconda/ntp.py           | 38 ++++++++++++++++++++++++++------------
 4 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/anaconda.spec.in b/anaconda.spec.in
index d8be92a..bebeef4 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -124,7 +124,7 @@ Requires: anaconda-yum-plugins
 Requires: libselinux-python >= %{libselinuxver}
 Requires: kbd
 Requires: chrony
-Requires: ntpdate
+Requires: python-ntplib
 Requires: rsync
 Requires: hostname
 %ifnarch s390 s390x
diff --git a/pyanaconda/isys/__init__.py b/pyanaconda/isys/__init__.py
index 6953793..a320bf9 100755
--- a/pyanaconda/isys/__init__.py
+++ b/pyanaconda/isys/__init__.py
@@ -111,6 +111,17 @@ def isPaeAvailable():
 def getAnacondaVersion():
     return _isys.getAnacondaVersion()
 
+def set_system_time(secs):
+    """
+    Set system time to time given as a number of seconds since the Epoch.
+
+    :param secs: a number of seconds since the Epoch to set system time to
+    :type secs: int
+
+    """
+
+    return  _isys.set_system_time(secs)
+
 auditDaemon = _isys.auditdaemon
 
 handleSegv = _isys.handleSegv
diff --git a/pyanaconda/isys/isys.c b/pyanaconda/isys/isys.c
index c99cb19..688695d 100644
--- a/pyanaconda/isys/isys.c
+++ b/pyanaconda/isys/isys.c
@@ -88,6 +88,7 @@ static PyObject * doIsCapsLockEnabled(PyObject * s, PyObject * args);
 static PyObject * doGetAnacondaVersion(PyObject * s, PyObject * args);
 static PyObject * doInitLog(PyObject * s);
 static PyObject * doTotalMemory(PyObject * s);
+static PyObject * doSetSystemTime(PyObject *s, PyObject *args);
 
 static PyMethodDef isysModuleMethods[] = {
     { "devSpaceFree", (PyCFunction) doDevSpaceFree, METH_VARARGS, NULL },
@@ -103,6 +104,7 @@ static PyMethodDef isysModuleMethods[] = {
     { "getAnacondaVersion", (PyCFunction) doGetAnacondaVersion, METH_VARARGS, NULL },
     { "initLog", (PyCFunction) doInitLog, METH_VARARGS, NULL },
     { "total_memory", (PyCFunction) doTotalMemory, METH_NOARGS, NULL },
+    { "set_system_time", (PyCFunction) doSetSystemTime, METH_VARARGS, NULL},
     { NULL, NULL, 0, NULL }
 } ;
 
@@ -274,4 +276,21 @@ static PyObject * doTotalMemory(PyObject * s) {
     return PyLong_FromUnsignedLongLong(tm);
 }
 
+static PyObject * doSetSystemTime(PyObject *s, PyObject  *args) {
+    int int_secs;
+    struct timeval tv;
+
+    if (!PyArg_ParseTuple(args, "i", &int_secs))
+        return NULL;
+
+    tv.tv_sec = (time_t) int_secs;
+    tv.tv_usec = 0;
+
+    settimeofday(&tv, NULL);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
 /* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/pyanaconda/ntp.py b/pyanaconda/ntp.py
index 0014a9d..ca0bbc8 100644
--- a/pyanaconda/ntp.py
+++ b/pyanaconda/ntp.py
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2012  Red Hat, Inc.
+# Copyright (C) 2012-2013  Red Hat, Inc.
 #
 # This copyrighted material is made available to anyone wishing to use,
 # modify, copy, or redistribute it subject to the terms and conditions of
@@ -27,8 +27,10 @@ import re
 import os
 import tempfile
 import shutil
+import ntplib
+import socket
 
-from pyanaconda import iutil
+from pyanaconda import isys
 from pyanaconda.threads import threadMgr, AnacondaThread
 from pyanaconda.constants import THREAD_SYNC_TIME_BASENAME
 
@@ -44,19 +46,25 @@ class NTPconfigError(Exception):
 
 def ntp_server_working(server):
     """
-    Runs ntpdate to try to connect to the $server (timeout may take some time).
+    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
     :return: True if the given server is reachable and working, False otherwise
+    :rtype: bool
 
     """
 
-    #FIXME: It would be nice to use execWithRedirect here, but it is not
-    #       thread-safe and hangs if this function is called from threads.
-    #       By using tee (and block-buffered pipes) it is also much slower.
-    #we just need to know the exit status
-    retc = os.system("ntpdate -q %s &>/dev/null" % server)
+    client = ntplib.NTPClient()
 
-    return retc == 0
+    try:
+        client.request(server)
+    except ntplib.NTPException:
+        return False
+    except socket.gaierror:
+        return False
+
+    return True
 
 def get_servers_from_config(conf_file_path=NTP_CONFIG_FILE,
                             srv_regexp=SRV_LINE_REGEXP):
@@ -164,9 +172,15 @@ def one_time_sync(server, callback=None):
 
     """
 
-    ret = iutil.execWithRedirect("ntpdate", [server])
-
-    success = ret == 0
+    client = ntplib.NTPClient()
+    try:
+        results = client.request(server)
+        isys.set_system_time(int(results.tx_time))
+        success = True
+    except ntplib.NTPException:
+        success = False
+    except socket.gaierror:
+        success = False
 
     if callback is not None:
         callback(success)
-- 
1.7.11.7



More information about the anaconda-patches mailing list