summaryrefslogtreecommitdiff
path: root/ironic_python_agent/utils.py
diff options
context:
space:
mode:
authorJulia Kreger <juliaashleykreger@gmail.com>2020-02-14 13:45:12 -0800
committerJulia Kreger <juliaashleykreger@gmail.com>2020-03-07 09:16:19 -0800
commitcee4bfc4bc2b038ca5c092aa73b1f9f670b58f66 (patch)
tree654228ecd4c566e6088c441257bc6a7ad1793d22 /ironic_python_agent/utils.py
parent48ef7c918898b7ce679d500270018b831a81ae03 (diff)
downloadironic-python-agent-cee4bfc4bc2b038ca5c092aa73b1f9f670b58f66.tar.gz
Add NTP time sync
Attempt to sync the clock and save it to the hardware clock. This feature supports use of chrony or ntpdate. Sem-Ver: feature Change-Id: I178d7614429d582e742d9cba6d0fa3ae099775e3 Story: 1619054 Task: 11591
Diffstat (limited to 'ironic_python_agent/utils.py')
-rw-r--r--ironic_python_agent/utils.py90
1 files changed, 90 insertions, 0 deletions
diff --git a/ironic_python_agent/utils.py b/ironic_python_agent/utils.py
index 5f1c0dc2..ccbc42f7 100644
--- a/ironic_python_agent/utils.py
+++ b/ironic_python_agent/utils.py
@@ -27,6 +27,7 @@ import time
from ironic_lib import utils as ironic_utils
from oslo_concurrency import processutils
+from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import base64
from oslo_utils import units
@@ -35,6 +36,7 @@ from ironic_python_agent import errors
LOG = logging.getLogger(__name__)
+CONF = cfg.CONF
# Agent parameters can be passed by kernel command-line arguments and/or
# by virtual media. Virtual media parameters passed would be available
@@ -486,3 +488,91 @@ def remove_large_keys(var):
return var.__class__(map(remove_large_keys, var))
else:
return var
+
+
+def determine_time_method():
+ """Helper method to determine what time utility is present.
+
+ :returns: "ntpdate" if ntpdate has been found, "chrony" if chrony
+ was located, and None if neither are located. If both tools
+ are present, "chrony" will supercede "ntpdate".
+ """
+ try:
+ execute('chronyd', '-h')
+ return 'chronyd'
+ except OSError:
+ LOG.debug('Command \'chronyd\' not found for time sync.')
+ try:
+ execute('ntpdate', '-v', check_exit_code=[0, 1])
+ return 'ntpdate'
+ except OSError:
+ LOG.debug('Command \'ntpdate\' not found for time sync.')
+ return None
+
+
+def sync_clock(ignore_errors=False):
+ """Syncs the software clock of the system.
+
+ This method syncs the system software clock if a NTP server
+ was defined in the "[DEFAULT]ntp_server" configuration
+ parameter. This method does NOT attempt to sync the hardware
+ clock.
+
+ It will try to use either ntpdate or chrony to sync the software
+ clock of the system. If neither is found, an exception is raised.
+
+ :param ignore_errors: Boolean value default False that allows for
+ the method to be called and ultimately not
+ raise an exception. This may be useful for
+ opportunistically attempting to sync the
+ system software clock.
+ :raises: CommandExecutionError if an error is encountered while
+ attempting to sync the software clock.
+ """
+
+ if not CONF.ntp_server:
+ return
+
+ method = determine_time_method()
+
+ if method == 'ntpdate':
+ try:
+ execute('ntpdate', CONF.ntp_server)
+ LOG.debug('Set software clock using ntpdate')
+ except processutils.ProcessExecutionError as e:
+ msg = ('Failed to sync with ntp server: '
+ '%s: %s' % (CONF.ntp_server, e))
+ LOG.error(msg)
+ if CONF.fail_if_clock_not_set or not ignore_errors:
+ raise errors.CommandExecutionError(msg)
+ elif method == 'chronyd':
+ try:
+ # 0 should be if chronyd started
+ # 1 if already running
+ execute('chronyd', check_exit_code=[0, 1])
+ # NOTE(TheJulia): Once started, chronyd forks and stays in the
+ # background as a server service, it will continue to keep the
+ # clock in sync.
+ try:
+ execute('chronyc', 'add', 'server', CONF.ntp_server)
+ except processutils.ProcessExecutionError as e:
+ if 'Source already present' not in str(e):
+ msg = 'Error occured adding ntp server: %s' % e
+ LOG.error(msg)
+ raise errors.CommandExecutionError(msg)
+ # Force the clock to sync now.
+ execute('chronyc', 'makestep')
+ LOG.debug('Set software clock using chrony')
+ except (processutils.ProcessExecutionError,
+ errors.CommandExecutionError) as e:
+ msg = ('Failed to sync time using chrony to ntp server: '
+ '%s: %s' % (CONF.ntp_server, e))
+ LOG.error(msg)
+ if CONF.fail_if_clock_not_set or not ignore_errors:
+ raise errors.CommandExecutionError(msg)
+ else:
+ msg = ('Unable to sync clock, available methods of '
+ '\'ntpdate\' or \'chrony\' not found.')
+ LOG.error(msg)
+ if CONF.fail_if_clock_not_set or not ignore_errors:
+ raise errors.CommandExecutionError(msg)