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/>.
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
|
import string
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule, get_platform
|
from ansible.module_utils.basic import AnsibleModule, get_platform
|
||||||
from ansible.module_utils.six import iteritems
|
from ansible.module_utils.six import iteritems
|
||||||
|
|
||||||
|
@ -34,12 +38,15 @@ module: timezone
|
||||||
short_description: Configure timezone setting
|
short_description: Configure timezone setting
|
||||||
description:
|
description:
|
||||||
- This module configures the timezone setting, both of the system clock
|
- 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,
|
It is recommended to restart C(crond) after changing the timezone,
|
||||||
otherwise the jobs may run at the wrong time.
|
otherwise the jobs may run at the wrong time.
|
||||||
It uses the C(timedatectl) command if available. Otherwise, it edits
|
On Linux it uses the C(timedatectl) command if available. Otherwise,
|
||||||
C(/etc/sysconfig/clock) or C(/etc/timezone) for the system clock,
|
it edits C(/etc/sysconfig/clock) or C(/etc/timezone) for the system clock,
|
||||||
and uses the C(hwclock) command for the hardware 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.
|
If you want to set up the NTP, use M(service) module.
|
||||||
version_added: "2.2"
|
version_added: "2.2"
|
||||||
options:
|
options:
|
||||||
|
@ -56,9 +63,12 @@ options:
|
||||||
Note that this option is recommended not to change and may fail
|
Note that this option is recommended not to change and may fail
|
||||||
to configure, especially on virtual environments such as AWS.
|
to configure, especially on virtual environments such as AWS.
|
||||||
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.)
|
||||||
required: false
|
required: false
|
||||||
aliases: ['rtc']
|
aliases: ['rtc']
|
||||||
author: "Shinichi TAMURA (@tmshn)"
|
author:
|
||||||
|
- "Shinichi TAMURA (@tmshn)"
|
||||||
|
- "Jasper Lievisse Adriaanse (@jasperla)"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = '''
|
RETURN = '''
|
||||||
|
@ -93,8 +103,8 @@ class Timezone(object):
|
||||||
def __new__(cls, module):
|
def __new__(cls, module):
|
||||||
"""Return the platform-specific subclass.
|
"""Return the platform-specific subclass.
|
||||||
|
|
||||||
It does not use load_platform_subclass() because it need to judge based
|
It does not use load_platform_subclass() because it needs to judge based
|
||||||
on whether the `timedatectl` command exists and available.
|
on whether the `timedatectl` command exists and is available.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
module: The AnsibleModule.
|
module: The AnsibleModule.
|
||||||
|
@ -105,6 +115,14 @@ class Timezone(object):
|
||||||
return super(Timezone, SystemdTimezone).__new__(SystemdTimezone)
|
return super(Timezone, SystemdTimezone).__new__(SystemdTimezone)
|
||||||
else:
|
else:
|
||||||
return super(Timezone, NosystemdTimezone).__new__(NosystemdTimezone)
|
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:
|
else:
|
||||||
# Not supported yet
|
# Not supported yet
|
||||||
return super(Timezone, Timezone).__new__(Timezone)
|
return super(Timezone, Timezone).__new__(Timezone)
|
||||||
|
@ -430,12 +448,114 @@ class NosystemdTimezone(Timezone):
|
||||||
self.abort('unknown parameter "%s"' % key)
|
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():
|
def main():
|
||||||
# Construct 'module' and 'tz'
|
# Construct 'module' and 'tz'
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=dict(
|
argument_spec=dict(
|
||||||
hwclock=dict(default=None, choices=['UTC', 'local'], aliases=['rtc']),
|
hwclock=dict(choices=['UTC', 'local'], aliases=['rtc']),
|
||||||
name=dict(default=None),
|
name=dict(),
|
||||||
),
|
),
|
||||||
required_one_of=[['hwclock', 'name']],
|
required_one_of=[['hwclock', 'name']],
|
||||||
supports_check_mode=True
|
supports_check_mode=True
|
||||||
|
|
Loading…
Reference in a new issue