mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Improve timezone module for none systemd Linux distributions (#38032)
* The module now correctly sets the timezone in both the config file and in /etc/localtime; while hwclock is set in both the config and /etc/adjtime. * Module checks if the timezone is actually set by checking /etc/localtime. Before it only checked if it was set in the config file. * Fixed module not setting the timezone on RedHat systems if /etc/localtime was a symbolic link. * Fixed module failures in case of missing config files or incorrect data in them. * Added a lot of integrations tests to cover most of these situations.
This commit is contained in:
parent
4a6161bab8
commit
de57fa71c1
3 changed files with 736 additions and 49 deletions
|
@ -40,6 +40,7 @@ options:
|
||||||
B(At least one of name and hwclock are required.)
|
B(At least one of name and hwclock are required.)
|
||||||
I(Only used on Linux.)
|
I(Only used on Linux.)
|
||||||
aliases: [ rtc ]
|
aliases: [ rtc ]
|
||||||
|
choices: [ "UTC", "local" ]
|
||||||
notes:
|
notes:
|
||||||
- On SmartOS the C(sm-set-timezone) utility (part of the smtools package) is required to set the zone timezone
|
- On SmartOS the C(sm-set-timezone) utility (part of the smtools package) is required to set the zone timezone
|
||||||
author:
|
author:
|
||||||
|
@ -75,8 +76,9 @@ import platform
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
|
import filecmp
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule, get_platform
|
from ansible.module_utils.basic import AnsibleModule, get_platform, get_distribution
|
||||||
from ansible.module_utils.six import iteritems
|
from ansible.module_utils.six import iteritems
|
||||||
|
|
||||||
|
|
||||||
|
@ -318,7 +320,12 @@ class NosystemdTimezone(Timezone):
|
||||||
adjtime='/etc/adjtime'
|
adjtime='/etc/adjtime'
|
||||||
)
|
)
|
||||||
|
|
||||||
allow_no_file = dict()
|
# It's fine if all tree config files don't exist
|
||||||
|
allow_no_file = dict(
|
||||||
|
name=True,
|
||||||
|
hwclock=True,
|
||||||
|
adjtime=True
|
||||||
|
)
|
||||||
|
|
||||||
regexps = dict(
|
regexps = dict(
|
||||||
name=None, # To be set in __init__
|
name=None, # To be set in __init__
|
||||||
|
@ -326,47 +333,77 @@ class NosystemdTimezone(Timezone):
|
||||||
adjtime=re.compile(r'^(UTC|LOCAL)$', re.MULTILINE)
|
adjtime=re.compile(r'^(UTC|LOCAL)$', re.MULTILINE)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dist_regexps = dict(
|
||||||
|
SuSE=re.compile(r'^TIMEZONE\s*=\s*"?([^"\s]+)"?', re.MULTILINE),
|
||||||
|
redhat=re.compile(r'^ZONE\s*=\s*"?([^"\s]+)"?', re.MULTILINE)
|
||||||
|
)
|
||||||
|
|
||||||
|
dist_tzline_format = dict(
|
||||||
|
SuSE='TIMEZONE="%s"\n',
|
||||||
|
redhat='ZONE="%s"\n'
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
super(NosystemdTimezone, self).__init__(module)
|
super(NosystemdTimezone, self).__init__(module)
|
||||||
# Validate given timezone
|
# Validate given timezone
|
||||||
if 'name' in self.value:
|
if 'name' in self.value:
|
||||||
tzfile = self._verify_timezone()
|
tzfile = self._verify_timezone()
|
||||||
self.update_timezone = ['%s %s /etc/localtime' % (self.module.get_bin_path('cp', required=True), tzfile)]
|
# `--remove-destination` is needed if /etc/localtime is a symlink so
|
||||||
|
# that it overwrites it instead of following it.
|
||||||
|
self.update_timezone = ['%s --remove-destination %s /etc/localtime' % (self.module.get_bin_path('cp', required=True), tzfile)]
|
||||||
self.update_hwclock = self.module.get_bin_path('hwclock', required=True)
|
self.update_hwclock = self.module.get_bin_path('hwclock', required=True)
|
||||||
self.allow_no_file['hwclock'] = True # Since this is only used for get values, file absense does not metter
|
|
||||||
# Distribution-specific configurations
|
# Distribution-specific configurations
|
||||||
if self.module.get_bin_path('dpkg-reconfigure') is not None:
|
if self.module.get_bin_path('dpkg-reconfigure') is not None:
|
||||||
# Debian/Ubuntu
|
# Debian/Ubuntu
|
||||||
self.update_timezone = ['%s -sf %s /etc/localtime' % (self.module.get_bin_path('ln', required=True), tzfile),
|
if 'name' in self.value:
|
||||||
'%s --frontend noninteractive tzdata' % self.module.get_bin_path('dpkg-reconfigure', required=True)]
|
self.update_timezone = ['%s -sf %s /etc/localtime' % (self.module.get_bin_path('ln', required=True), tzfile),
|
||||||
|
'%s --frontend noninteractive tzdata' % self.module.get_bin_path('dpkg-reconfigure', required=True)]
|
||||||
self.conf_files['name'] = '/etc/timezone'
|
self.conf_files['name'] = '/etc/timezone'
|
||||||
self.allow_no_file['name'] = True
|
|
||||||
self.conf_files['hwclock'] = '/etc/default/rcS'
|
self.conf_files['hwclock'] = '/etc/default/rcS'
|
||||||
self.regexps['name'] = re.compile(r'^([^\s]+)', re.MULTILINE)
|
self.regexps['name'] = re.compile(r'^([^\s]+)', re.MULTILINE)
|
||||||
self.tzline_format = '%s\n'
|
self.tzline_format = '%s\n'
|
||||||
else:
|
else:
|
||||||
# RHEL/CentOS/SUSE
|
# RHEL/CentOS/SUSE
|
||||||
if self.module.get_bin_path('tzdata-update') is not None:
|
if self.module.get_bin_path('tzdata-update') is not None:
|
||||||
self.update_timezone = [self.module.get_bin_path('tzdata-update', required=True)]
|
# tzdata-update cannot update the timezone if /etc/localtime is
|
||||||
self.allow_no_file['name'] = True
|
# a symlink so we have to use cp to update the time zone which
|
||||||
# else:
|
# was set above.
|
||||||
# self.update_timezone = 'cp ...' <- configured above
|
if not os.path.islink('/etc/localtime'):
|
||||||
# self.allow_no_file['name'] = False <- this is default behavior
|
self.update_timezone = [self.module.get_bin_path('tzdata-update', required=True)]
|
||||||
|
# else:
|
||||||
|
# self.update_timezone = 'cp --remove-destination ...' <- configured above
|
||||||
self.conf_files['name'] = '/etc/sysconfig/clock'
|
self.conf_files['name'] = '/etc/sysconfig/clock'
|
||||||
self.conf_files['hwclock'] = '/etc/sysconfig/clock'
|
self.conf_files['hwclock'] = '/etc/sysconfig/clock'
|
||||||
# The key for timezone might be `ZONE` or `TIMEZONE`
|
try:
|
||||||
# (the former is used in RHEL/CentOS and the latter is used in SUSE linux).
|
f = open(self.conf_files['name'], 'r')
|
||||||
# So check the content of /etc/sysconfig/clock and decide which key to use.
|
except IOError as err:
|
||||||
with open(self.conf_files['name'], mode='r') as f:
|
if self._allow_ioerror(err, 'name'):
|
||||||
sysconfig_clock = f.read()
|
# If the config file doesn't exist detect the distribution and set regexps.
|
||||||
if re.search(r'^TIMEZONE\s*=', sysconfig_clock, re.MULTILINE):
|
distribution = get_distribution()
|
||||||
# For SUSE
|
if distribution == 'SuSE':
|
||||||
self.regexps['name'] = re.compile(r'^TIMEZONE\s*=\s*"?([^"\s]+)"?', re.MULTILINE)
|
# For SUSE
|
||||||
self.tzline_format = 'TIMEZONE="%s"\n'
|
self.regexps['name'] = self.dist_regexps['SuSE']
|
||||||
|
self.tzline_format = self.dist_tzline_format['SuSE']
|
||||||
|
else:
|
||||||
|
# For RHEL/CentOS
|
||||||
|
self.regexps['name'] = self.dist_regexps['redhat']
|
||||||
|
self.tzline_format = self.dist_tzline_format['redhat']
|
||||||
|
else:
|
||||||
|
self.abort('could not read configuration file "%s"' % self.conf_files['name'])
|
||||||
else:
|
else:
|
||||||
# For RHEL/CentOS
|
# The key for timezone might be `ZONE` or `TIMEZONE`
|
||||||
self.regexps['name'] = re.compile(r'^ZONE\s*=\s*"?([^"\s]+)"?', re.MULTILINE)
|
# (the former is used in RHEL/CentOS and the latter is used in SUSE linux).
|
||||||
self.tzline_format = 'ZONE="%s"\n'
|
# So check the content of /etc/sysconfig/clock and decide which key to use.
|
||||||
|
sysconfig_clock = f.read()
|
||||||
|
f.close()
|
||||||
|
if re.search(r'^TIMEZONE\s*=', sysconfig_clock, re.MULTILINE):
|
||||||
|
# For SUSE
|
||||||
|
self.regexps['name'] = self.dist_regexps['SuSE']
|
||||||
|
self.tzline_format = self.dist_tzline_format['SuSE']
|
||||||
|
else:
|
||||||
|
# For RHEL/CentOS
|
||||||
|
self.regexps['name'] = self.dist_regexps['redhat']
|
||||||
|
self.tzline_format = self.dist_tzline_format['redhat']
|
||||||
|
|
||||||
def _allow_ioerror(self, err, key):
|
def _allow_ioerror(self, err, key):
|
||||||
# In some cases, even if the target file does not exist,
|
# In some cases, even if the target file does not exist,
|
||||||
|
@ -424,18 +461,18 @@ class NosystemdTimezone(Timezone):
|
||||||
file.close()
|
file.close()
|
||||||
self.msg.append('Added 1 line and deleted %s line(s) on %s' % (len(matched_indices), filename))
|
self.msg.append('Added 1 line and deleted %s line(s) on %s' % (len(matched_indices), filename))
|
||||||
|
|
||||||
def get(self, key, phase):
|
def _get_value_from_config(self, key, phase):
|
||||||
if key == 'hwclock' and os.path.isfile('/etc/adjtime'):
|
|
||||||
# If /etc/adjtime exists, use that file.
|
|
||||||
key = 'adjtime'
|
|
||||||
|
|
||||||
filename = self.conf_files[key]
|
filename = self.conf_files[key]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
file = open(filename, mode='r')
|
file = open(filename, mode='r')
|
||||||
except IOError as err:
|
except IOError as err:
|
||||||
if self._allow_ioerror(err, key):
|
if self._allow_ioerror(err, key):
|
||||||
return None
|
if key == 'hwclock':
|
||||||
|
return 'n/a'
|
||||||
|
elif key == 'adjtime':
|
||||||
|
return 'UTC'
|
||||||
|
elif key == 'name':
|
||||||
|
return 'n/a'
|
||||||
else:
|
else:
|
||||||
self.abort('tried to configure %s using a file "%s", but could not read it' % (key, filename))
|
self.abort('tried to configure %s using a file "%s", but could not read it' % (key, filename))
|
||||||
else:
|
else:
|
||||||
|
@ -444,19 +481,77 @@ class NosystemdTimezone(Timezone):
|
||||||
try:
|
try:
|
||||||
value = self.regexps[key].search(status).group(1)
|
value = self.regexps[key].search(status).group(1)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.abort('tried to configure %s using a file "%s", but could not find a valid value in it' % (key, filename))
|
if key == 'hwclock':
|
||||||
|
# If we cannot find UTC in the config that's fine.
|
||||||
|
return 'n/a'
|
||||||
|
elif key == 'adjtime':
|
||||||
|
# If we cannot find UTC/LOCAL in /etc/cannot that means UTC
|
||||||
|
# will be used by default.
|
||||||
|
return 'UTC'
|
||||||
|
elif key == 'name':
|
||||||
|
if phase == 'before':
|
||||||
|
# In 'before' phase UTC/LOCAL doesn't need to be set in
|
||||||
|
# the timezone config file, so we ignore this error.
|
||||||
|
return 'n/a'
|
||||||
|
else:
|
||||||
|
self.abort('tried to configure %s using a file "%s", but could not find a valid value in it' % (key, filename))
|
||||||
else:
|
else:
|
||||||
if key == 'hwclock':
|
if key == 'hwclock':
|
||||||
# For key='hwclock'; convert yes/no -> UTC/local
|
# convert yes/no -> UTC/local
|
||||||
if self.module.boolean(value):
|
if self.module.boolean(value):
|
||||||
value = 'UTC'
|
value = 'UTC'
|
||||||
else:
|
else:
|
||||||
value = 'local'
|
value = 'local'
|
||||||
elif key == 'adjtime':
|
elif key == 'adjtime':
|
||||||
# For key='adjtime'; convert LOCAL -> local
|
# convert LOCAL -> local
|
||||||
if value != 'UTC':
|
if value != 'UTC':
|
||||||
value = value.lower()
|
value = value.lower()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def get(self, key, phase):
|
||||||
|
planned = self.value[key]['planned']
|
||||||
|
if key == 'hwclock':
|
||||||
|
value = self._get_value_from_config(key, phase)
|
||||||
|
if value == planned:
|
||||||
|
# If the value in the config file is the same as the 'planned'
|
||||||
|
# value, we need to check /etc/adjtime.
|
||||||
|
value = self._get_value_from_config('adjtime', phase)
|
||||||
|
elif key == 'name':
|
||||||
|
value = self._get_value_from_config(key, phase)
|
||||||
|
if value == planned:
|
||||||
|
# If the planned values is the same as the one in the config file
|
||||||
|
# we need to check if /etc/localtime is also set to the 'planned' zone.
|
||||||
|
if os.path.islink('/etc/localtime'):
|
||||||
|
# If /etc/localtime is a symlink and is not set to the TZ we 'planned'
|
||||||
|
# to set, we need to return the TZ which the symlink points to.
|
||||||
|
if os.path.exists('/etc/localtime'):
|
||||||
|
# We use readlink() because on some distros zone files are symlinks
|
||||||
|
# to other zone files, so it's hard to get which TZ is actually set
|
||||||
|
# if we follow the symlink.
|
||||||
|
path = os.readlink('/etc/localtime')
|
||||||
|
linktz = re.search(r'/usr/share/zoneinfo/(.*)', path, re.MULTILINE)
|
||||||
|
if linktz:
|
||||||
|
valuelink = linktz.group(1)
|
||||||
|
if valuelink != planned:
|
||||||
|
value = valuelink
|
||||||
|
else:
|
||||||
|
# Set current TZ to 'n/a' if the symlink points to a path
|
||||||
|
# which isn't a zone file.
|
||||||
|
value = 'n/a'
|
||||||
|
else:
|
||||||
|
# Set current TZ to 'n/a' if the symlink to the zone file is broken.
|
||||||
|
value = 'n/a'
|
||||||
|
else:
|
||||||
|
# If /etc/localtime is not a symlink best we can do is compare it with
|
||||||
|
# the 'planned' zone info file and return 'n/a' if they are different.
|
||||||
|
try:
|
||||||
|
if not filecmp.cmp('/etc/localtime', '/usr/share/zoneinfo/' + planned):
|
||||||
|
return 'n/a'
|
||||||
|
except:
|
||||||
|
return 'n/a'
|
||||||
|
else:
|
||||||
|
self.abort('unknown parameter "%s"' % key)
|
||||||
|
return value
|
||||||
|
|
||||||
def set_timezone(self, value):
|
def set_timezone(self, value):
|
||||||
self._edit_file(filename=self.conf_files['name'],
|
self._edit_file(filename=self.conf_files['name'],
|
||||||
|
@ -469,8 +564,15 @@ class NosystemdTimezone(Timezone):
|
||||||
def set_hwclock(self, value):
|
def set_hwclock(self, value):
|
||||||
if value == 'local':
|
if value == 'local':
|
||||||
option = '--localtime'
|
option = '--localtime'
|
||||||
|
utc = 'no'
|
||||||
else:
|
else:
|
||||||
option = '--utc'
|
option = '--utc'
|
||||||
|
utc = 'yes'
|
||||||
|
if self.conf_files['hwclock'] is not None:
|
||||||
|
self._edit_file(filename=self.conf_files['hwclock'],
|
||||||
|
regexp=self.regexps['hwclock'],
|
||||||
|
value='UTC=%s\n' % utc,
|
||||||
|
key='hwclock')
|
||||||
self.execute(self.update_hwclock, '--systohc', option, log=True)
|
self.execute(self.update_hwclock, '--systohc', option, log=True)
|
||||||
|
|
||||||
def set(self, key, value):
|
def set(self, key, value):
|
||||||
|
|
|
@ -1,21 +1,607 @@
|
||||||
- name: Set timezone to Etc/UTC
|
# Because hwclock usually isn't available inside Docker containers in Shippable
|
||||||
|
# these tasks will detect if hwclock works and only run hwclock tests if it is
|
||||||
|
# supported. That is why it is recommended to run these tests locally with
|
||||||
|
# `--docker-privileged` on centos6, centos7 and ubuntu1404 images. Example
|
||||||
|
# command to run on centos6:
|
||||||
|
#
|
||||||
|
# ansible-test integration --docker centos6 --docker-privileged -v timezone
|
||||||
|
|
||||||
|
####
|
||||||
|
#### timezone tests
|
||||||
|
####
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## set path to timezone config files
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: set config file path on Debian
|
||||||
|
set_fact:
|
||||||
|
timezone_config_file: '/etc/timezone'
|
||||||
|
when: ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: set config file path on RedHat
|
||||||
|
set_fact:
|
||||||
|
timezone_config_file: '/etc/sysconfig/clock'
|
||||||
|
when: ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## set path to hwclock config files
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: set config file path on Debian
|
||||||
|
set_fact:
|
||||||
|
hwclock_config_file: '/etc/default/rcS'
|
||||||
|
when: ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: set config file path on RedHat
|
||||||
|
set_fact:
|
||||||
|
hwclock_config_file: '/etc/sysconfig/clock'
|
||||||
|
when: ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test setting timezone, idempotency and checkmode
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: set timezone to Etc/UTC
|
||||||
timezone:
|
timezone:
|
||||||
name: Etc/UTC
|
name: Etc/UTC
|
||||||
register: original_timezone
|
register: original_timezone
|
||||||
|
|
||||||
- block:
|
- name: set timezone to Australia/Brisbane (checkmode)
|
||||||
- name: Set timezone to Australia/Brisbane
|
timezone:
|
||||||
timezone:
|
name: Australia/Brisbane
|
||||||
name: Australia/Brisbane
|
check_mode: yes
|
||||||
register: timezone_set
|
register: timezone_set_checkmode
|
||||||
|
|
||||||
- name: Ensure timezone changed
|
- name: ensure timezone reported as changed in checkmode
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- timezone_set_checkmode.changed
|
||||||
|
- timezone_set_checkmode.diff.after.name == 'Australia/Brisbane'
|
||||||
|
- timezone_set_checkmode.diff.before.name == 'Etc/UTC'
|
||||||
|
|
||||||
|
- name: ensure checkmode didn't change the timezone
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Australia/Brisbane
|
||||||
|
register: result
|
||||||
|
failed_when: result is not failed
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: ensure that checkmode didn't update the timezone in the config file
|
||||||
|
command: egrep '^(TIME)?ZONE="Etc/UTC"' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_service_mgr != 'systemd'
|
||||||
|
- ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
- name: ensure that checkmode didn't update the timezone in the config file
|
||||||
|
command: egrep '^Etc/UTC' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_service_mgr != 'systemd'
|
||||||
|
- ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: set timezone to Australia/Brisbane
|
||||||
|
timezone:
|
||||||
|
name: Australia/Brisbane
|
||||||
|
register: timezone_set
|
||||||
|
|
||||||
|
- name: ensure timezone changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- timezone_set.changed
|
||||||
|
- timezone_set.diff.after.name == 'Australia/Brisbane'
|
||||||
|
- timezone_set.diff.before.name == 'Etc/UTC'
|
||||||
|
|
||||||
|
- name: ensure that the timezone is actually set
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Australia/Brisbane
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: ensure that the timezone is updated in the config file
|
||||||
|
command: egrep '^(TIME)?ZONE="Australia/Brisbane"' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_service_mgr != 'systemd'
|
||||||
|
- ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
- name: ensure that the timezone is updated in the config file
|
||||||
|
command: egrep '^Australia/Brisbane' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_service_mgr != 'systemd'
|
||||||
|
- ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: set timezone to Australia/Brisbane again
|
||||||
|
timezone:
|
||||||
|
name: Australia/Brisbane
|
||||||
|
register: timezone_again
|
||||||
|
|
||||||
|
- name: ensure timezone idempotency
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not timezone_again.changed
|
||||||
|
|
||||||
|
- name: set timezone to Australia/Brisbane again in checkmode
|
||||||
|
timezone:
|
||||||
|
name: Australia/Brisbane
|
||||||
|
register: timezone_again_checkmode
|
||||||
|
|
||||||
|
- name: set timezone idempotency (checkmode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not timezone_again_checkmode.changed
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## no systemd tests for timezone
|
||||||
|
##
|
||||||
|
|
||||||
|
- block:
|
||||||
|
##
|
||||||
|
## test with empty config file
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: empty config file
|
||||||
|
command: cp /dev/null {{ timezone_config_file }}
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade (empty config file)
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
register: timezone_empty_conf
|
||||||
|
|
||||||
|
- name: check if timezone set (empty config file)
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- timezone_set is changed
|
- timezone_empty_conf.changed
|
||||||
- timezone_set.diff.after.name == 'Australia/Brisbane'
|
- timezone_empty_conf.diff.after.name == 'Europe/Belgrade'
|
||||||
- timezone_set.diff.before.name == 'Etc/UTC'
|
- timezone_empty_conf.diff.before.name == 'n/a'
|
||||||
always:
|
|
||||||
- name: Restore original system timezone - {{ original_timezone.diff.before.name }}
|
- name: check if the timezone is actually set (empty config file)
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Europe/Belgrade
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test with deleted config file
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: remove config file
|
||||||
|
file:
|
||||||
|
path: '{{ timezone_config_file }}'
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade (no config file)
|
||||||
timezone:
|
timezone:
|
||||||
name: "{{ original_timezone.diff.before.name }}"
|
name: Europe/Belgrade
|
||||||
|
register: timezone_missing_conf
|
||||||
|
|
||||||
|
- name: check if timezone set (no config file)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- timezone_missing_conf.changed
|
||||||
|
- timezone_missing_conf.diff.after.name == 'Europe/Belgrade'
|
||||||
|
- timezone_missing_conf.diff.before.name == 'n/a'
|
||||||
|
|
||||||
|
- name: check if the timezone is actually set (no config file)
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Europe/Belgrade
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test with /etc/localtime as symbolic link to a zoneinfo file
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: create symlink /etc/locatime -> /usr/share/zoneinfo/Etc/UTC
|
||||||
|
file:
|
||||||
|
src: /usr/share/zoneinfo/Etc/UTC
|
||||||
|
dest: /etc/localtime
|
||||||
|
state: link
|
||||||
|
force: yes
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade (over symlink)
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
register: timezone_symllink
|
||||||
|
|
||||||
|
- name: check if timezone set (over symlink)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- timezone_symllink.changed
|
||||||
|
- timezone_symllink.diff.after.name == 'Europe/Belgrade'
|
||||||
|
- timezone_symllink.diff.before.name == 'Etc/UTC'
|
||||||
|
|
||||||
|
- name: check if the timezone is actually set (over symlink)
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Europe/Belgrade
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test with /etc/localtime as broken symbolic link
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: set timezone to a broken symlink
|
||||||
|
file:
|
||||||
|
src: /tmp/foo
|
||||||
|
dest: /etc/localtime
|
||||||
|
state: link
|
||||||
|
force: yes
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade (over broken symlink)
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
register: timezone_symllink_broken
|
||||||
|
|
||||||
|
- name: check if timezone set (over broken symlink)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- timezone_symllink_broken.changed
|
||||||
|
- timezone_symllink_broken.diff.after.name == 'Europe/Belgrade'
|
||||||
|
- timezone_symllink_broken.diff.before.name == 'n/a'
|
||||||
|
|
||||||
|
- name: check if the timezone is actually set (over broken symlink)
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Europe/Belgrade
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test with /etc/localtime set manually using copy
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: set timezone manually by coping zone info file to /etc/localtime
|
||||||
|
copy:
|
||||||
|
src: /usr/share/zoneinfo/Etc/UTC
|
||||||
|
dest: /etc/localtime
|
||||||
|
remote_src: yes
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade (over copied file)
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
register: timezone_copied
|
||||||
|
|
||||||
|
- name: check if timezone set (over copied file)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- timezone_copied.changed
|
||||||
|
- timezone_copied.diff.after.name == 'Europe/Belgrade'
|
||||||
|
- timezone_copied.diff.before.name == 'n/a'
|
||||||
|
|
||||||
|
- name: check if the timezone is actually set (over copied file)
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Europe/Belgrade
|
||||||
|
changed_when: no
|
||||||
|
when:
|
||||||
|
- ansible_service_mgr != 'systemd'
|
||||||
|
- timezone_config_file is defined
|
||||||
|
|
||||||
|
|
||||||
|
####
|
||||||
|
#### hwclock tests
|
||||||
|
####
|
||||||
|
|
||||||
|
- name: check if hwclock is supported in the environment
|
||||||
|
command: hwclock --test
|
||||||
|
register: hwclock_test
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: check if timedatectl works in the environment
|
||||||
|
command: timedatectl
|
||||||
|
register: timedatectl_test
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name:
|
||||||
|
set_fact:
|
||||||
|
hwclock_supported: '{{ hwclock_test is successful or timedatectl_test is successful }}'
|
||||||
|
##
|
||||||
|
## test set hwclock, idempotency and checkmode
|
||||||
|
##
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: set hwclock to local
|
||||||
|
timezone:
|
||||||
|
hwclock: local
|
||||||
|
|
||||||
|
- name: set hwclock to UTC (checkmode)
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
check_mode: yes
|
||||||
|
register: hwclock_set_checkmode
|
||||||
|
|
||||||
|
- name: ensure hwclock reported as changed (checkmode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- hwclock_set_checkmode.changed
|
||||||
|
- hwclock_set_checkmode.diff.after.hwclock == 'UTC'
|
||||||
|
- hwclock_set_checkmode.diff.before.hwclock == 'local'
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: ensure that checkmode didn't update hwclock in /etc/adjtime
|
||||||
|
command: grep ^UTC /etc/adjtime
|
||||||
|
register: result
|
||||||
|
failed_when: result is not failed
|
||||||
|
|
||||||
|
- name: ensure that checkmode didn't update hwclock the config file
|
||||||
|
command: grep ^UTC=no {{ hwclock_config_file }}
|
||||||
|
when: ansible_service_mgr != 'systemd'
|
||||||
|
|
||||||
|
- name: set hwclock to UTC
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
register: hwclock_set
|
||||||
|
|
||||||
|
- name: ensure hwclock changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- hwclock_set.changed
|
||||||
|
- hwclock_set.diff.after.hwclock == 'UTC'
|
||||||
|
- hwclock_set.diff.before.hwclock == 'local'
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: ensure that hwclock is updated in /etc/adjtime
|
||||||
|
command: grep ^UTC /etc/adjtime
|
||||||
|
|
||||||
|
- name: ensure that hwclock is updated in the config file
|
||||||
|
command: grep ^UTC=yes {{ hwclock_config_file }}
|
||||||
|
when: ansible_service_mgr != 'systemd'
|
||||||
|
|
||||||
|
- name: set hwclock to RTC again
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
register: hwclock_again
|
||||||
|
|
||||||
|
- name: set hwclock idempotency
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not hwclock_again.changed
|
||||||
|
|
||||||
|
- name: set hwclock to RTC again (checkmode)
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
check_mode: yes
|
||||||
|
register: hwclock_again_checkmode
|
||||||
|
|
||||||
|
- name: set hwclock idempotency (checkmode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not hwclock_again_checkmode.changed
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## no systemd tests for hwclock
|
||||||
|
##
|
||||||
|
|
||||||
|
- block:
|
||||||
|
##
|
||||||
|
## test set hwclock with both /etc/adjtime and conf file deleted
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: remove /etc/adjtime and conf file
|
||||||
|
file:
|
||||||
|
path: '{{ item }}'
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- /etc/adjtime
|
||||||
|
- '{{ hwclock_config_file }}'
|
||||||
|
|
||||||
|
- name: set hwclock to UTC with deleted /etc/adjtime and conf file
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
register: hwclock_set_utc_deleted_adjtime_and_conf
|
||||||
|
|
||||||
|
- name: ensure hwclock changed with deleted /etc/adjtime and conf
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- hwclock_set_utc_deleted_adjtime_and_conf.changed
|
||||||
|
- hwclock_set_utc_deleted_adjtime_and_conf.diff.after.hwclock == 'UTC'
|
||||||
|
- hwclock_set_utc_deleted_adjtime_and_conf.diff.before.hwclock == 'n/a'
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test set hwclock with /etc/adjtime deleted
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: remove /etc/adjtime
|
||||||
|
file:
|
||||||
|
path: '{{ item }}'
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- /etc/adjtime
|
||||||
|
|
||||||
|
- name: set hwclock to UTC with deleted /etc/adjtime
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
register: hwclock_set_utc_deleted_adjtime_utc
|
||||||
|
|
||||||
|
- name: ensure hwclock changed with deleted /etc/adjtime
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not hwclock_set_utc_deleted_adjtime_utc.changed
|
||||||
|
- hwclock_set_utc_deleted_adjtime_utc.diff.after.hwclock == 'UTC'
|
||||||
|
- hwclock_set_utc_deleted_adjtime_utc.diff.before.hwclock == 'UTC'
|
||||||
|
|
||||||
|
- name: set hwclock to LOCAL with deleted /etc/adjtime
|
||||||
|
timezone:
|
||||||
|
hwclock: local
|
||||||
|
register: hwclock_set_local_deleted_adjtime_local
|
||||||
|
|
||||||
|
- name: ensure hwclock changed to LOCAL with deleted /etc/adjtime
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- hwclock_set_local_deleted_adjtime_local.changed
|
||||||
|
- hwclock_set_local_deleted_adjtime_local.diff.after.hwclock == 'local'
|
||||||
|
- hwclock_set_local_deleted_adjtime_local.diff.before.hwclock == 'UTC'
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test set hwclock with conf file deleted
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: remove conf file
|
||||||
|
file:
|
||||||
|
path: '{{ item }}'
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- '{{ hwclock_config_file }}'
|
||||||
|
|
||||||
|
- name: set hwclock to UTC with deleted conf
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
register: hwclock_set_utc_deleted_conf
|
||||||
|
|
||||||
|
- name: ensure hwclock changed with deleted /etc/adjtime
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- hwclock_set_utc_deleted_conf.changed
|
||||||
|
- hwclock_set_utc_deleted_conf.diff.after.hwclock == 'UTC'
|
||||||
|
- hwclock_set_utc_deleted_conf.diff.before.hwclock == 'n/a'
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## test set hwclock with /etc/adjtime missing UTC/LOCAL strings
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: create /etc/adjtime without UTC/LOCAL
|
||||||
|
copy:
|
||||||
|
content: '0.0 0 0\n0'
|
||||||
|
dest: /etc/adjtime
|
||||||
|
|
||||||
|
- name: set hwclock to UTC with broken /etc/adjtime
|
||||||
|
timezone:
|
||||||
|
hwclock: UTC
|
||||||
|
register: hwclock_set_utc_broken_adjtime
|
||||||
|
|
||||||
|
- name: ensure hwclock doesn't report changed with broken /etc/adjtime
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not hwclock_set_utc_broken_adjtime.changed
|
||||||
|
- hwclock_set_utc_broken_adjtime.diff.after.hwclock == 'UTC'
|
||||||
|
- hwclock_set_utc_broken_adjtime.diff.before.hwclock == 'UTC'
|
||||||
|
|
||||||
|
- name: set hwclock to LOCAL with broken /etc/adjtime
|
||||||
|
timezone:
|
||||||
|
hwclock: local
|
||||||
|
register: hwclock_set_local_broken_adjtime
|
||||||
|
|
||||||
|
- name: ensure hwclock changed to LOCAL with broken /etc/adjtime
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- hwclock_set_local_broken_adjtime.changed
|
||||||
|
- hwclock_set_local_broken_adjtime.diff.after.hwclock == 'local'
|
||||||
|
- hwclock_set_local_broken_adjtime.diff.before.hwclock == 'UTC'
|
||||||
|
when:
|
||||||
|
- ansible_service_mgr != 'systemd'
|
||||||
|
- hwclock_config_file is defined
|
||||||
|
|
||||||
|
####
|
||||||
|
#### timezone + hwclock tests
|
||||||
|
####
|
||||||
|
|
||||||
|
##
|
||||||
|
## test set timezone and hwclock, idempotency and checkmode
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: set timezone to Etc/UTC and hwclock to local
|
||||||
|
timezone:
|
||||||
|
name: Etc/UTC
|
||||||
|
hwclock: local
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade and hwclock to UTC (checkmode)
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
hwclock: UTC
|
||||||
|
check_mode: yes
|
||||||
|
register: tzclock_set_checkmode
|
||||||
|
|
||||||
|
- name: ensure timezone and hwclock reported as changed in checkmode
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- tzclock_set_checkmode.changed
|
||||||
|
- tzclock_set_checkmode.diff.after.name == 'Europe/Belgrade'
|
||||||
|
- tzclock_set_checkmode.diff.before.name == 'Etc/UTC'
|
||||||
|
- tzclock_set_checkmode.diff.after.hwclock == 'UTC'
|
||||||
|
- tzclock_set_checkmode.diff.before.hwclock == 'local'
|
||||||
|
|
||||||
|
- name: ensure checkmode didn't change the timezone
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Australia/Brisbane
|
||||||
|
register: result
|
||||||
|
failed_when: result is not failed
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: ensure that checkmode didn't update the timezone in the config file
|
||||||
|
command: egrep '^(TIME)?ZONE="Etc/UTC"' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
- name: ensure that checkmode didn't update the timezone in the config file
|
||||||
|
command: egrep '^Etc/UTC' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: ensure that checkmode didn't update hwclock in /etc/adjtime
|
||||||
|
command: grep ^UTC /etc/adjtime
|
||||||
|
register: result
|
||||||
|
failed_when: result is not failed
|
||||||
|
|
||||||
|
- name: ensure that checkmode didn't update hwclock the config file
|
||||||
|
command: grep ^UTC=no {{ hwclock_config_file }}
|
||||||
|
when: ansible_service_mgr != 'systemd'
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade and hwclock to UTC
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
hwclock: UTC
|
||||||
|
register: tzclock_set
|
||||||
|
|
||||||
|
- name: ensure timezone and hwclock changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- tzclock_set.changed
|
||||||
|
- tzclock_set.diff.after.name == 'Europe/Belgrade'
|
||||||
|
- tzclock_set.diff.before.name == 'Etc/UTC'
|
||||||
|
- tzclock_set.diff.after.hwclock == 'UTC'
|
||||||
|
- tzclock_set.diff.before.hwclock == 'local'
|
||||||
|
|
||||||
|
- name: ensure that the timezone is actually set
|
||||||
|
command: cmp /etc/localtime /usr/share/zoneinfo/Europe/Belgrade
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: ensure that the timezone is updated in the config file
|
||||||
|
command: egrep '^(TIME)?ZONE="Europe/Belgrade"' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_os_family == 'RedHat'
|
||||||
|
|
||||||
|
- name: ensure that the timezone is updated in the config file
|
||||||
|
command: egrep 'Europe/Belgrade' {{ timezone_config_file }}
|
||||||
|
when:
|
||||||
|
- ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: ensure that hwclock is updated in /etc/adjtime
|
||||||
|
command: grep ^UTC /etc/adjtime
|
||||||
|
|
||||||
|
- name: ensure that hwclock is updated in the config file
|
||||||
|
command: grep ^UTC=yes {{ hwclock_config_file }}
|
||||||
|
when: ansible_service_mgr != 'systemd'
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade and hwclock to UTC again
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
hwclock: UTC
|
||||||
|
register: tzclock_set_again
|
||||||
|
|
||||||
|
- name: set timezone and hwclock idempotency
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not tzclock_set_again.changed
|
||||||
|
|
||||||
|
- name: set timezone to Europe/Belgrade and hwclock to UTC again (checkmode)
|
||||||
|
timezone:
|
||||||
|
name: Europe/Belgrade
|
||||||
|
hwclock: UTC
|
||||||
|
register: tzclock_set_again_checkmode
|
||||||
|
|
||||||
|
- name: set timezone and hwclock idempotency in checkmode
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not tzclock_set_again_checkmode.changed
|
||||||
|
|
||||||
|
when:
|
||||||
|
- ansible_system == 'Linux'
|
||||||
|
- hwclock_supported
|
||||||
|
|
|
@ -1228,7 +1228,6 @@ lib/ansible/modules/system/service.py E323
|
||||||
lib/ansible/modules/system/solaris_zone.py E324
|
lib/ansible/modules/system/solaris_zone.py E324
|
||||||
lib/ansible/modules/system/svc.py E322
|
lib/ansible/modules/system/svc.py E322
|
||||||
lib/ansible/modules/system/svc.py E324
|
lib/ansible/modules/system/svc.py E324
|
||||||
lib/ansible/modules/system/timezone.py E326
|
|
||||||
lib/ansible/modules/system/ufw.py E322
|
lib/ansible/modules/system/ufw.py E322
|
||||||
lib/ansible/modules/system/ufw.py E326
|
lib/ansible/modules/system/ufw.py E326
|
||||||
lib/ansible/modules/system/user.py E324
|
lib/ansible/modules/system/user.py E324
|
||||||
|
|
Loading…
Reference in a new issue