Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

timezone - Add AIX support using chtz #58838

Merged
merged 5 commits into from Jul 15, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
100 changes: 99 additions & 1 deletion lib/ansible/modules/system/timezone.py
Expand Up @@ -21,9 +21,11 @@
- 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:
Expand All @@ -45,6 +47,8 @@
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)
Expand Down Expand Up @@ -126,6 +130,12 @@ def __new__(cls, module):
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)
Expand Down Expand Up @@ -768,6 +778,94 @@ def set(self, key, value):
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(
Expand Down