mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge pull request #26951 from terminalmage/fix-timezone
Fix timezone module for CentOS
This commit is contained in:
commit
fbc95f4685
@ -6,8 +6,10 @@ from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
import os
|
||||
import errno
|
||||
import logging
|
||||
import re
|
||||
import string
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
@ -25,6 +27,67 @@ def __virtual__():
|
||||
return True
|
||||
|
||||
|
||||
def _get_zone_solaris():
|
||||
tzfile = '/etc/TIMEZONE'
|
||||
with salt.utils.fopen(tzfile, 'r') as fp_:
|
||||
for line in fp_:
|
||||
if 'TZ=' in line:
|
||||
zonepart = line.rstrip('\n').split('=')[-1]
|
||||
return zonepart.strip('\'"') or 'UTC'
|
||||
raise CommandExecutionError('Unable to get timezone from ' + tzfile)
|
||||
|
||||
|
||||
def _get_zone_sysconfig():
|
||||
tzfile = '/etc/sysconfig/clock'
|
||||
with salt.utils.fopen(tzfile, 'r') as fp_:
|
||||
for line in fp_:
|
||||
if re.match(r'^\s*#', line):
|
||||
continue
|
||||
if 'ZONE' in line and '=' in line:
|
||||
zonepart = line.rstrip('\n').split('=')[-1]
|
||||
return zonepart.strip('\'"') or 'UTC'
|
||||
raise CommandExecutionError('Unable to get timezone from ' + tzfile)
|
||||
|
||||
|
||||
def _get_zone_etc_localtime():
|
||||
tzfile = '/etc/localtime'
|
||||
tzdir = '/usr/share/zoneinfo/'
|
||||
tzdir_len = len(tzdir)
|
||||
try:
|
||||
olson_name = os.path.normpath(
|
||||
os.path.join('/etc', os.readlink(tzfile))
|
||||
)
|
||||
if olson_name.startswith(tzdir):
|
||||
return olson_name[tzdir_len:]
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.ENOENT:
|
||||
raise CommandExecutionError(tzfile + ' does not exist')
|
||||
elif exc.errno == errno.EINVAL:
|
||||
log.warning(
|
||||
tzfile + ' is not a symbolic link, attempting to match ' +
|
||||
tzfile + ' to zoneinfo files'
|
||||
)
|
||||
# Regular file. Try to match the hash.
|
||||
hash_type = __opts__.get('hash_type', 'md5')
|
||||
tzfile_hash = salt.utils.get_hash(tzfile, hash_type)
|
||||
# Not a link, just a copy of the tzdata file
|
||||
for root, dirs, files in os.walk(tzdir):
|
||||
for filename in files:
|
||||
full_path = os.path.join(root, filename)
|
||||
olson_name = full_path[tzdir_len:]
|
||||
if olson_name[0] in string.ascii_lowercase:
|
||||
continue
|
||||
if tzfile_hash == \
|
||||
salt.utils.get_hash(full_path, hash_type):
|
||||
return olson_name
|
||||
raise CommandExecutionError('Unable to determine timezone')
|
||||
|
||||
|
||||
def _get_zone_etc_timezone():
|
||||
with salt.utils.fopen('/etc/timezone', 'r') as fp_:
|
||||
return fp_.read().strip()
|
||||
|
||||
|
||||
def get_zone():
|
||||
'''
|
||||
Get current timezone (i.e. America/Denver)
|
||||
@ -37,7 +100,7 @@ def get_zone():
|
||||
'''
|
||||
cmd = ''
|
||||
if salt.utils.which('timedatectl'):
|
||||
out = __salt__['cmd.run']('timedatectl')
|
||||
out = __salt__['cmd.run'](['timedatectl'], python_shell=False)
|
||||
for line in (x.strip() for x in out.splitlines()):
|
||||
try:
|
||||
return re.match(r'Time ?zone:\s+(\S+)', line).group(1)
|
||||
@ -46,23 +109,21 @@ def get_zone():
|
||||
raise CommandExecutionError(
|
||||
'Failed to parse timedatectl output, this is likely a bug'
|
||||
)
|
||||
elif 'RedHat' in __grains__['os_family']:
|
||||
cmd = 'grep ZONE /etc/sysconfig/clock | grep -vE "^#"'
|
||||
elif 'Suse' in __grains__['os_family']:
|
||||
cmd = 'grep ZONE /etc/sysconfig/clock | grep -vE "^#"'
|
||||
elif 'Debian' in __grains__['os_family']:
|
||||
with salt.utils.fopen('/etc/timezone', 'r') as ofh:
|
||||
return ofh.read().strip()
|
||||
elif 'Gentoo' in __grains__['os_family']:
|
||||
with salt.utils.fopen('/etc/timezone', 'r') as ofh:
|
||||
return ofh.read().strip()
|
||||
elif __grains__['os_family'] in ('FreeBSD', 'OpenBSD', 'NetBSD'):
|
||||
return os.readlink('/etc/localtime').lstrip('/usr/share/zoneinfo/')
|
||||
elif 'Solaris' in __grains__['os_family']:
|
||||
cmd = 'grep "TZ=" /etc/TIMEZONE'
|
||||
out = __salt__['cmd.run'](cmd, python_shell=True).split('=')
|
||||
ret = out[1].replace('"', '')
|
||||
return ret
|
||||
else:
|
||||
if __grains__['os'].lower() == 'centos':
|
||||
return _get_zone_etc_localtime()
|
||||
os_family = __grains__['os_family']
|
||||
for family in ('RedHat', 'Suse'):
|
||||
if family in os_family:
|
||||
return _get_zone_sysconfig()
|
||||
for family in ('Debian', 'Gentoo'):
|
||||
if family in os_family:
|
||||
return _get_zone_etc_timezone()
|
||||
if os_family in ('FreeBSD', 'OpenBSD', 'NetBSD'):
|
||||
return _get_zone_etc_localtime()
|
||||
elif 'Solaris' in os_family:
|
||||
return _get_zone_solaris()
|
||||
raise CommandExecutionError('Unable to get timezone')
|
||||
|
||||
|
||||
def get_zonecode():
|
||||
@ -75,9 +136,7 @@ def get_zonecode():
|
||||
|
||||
salt '*' timezone.get_zonecode
|
||||
'''
|
||||
cmd = 'date +%Z'
|
||||
out = __salt__['cmd.run'](cmd)
|
||||
return out
|
||||
return __salt__['cmd.run'](['date', '+%Z'], python_shell=False)
|
||||
|
||||
|
||||
def get_offset():
|
||||
@ -90,9 +149,7 @@ def get_offset():
|
||||
|
||||
salt '*' timezone.get_offset
|
||||
'''
|
||||
cmd = 'date +%z'
|
||||
out = __salt__['cmd.run'](cmd)
|
||||
return out
|
||||
return __salt__['cmd.run'](['date', '+%z'], python_shell=False)
|
||||
|
||||
|
||||
def set_zone(timezone):
|
||||
@ -101,7 +158,8 @@ def set_zone(timezone):
|
||||
|
||||
The timezone is crucial to several system processes, each of which SHOULD
|
||||
be restarted (for instance, whatever you system uses as its cron and
|
||||
syslog daemons). This will not be magically done for you!
|
||||
syslog daemons). This will not be automagically done and must be done
|
||||
manually!
|
||||
|
||||
CLI Example:
|
||||
|
||||
@ -195,7 +253,7 @@ def get_hwclock():
|
||||
'''
|
||||
cmd = ''
|
||||
if salt.utils.which('timedatectl'):
|
||||
out = __salt__['cmd.run']('timedatectl')
|
||||
out = __salt__['cmd.run'](['timedatectl'], python_shell=False)
|
||||
for line in (x.strip() for x in out.splitlines()):
|
||||
if 'rtc in local tz' in line.lower():
|
||||
try:
|
||||
@ -208,39 +266,64 @@ def get_hwclock():
|
||||
raise CommandExecutionError(
|
||||
'Failed to parse timedatectl output, this is likely a bug'
|
||||
)
|
||||
elif 'RedHat' in __grains__['os_family']:
|
||||
cmd = 'tail -n 1 /etc/adjtime'
|
||||
return __salt__['cmd.run'](cmd)
|
||||
elif 'Suse' in __grains__['os_family']:
|
||||
cmd = 'tail -n 1 /etc/adjtime'
|
||||
return __salt__['cmd.run'](cmd)
|
||||
elif 'Debian' in __grains__['os_family']:
|
||||
#Original way to look up hwclock on Debian-based systems
|
||||
cmd = 'grep "UTC=" /etc/default/rcS | grep -vE "^#"'
|
||||
out = __salt__['cmd.run'](
|
||||
cmd, ignore_retcode=True, python_shell=True).split('=')
|
||||
if len(out) > 1:
|
||||
if out[1] == 'yes':
|
||||
return 'UTC'
|
||||
else:
|
||||
return 'localtime'
|
||||
else:
|
||||
#Since Wheezy
|
||||
cmd = 'tail -n 1 /etc/adjtime'
|
||||
return __salt__['cmd.run'](cmd)
|
||||
elif 'Gentoo' in __grains__['os_family']:
|
||||
cmd = 'grep "^clock=" /etc/conf.d/hwclock | grep -vE "^#"'
|
||||
out = __salt__['cmd.run'](cmd, python_shell=True).split('=')
|
||||
return out[1].replace('"', '')
|
||||
elif 'Solaris' in __grains__['os_family']:
|
||||
if os.path.isfile('/etc/rtc_config'):
|
||||
with salt.utils.fopen('/etc/rtc_config', 'r') as fp_:
|
||||
for line in fp_:
|
||||
if line.startswith('zone_info=GMT'):
|
||||
return 'UTC'
|
||||
return 'localtime'
|
||||
else:
|
||||
return 'UTC'
|
||||
else:
|
||||
os_family = __grains__['os_family']
|
||||
for family in ('RedHat', 'Suse'):
|
||||
if family in os_family:
|
||||
cmd = ['tail', '-n', '1', '/etc/adjtime']
|
||||
return __salt__['cmd.run'](cmd, python_shell=False)
|
||||
if 'Debian' in __grains__['os_family']:
|
||||
# Original way to look up hwclock on Debian-based systems
|
||||
try:
|
||||
with salt.utils.fopen('/etc/default/rcS', 'r') as fp_:
|
||||
for line in fp_:
|
||||
if re.match(r'^\s*#', line):
|
||||
continue
|
||||
if 'UTC=' in line:
|
||||
is_utc = line.rstrip('\n').split('=')[-1].lower()
|
||||
if is_utc == 'yes':
|
||||
return 'UTC'
|
||||
else:
|
||||
return 'localtime'
|
||||
except IOError as exc:
|
||||
pass
|
||||
# Since Wheezy
|
||||
cmd = ['tail', '-n', '1', '/etc/adjtime']
|
||||
return __salt__['cmd.run'](cmd, python_shell=False)
|
||||
elif 'Gentoo' in __grains__['os_family']:
|
||||
offset_file = '/etc/conf.d/hwclock'
|
||||
try:
|
||||
with salt.utils.fopen(offset_file, 'r') as fp_:
|
||||
for line in fp_:
|
||||
if line.startswith('clock='):
|
||||
line = line.rstrip('\n')
|
||||
return line.split('=')[-1].strip('\'"')
|
||||
raise CommandExecutionError(
|
||||
'Offset information not found in {0}'.format(
|
||||
offset_file
|
||||
)
|
||||
)
|
||||
except IOError as exc:
|
||||
raise CommandExecutionError(
|
||||
'Problem reading offset file {0}: {1}'
|
||||
.format(offset_file, exc.strerror)
|
||||
)
|
||||
elif 'Solaris' in __grains__['os_family']:
|
||||
offset_file = '/etc/rtc_config'
|
||||
try:
|
||||
with salt.utils.fopen(offset_file, 'r') as fp_:
|
||||
for line in fp_:
|
||||
if line.startswith('zone_info=GMT'):
|
||||
return 'UTC'
|
||||
return 'localtime'
|
||||
except IOError as exc:
|
||||
if exc.errno == errno.ENOENT:
|
||||
# offset file does not exist
|
||||
return 'UTC'
|
||||
raise CommandExecutionError(
|
||||
'Problem reading offset file {0}: {1}'
|
||||
.format(offset_file, exc.strerror)
|
||||
)
|
||||
|
||||
|
||||
def set_hwclock(clock):
|
||||
@ -256,33 +339,31 @@ def set_hwclock(clock):
|
||||
timezone = get_zone()
|
||||
|
||||
if 'Solaris' in __grains__['os_family']:
|
||||
if clock.lower() not in ('localtime', 'utc'):
|
||||
raise SaltInvocationError(
|
||||
'localtime and UTC are the only permitted values'
|
||||
)
|
||||
if 'sparc' in __grains__['cpuarch']:
|
||||
return 'UTC is the only choice for SPARC architecture'
|
||||
if clock == 'localtime':
|
||||
cmd = 'rtc -z {0}'.format(timezone)
|
||||
__salt__['cmd.run'](cmd)
|
||||
return True
|
||||
elif clock == 'UTC':
|
||||
cmd = 'rtc -z GMT'
|
||||
__salt__['cmd.run'](cmd)
|
||||
return True
|
||||
else:
|
||||
zonepath = '/usr/share/zoneinfo/{0}'.format(timezone)
|
||||
raise SaltInvocationError(
|
||||
'UTC is the only choice for SPARC architecture'
|
||||
)
|
||||
cmd = ['rtc', '-z', 'GMT' if clock.lower() == 'utc' else timezone]
|
||||
return __salt__['cmd.retcode'](cmd, python_shell=False) == 0
|
||||
|
||||
zonepath = '/usr/share/zoneinfo/{0}'.format(timezone)
|
||||
|
||||
if not os.path.exists(zonepath):
|
||||
return 'Zone does not exist: {0}'.format(zonepath)
|
||||
raise CommandExecutionError(
|
||||
'Zone \'{0}\' does not exist'.format(zonepath)
|
||||
)
|
||||
|
||||
if 'Solaris' not in __grains__['os_family']:
|
||||
os.unlink('/etc/localtime')
|
||||
os.symlink(zonepath, '/etc/localtime')
|
||||
os.unlink('/etc/localtime')
|
||||
os.symlink(zonepath, '/etc/localtime')
|
||||
|
||||
if 'Arch' in __grains__['os_family']:
|
||||
if clock == 'localtime':
|
||||
cmd = 'timezonectl set-local-rtc true'
|
||||
__salt__['cmd.run'](cmd)
|
||||
else:
|
||||
cmd = 'timezonectl set-local-rtc false'
|
||||
__salt__['cmd.run'](cmd)
|
||||
cmd = ['timezonectl', 'set-local-rtc',
|
||||
'true' if clock == 'localtime' else 'false']
|
||||
return __salt__['cmd.retcode'](cmd, python_shell=False) == 0
|
||||
elif 'RedHat' in __grains__['os_family']:
|
||||
__salt__['file.sed'](
|
||||
'/etc/sysconfig/clock', '^ZONE=.*', 'ZONE="{0}"'.format(timezone))
|
||||
|
@ -22,8 +22,7 @@ ensure_in_syspath('../../')
|
||||
import salt.utils
|
||||
from salt.modules import timezone
|
||||
import os
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.exceptions import SaltInvocationError
|
||||
from salt.exceptions import CommandExecutionError, SaltInvocationError
|
||||
|
||||
|
||||
# Globals
|
||||
@ -53,22 +52,28 @@ class TimezoneTestCase(TestCase):
|
||||
with patch('salt.utils.fopen', mock_open(read_data=file_data),
|
||||
create=True) as mfile:
|
||||
mfile.return_value.__iter__.return_value = file_data.splitlines()
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Debian'}):
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Debian',
|
||||
'os': 'Debian'}):
|
||||
self.assertEqual(timezone.get_zone(), '#\nA')
|
||||
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Gentoo'}):
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Gentoo',
|
||||
'os': 'Gentoo'}):
|
||||
self.assertEqual(timezone.get_zone(), '')
|
||||
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'FreeBSD'}):
|
||||
with patch.object(os, 'readlink',
|
||||
return_value='/usr/share/zoneinfo/'):
|
||||
self.assertEqual(timezone.get_zone(), '')
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'FreeBSD',
|
||||
'os': 'FreeBSD'}):
|
||||
zone = 'America/Denver'
|
||||
linkpath = '/usr/share/zoneinfo/' + zone
|
||||
with patch.object(os, 'readlink', return_value=linkpath):
|
||||
self.assertEqual(timezone.get_zone(), zone)
|
||||
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Solaris'}):
|
||||
with patch.dict(timezone.__salt__,
|
||||
{'cmd.run':
|
||||
MagicMock(return_value='A=B')}):
|
||||
self.assertEqual(timezone.get_zone(), 'B')
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Solaris',
|
||||
'os': 'Solaris'}):
|
||||
fl_data = 'TZ=Foo\n'
|
||||
with patch('salt.utils.fopen',
|
||||
mock_open(read_data=fl_data)) as mfile:
|
||||
mfile.return_value.__iter__.return_value = [fl_data]
|
||||
self.assertEqual(timezone.get_zone(), 'Foo')
|
||||
|
||||
def test_get_zonecode(self):
|
||||
'''
|
||||
@ -171,26 +176,24 @@ class TimezoneTestCase(TestCase):
|
||||
self.assertEqual(timezone.get_hwclock(), 'A')
|
||||
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Debian'}):
|
||||
with patch.dict(timezone.__salt__,
|
||||
{'cmd.run':
|
||||
MagicMock(return_value='A=yes')}):
|
||||
fl_data = 'UTC=yes\n'
|
||||
with patch('salt.utils.fopen',
|
||||
mock_open(read_data=fl_data)) as mfile:
|
||||
mfile.return_value.__iter__.return_value = [fl_data]
|
||||
self.assertEqual(timezone.get_hwclock(), 'UTC')
|
||||
|
||||
with patch.dict(timezone.__salt__,
|
||||
{'cmd.run':
|
||||
MagicMock(return_value='A=no')}):
|
||||
fl_data = 'UTC=no\n'
|
||||
with patch('salt.utils.fopen',
|
||||
mock_open(read_data=fl_data)) as mfile:
|
||||
mfile.return_value.__iter__.return_value = [fl_data]
|
||||
self.assertEqual(timezone.get_hwclock(), 'localtime')
|
||||
|
||||
with patch.dict(timezone.__salt__,
|
||||
{'cmd.run':
|
||||
MagicMock(return_value='A')}):
|
||||
self.assertEqual(timezone.get_hwclock(), 'A')
|
||||
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Gentoo'}):
|
||||
with patch.dict(timezone.__salt__,
|
||||
{'cmd.run':
|
||||
MagicMock(return_value='A=B')}):
|
||||
self.assertEqual(timezone.get_hwclock(), 'B')
|
||||
fl_data = 'clock=UTC\n'
|
||||
with patch('salt.utils.fopen',
|
||||
mock_open(read_data=fl_data)) as mfile:
|
||||
mfile.return_value.__iter__.return_value = [fl_data]
|
||||
self.assertEqual(timezone.get_hwclock(), 'UTC')
|
||||
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.object(os.path, 'isfile', mock):
|
||||
@ -226,31 +229,30 @@ class TimezoneTestCase(TestCase):
|
||||
'''
|
||||
Test to sets the hardware clock to be either UTC or localtime
|
||||
'''
|
||||
ret = ('UTC is the only choice for SPARC architecture')
|
||||
ret1 = ('Zone does not exist: /usr/share/zoneinfo/America/Denver')
|
||||
with patch.object(timezone, 'get_zone',
|
||||
return_value='America/Denver'):
|
||||
zone = 'America/Denver'
|
||||
with patch.object(timezone, 'get_zone', return_value=zone):
|
||||
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Solaris',
|
||||
'cpuarch': 'sparc'}):
|
||||
self.assertEqual(timezone.set_hwclock('clock'), ret)
|
||||
self.assertRaises(
|
||||
SaltInvocationError,
|
||||
timezone.set_hwclock,
|
||||
'clock'
|
||||
)
|
||||
self.assertRaises(
|
||||
SaltInvocationError,
|
||||
timezone.set_hwclock,
|
||||
'localtime'
|
||||
)
|
||||
|
||||
with patch.dict(timezone.__salt__,
|
||||
{'cmd.run':
|
||||
MagicMock(return_value=None)}):
|
||||
self.assertTrue(timezone.set_hwclock('localtime'))
|
||||
|
||||
self.assertTrue(timezone.set_hwclock('UTC'))
|
||||
|
||||
with patch.dict(timezone.__grains__, {'os_family': 'Sola'}):
|
||||
with patch.dict(timezone.__grains__,
|
||||
{'os_family': 'DoesNotMatter'}):
|
||||
with patch.object(os.path, 'exists', return_value=False):
|
||||
self.assertEqual(timezone.set_hwclock('clock'), ret1)
|
||||
|
||||
with patch.object(os.path, 'exists', return_value=True):
|
||||
with patch.object(os, 'unlink', return_value=None):
|
||||
with patch.object(os, 'symlink', return_value=None):
|
||||
self.assertTrue(timezone.set_hwclock('clock'))
|
||||
|
||||
self.assertRaises(
|
||||
CommandExecutionError,
|
||||
timezone.set_hwclock,
|
||||
'UTC'
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
Loading…
Reference in New Issue
Block a user