#!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright (c) 2017 F5 Networks Inc. # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['stableinterface'], 'supported_by': 'certified'} DOCUMENTATION = r''' --- module: bigip_device_ntp short_description: Manage NTP servers on a BIG-IP description: - Manage NTP servers on a BIG-IP. version_added: 2.2 options: ntp_servers: description: - A list of NTP servers to set on the device. At least one of C(ntp_servers) or C(timezone) is required. state: description: - The state of the NTP servers on the system. When C(present), guarantees that the NTP servers are set on the system. When C(absent), removes the specified NTP servers from the device configuration. default: present choices: - absent - present timezone: description: - The timezone to set for NTP lookups. At least one of C(ntp_servers) or C(timezone) is required. extends_documentation_fragment: f5 author: - Tim Rupp (@caphrim007) - Wojciech Wypior (@wojtek0806) ''' EXAMPLES = r''' - name: Set NTP server bigip_device_ntp: ntp_servers: - 192.0.2.23 password: secret server: lb.mydomain.com user: admin validate_certs: no delegate_to: localhost - name: Set timezone bigip_device_ntp: password: secret server: lb.mydomain.com timezone: America/Los_Angeles user: admin validate_certs: no delegate_to: localhost ''' RETURN = r''' ntp_servers: description: The NTP servers that were set on the device returned: changed type: list sample: ["192.0.2.23", "192.0.2.42"] timezone: description: The timezone that was set on the device returned: changed type: string sample: true ''' from ansible.module_utils.basic import AnsibleModule try: from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import F5Client from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import AnsibleF5Parameters from library.module_utils.network.f5.common import cleanup_tokens from library.module_utils.network.f5.common import f5_argument_spec try: from library.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False except ImportError: from ansible.module_utils.network.f5.bigip import HAS_F5SDK from ansible.module_utils.network.f5.bigip import F5Client from ansible.module_utils.network.f5.common import F5ModuleError from ansible.module_utils.network.f5.common import AnsibleF5Parameters from ansible.module_utils.network.f5.common import cleanup_tokens from ansible.module_utils.network.f5.common import f5_argument_spec try: from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False class Parameters(AnsibleF5Parameters): api_map = { 'servers': 'ntp_servers' } api_attributes = [ 'servers', 'timezone', ] updatables = [ 'ntp_servers', 'timezone' ] returnables = [ 'ntp_servers', 'timezone' ] absentables = [ 'ntp_servers' ] def to_return(self): result = {} for returnable in self.returnables: result[returnable] = getattr(self, returnable) result = self._filter_params(result) return result class ModuleManager(object): def __init__(self, *args, **kwargs): self.module = kwargs.get('module', None) self.client = kwargs.get('client', None) self.have = None self.want = Parameters(params=self.module.params) self.changes = Parameters() def _update_changed_options(self): changed = {} for key in Parameters.updatables: if getattr(self.want, key) is not None: attr1 = getattr(self.want, key) attr2 = getattr(self.have, key) if attr1 != attr2: changed[key] = attr1 if changed: self.changes = Parameters(params=changed) return True return False def _absent_changed_options(self): changed = {} for key in Parameters.absentables: if getattr(self.want, key) is not None: set_want = set(getattr(self.want, key)) set_have = set(getattr(self.have, key)) if set_want != set_have: changed[key] = list(set_want) if changed: self.changes = Parameters(params=changed) return True return False def exec_module(self): changed = False result = dict() state = self.want.state try: if state == "present": changed = self.update() elif state == "absent": changed = self.absent() except iControlUnexpectedHTTPError as e: raise F5ModuleError(str(e)) changes = self.changes.to_return() result.update(**changes) result.update(dict(changed=changed)) return result def update(self): self.have = self.read_current_from_device() if not self.should_update(): return False if self.module.check_mode: return True self.update_on_device() return True def should_update(self): result = self._update_changed_options() if result: return True return False def should_absent(self): result = self._absent_changed_options() if result: return True return False def absent(self): self.have = self.read_current_from_device() if not self.should_absent(): return False if self.module.check_mode: return True self.absent_on_device() return True def update_on_device(self): params = self.want.api_params() resource = self.client.api.tm.sys.ntp.load() resource.update(**params) def read_current_from_device(self): resource = self.client.api.tm.sys.ntp.load() result = resource.attrs return Parameters(params=result) def absent_on_device(self): params = self.changes.api_params() resource = self.client.api.tm.sys.ntp.load() resource.update(**params) class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True argument_spec = dict( ntp_servers=dict( type='list', ), timezone=dict(), state=dict( default='present', choices=['present', 'absent'] ), ) self.argument_spec = {} self.argument_spec.update(f5_argument_spec) self.argument_spec.update(argument_spec) self.required_one_of = [ ['ntp_servers', 'timezone'] ] def main(): spec = ArgumentSpec() module = AnsibleModule( argument_spec=spec.argument_spec, supports_check_mode=spec.supports_check_mode, required_one_of=spec.required_one_of ) if not HAS_F5SDK: module.fail_json(msg="The python f5-sdk module is required") try: client = F5Client(**module.params) mm = ModuleManager(module=module, client=client) results = mm.exec_module() cleanup_tokens(client) module.exit_json(**results) except F5ModuleError as ex: cleanup_tokens(client) module.fail_json(msg=str(ex)) if __name__ == '__main__': main()