timezone - Add AIX support using chtz (#58838)

* init AIX support

* fix pylint whitespace issues

* Switch chtz from required=False to True

* Refactor AIX to include _get_timezone()

* More Pylint...
This commit is contained in:
d-little 2019-07-15 14:52:51 -05:00 committed by ansibot
parent 7cbd06f3a3
commit ee71a7df74

View file

@ -21,9 +21,11 @@ description:
- Several different tools are used depending on the OS/Distribution involved.
For Linux it can use C(timedatectl) or edit C(/etc/sysconfig/clock) or C(/etc/timezone) and C(hwclock).
On SmartOS, C(sm-set-timezone), for macOS, C(systemsetup), for BSD, C(/etc/localtime) is modified.
On AIX, C(chtz) is used.
- As of Ansible 2.3 support was added for SmartOS and BSDs.
- As of Ansible 2.4 support was added for macOS.
- Windows, AIX and HPUX are not supported, please let us know if you find any other OS/distro in which this fails.
- As of Ansible 2.9 support was added for AIX 6.1+
- Windows and HPUX are not supported, please let us know if you find any other OS/distro in which this fails.
version_added: "2.2"
options:
name:
@ -45,6 +47,8 @@ options:
choices: [ local, UTC ]
notes:
- On SmartOS the C(sm-set-timezone) utility (part of the smtools package) is required to set the zone timezone
- On AIX only Olson/tz database timezones are useable (POSIX is not supported).
- An OS reboot is also required on AIX for the new timezone setting to take effect.
author:
- Shinichi TAMURA (@tmshn)
- Jasper Lievisse Adriaanse (@jasperla)
@ -126,6 +130,12 @@ class Timezone(object):
return super(Timezone, DarwinTimezone).__new__(DarwinTimezone)
elif re.match('^(Free|Net|Open)BSD', platform.platform()):
return super(Timezone, BSDTimezone).__new__(BSDTimezone)
elif platform.system() == 'AIX':
AIXoslevel = int(platform.version() + platform.release())
if AIXoslevel >= 61:
return super(Timezone, AIXTimezone).__new__(AIXTimezone)
else:
module.fail_json(msg='AIX os level must be >= 61 for timezone module (Target: %s).' % AIXoslevel)
else:
# Not supported yet
return super(Timezone, Timezone).__new__(Timezone)
@ -768,6 +778,94 @@ class BSDTimezone(Timezone):
self.module.fail_json(msg='%s is not a supported option on target platform' % key)
class AIXTimezone(Timezone):
"""This is a Timezone manipulation class for AIX instances.
It uses the C(chtz) utility to set the timezone, and
inspects C(/etc/environment) to determine the current timezone.
While AIX time zones can be set using two formats (POSIX and
Olson) the prefered method is Olson.
See the following article for more information:
https://developer.ibm.com/articles/au-aix-posix/
NB: AIX needs to be rebooted in order for the change to be
activated.
"""
def __init__(self, module):
super(AIXTimezone, self).__init__(module)
self.settimezone = self.module.get_bin_path('chtz', required=True)
def __get_timezone(self):
""" Return the current value of TZ= in /etc/environment """
try:
f = open('/etc/environment', 'r')
etcenvironment = f.read()
f.close()
except Exception:
self.module.fail_json(msg='Issue reading contents of /etc/environment')
match = re.search(r'^TZ=(.*)$', etcenvironment, re.MULTILINE)
if match:
return match.group(1)
else:
return None
def get(self, key, phase):
"""Lookup the current timezone name in `/etc/environment`. If anything else
is requested, or if the TZ field is not set we fail.
"""
if key == 'name':
return self.__get_timezone()
else:
self.module.fail_json(msg='%s is not a supported option on target platform' % key)
def set(self, key, value):
"""Set the requested timezone through chtz, an invalid timezone name
will be rejected and we have no further input validation to perform.
"""
if key == 'name':
# chtz seems to always return 0 on AIX 7.2, even for invalid timezone values.
# It will only return non-zero if the chtz command itself fails, it does not check for
# valid timezones. We need to perform a basic check to confirm that the timezone
# definition exists in /usr/share/lib/zoneinfo
# This does mean that we can only support Olson for now. The below commented out regex
# detects Olson date formats, so in the future we could detect Posix or Olson and
# act accordingly.
# regex_olson = re.compile('^([a-z0-9_\-\+]+\/?)+$', re.IGNORECASE)
# if not regex_olson.match(value):
# msg = 'Supplied timezone (%s) does not appear to a be valid Olson string' % value
# self.module.fail_json(msg=msg)
# First determine if the requested timezone is valid by looking in the zoneinfo
# directory.
zonefile = '/usr/share/lib/zoneinfo/' + value
try:
if not os.path.isfile(zonefile):
self.module.fail_json(msg='%s is not a recognized timezone.' % value)
except Exception:
self.module.fail_json(msg='Failed to check %s.' % zonefile)
# Now set the TZ using chtz
cmd = 'chtz %s' % value
(rc, stdout, stderr) = self.module.run_command(cmd)
if rc != 0:
self.module.fail_json(msg=stderr)
# The best condition check we can do is to check the value of TZ after making the
# change.
TZ = self.__get_timezone()
if TZ != value:
msg = 'TZ value does not match post-change (Actual: %s, Expected: %s).' % (TZ, value)
self.module.fail_json(msg=msg)
else:
self.module.fail_json(msg='%s is not a supported option on target platform' % key)
def main():
# Construct 'module' and 'tz'
module = AnsibleModule(