mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Add support for OpenBSD and SmartOS to timezone module
This commit is contained in:
parent
a560a2d512
commit
e9038d8dc1
1 changed files with 128 additions and 8 deletions
|
@ -19,7 +19,11 @@
|
|||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, get_platform
|
||||
from ansible.module_utils.six import iteritems
|
||||
|
||||
|
@ -34,12 +38,15 @@ module: timezone
|
|||
short_description: Configure timezone setting
|
||||
description:
|
||||
- This module configures the timezone setting, both of the system clock
|
||||
and of the hardware clock. I(Currently only the Linux platform is supported).
|
||||
and of the hardware clock. I(Currently only Linux, OpenBSD and SmartOS
|
||||
instances are supported.)
|
||||
It is recommended to restart C(crond) after changing the timezone,
|
||||
otherwise the jobs may run at the wrong time.
|
||||
It uses the C(timedatectl) command if available. Otherwise, it edits
|
||||
C(/etc/sysconfig/clock) or C(/etc/timezone) for the system clock,
|
||||
On Linux it uses the C(timedatectl) command if available. Otherwise,
|
||||
it edits C(/etc/sysconfig/clock) or C(/etc/timezone) for the system clock,
|
||||
and uses the C(hwclock) command for the hardware clock.
|
||||
On SmartOS the C(sm-set-timezone) utility is used to set the zone timezone,
|
||||
and on OpenBSD C(/etc/localtime) is modified.
|
||||
If you want to set up the NTP, use M(service) module.
|
||||
version_added: "2.2"
|
||||
options:
|
||||
|
@ -56,9 +63,12 @@ options:
|
|||
Note that this option is recommended not to change and may fail
|
||||
to configure, especially on virtual environments such as AWS.
|
||||
B(At least one of name and hwclock are required.)
|
||||
I(Only used on Linux.)
|
||||
required: false
|
||||
aliases: ['rtc']
|
||||
author: "Shinichi TAMURA (@tmshn)"
|
||||
author:
|
||||
- "Shinichi TAMURA (@tmshn)"
|
||||
- "Jasper Lievisse Adriaanse (@jasperla)"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
|
@ -93,8 +103,8 @@ class Timezone(object):
|
|||
def __new__(cls, module):
|
||||
"""Return the platform-specific subclass.
|
||||
|
||||
It does not use load_platform_subclass() because it need to judge based
|
||||
on whether the `timedatectl` command exists and available.
|
||||
It does not use load_platform_subclass() because it needs to judge based
|
||||
on whether the `timedatectl` command exists and is available.
|
||||
|
||||
Args:
|
||||
module: The AnsibleModule.
|
||||
|
@ -105,6 +115,14 @@ class Timezone(object):
|
|||
return super(Timezone, SystemdTimezone).__new__(SystemdTimezone)
|
||||
else:
|
||||
return super(Timezone, NosystemdTimezone).__new__(NosystemdTimezone)
|
||||
elif re.match('^joyent_.*Z', platform.version()):
|
||||
# get_platform() returns SunOS, which is too broad. So look at the
|
||||
# platform version instead.
|
||||
return super(Timezone, SmartOSTimezone).__new__(SmartOSTimezone)
|
||||
elif re.match('^OpenBSD', platform.platform()):
|
||||
# This might be too specific for now, however it can then serve as
|
||||
# a generic base for /etc/localtime honoring Unix-like systems.
|
||||
return super(Timezone, OpenBSDTimezone).__new__(OpenBSDTimezone)
|
||||
else:
|
||||
# Not supported yet
|
||||
return super(Timezone, Timezone).__new__(Timezone)
|
||||
|
@ -430,12 +448,114 @@ class NosystemdTimezone(Timezone):
|
|||
self.abort('unknown parameter "%s"' % key)
|
||||
|
||||
|
||||
class SmartOSTimezone(Timezone):
|
||||
"""This is a Timezone manipulation class for SmartOS instances.
|
||||
|
||||
It uses the C(sm-set-timezone) utility to set the timezone, and
|
||||
inspects C(/etc/default/init) to determine the current timezone.
|
||||
|
||||
NB: A zone needs to be rebooted in order for the change to be
|
||||
activated.
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
super(SmartOSTimezone, self).__init__(module)
|
||||
self.settimezone = self.module.get_bin_path('sm-set-timezone', required=True)
|
||||
|
||||
def get(self, key, phase):
|
||||
"""Lookup the current timezone name in `/etc/default/init`. If anything else
|
||||
is requested, or if the TZ field is not set we fail.
|
||||
"""
|
||||
if key == 'name':
|
||||
try:
|
||||
f = open('/etc/default/init', 'r')
|
||||
for line in f:
|
||||
m = re.match('^TZ=(.*)$', line.strip())
|
||||
if m:
|
||||
return m.groups()[0]
|
||||
except:
|
||||
self.module.fail_json(msg='Failed to read /etc/default/init')
|
||||
else:
|
||||
self.module.fail_json(msg='{0} is not a supported option on target platform'.format(key))
|
||||
|
||||
def set(self, key, value):
|
||||
"""Set the requested timezone through sm-set-timezone, an invalid timezone name
|
||||
will be rejected and we have no further input validation to perform.
|
||||
"""
|
||||
if key == 'name':
|
||||
cmd = 'sm-set-timezone {0}'.format(value)
|
||||
|
||||
(rc, stdout, stderr) = self.module.run_command(cmd)
|
||||
|
||||
if rc != 0:
|
||||
self.module.fail_json(msg=stderr)
|
||||
|
||||
# sm-set-timezone knows no state and will always set the timezone.
|
||||
# XXX: https://github.com/joyent/smtools/pull/2
|
||||
m = re.match('^\* Changed (to)? timezone (to)? ({0}).*'.format(value), stdout.splitlines()[1])
|
||||
if not (m and m.groups()[-1] == value):
|
||||
self.module.fail_json(msg='Failed to set timezone')
|
||||
else:
|
||||
self.module.fail_json(msg='{0} is not a supported option on target platform'.
|
||||
format(key))
|
||||
|
||||
|
||||
class OpenBSDTimezone(Timezone):
|
||||
"""This is the timezone implementation for OpenBSD which works simply through
|
||||
updating the `/etc/localtime` symlink to point to a valid timezone name under
|
||||
`/usr/share/zoneinfo`.
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
super(OpenBSDTimezone, self).__init__(module)
|
||||
|
||||
def get(self, key, phase):
|
||||
"""Lookup the current timezone by resolving `/etc/localtime`."""
|
||||
if key == 'name':
|
||||
try:
|
||||
tz = os.readlink('/etc/localtime')
|
||||
return tz.replace('/usr/share/zoneinfo/', '')
|
||||
except:
|
||||
self.module.fail_json(msg='Could not read /etc/localtime')
|
||||
else:
|
||||
self.module.fail_json(msg='{0} is not a supported option on target platform'.
|
||||
format(key))
|
||||
|
||||
def set(self, key, value):
|
||||
if key == 'name':
|
||||
# First determine if the requested timezone is valid by looking in
|
||||
# the zoneinfo directory.
|
||||
zonefile = '/usr/share/zoneinfo/' + value
|
||||
try:
|
||||
if not os.path.isfile(zonefile):
|
||||
self.module.fail_json(msg='{0} is not a recognized timezone'.format(value))
|
||||
except:
|
||||
self.module.fail_json(msg='Failed to stat {0}'.format(zonefile))
|
||||
|
||||
# Now (somewhat) atomically update the symlink by creating a new
|
||||
# symlink and move it into place. Otherwise we have to remove the
|
||||
# original symlink and create the new symlink, however that would
|
||||
# create a race condition in case another process tries to read
|
||||
# /etc/localtime between removal and creation.
|
||||
suffix = "".join([random.choice(string.ascii_letters + string.digits) for x in range(0, 10)])
|
||||
new_localtime = '/etc/localtime.' + suffix
|
||||
|
||||
try:
|
||||
os.symlink(zonefile, new_localtime)
|
||||
os.rename(new_localtime, '/etc/localtime')
|
||||
except:
|
||||
os.remove(new_localtime)
|
||||
self.module.fail_json(msg='Could not update /etc/localtime')
|
||||
else:
|
||||
self.module.fail_json(msg='{0} is not a supported option on target platform'.format(key))
|
||||
|
||||
|
||||
def main():
|
||||
# Construct 'module' and 'tz'
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
hwclock=dict(default=None, choices=['UTC', 'local'], aliases=['rtc']),
|
||||
name=dict(default=None),
|
||||
hwclock=dict(choices=['UTC', 'local'], aliases=['rtc']),
|
||||
name=dict(),
|
||||
),
|
||||
required_one_of=[['hwclock', 'name']],
|
||||
supports_check_mode=True
|
||||
|
|
Loading…
Reference in a new issue