From bf932a852b7621fb93af3ab47cf6e10c86b7731e Mon Sep 17 00:00:00 2001 From: John McDonough Date: Fri, 29 Jun 2018 09:43:52 -0400 Subject: [PATCH] Module for UCSM Manager Timezone Management (#36974) * Module for UCSM Manager Timezone Management * Module for UCSM Manager Timezone Management * Module for UCSM Manager Timezone Management * Addressed PR comments and added integration tests * fixed mismatched default value between doc and argument_spec * changed main() to call run_module() * Change version to 2.7 * updated integration aliases indicating unsupported testing * updates to DOCUMENTATION --- .../remote_management/ucs/ucs_timezone.py | 165 ++++++++++++++++++ test/integration/targets/ucs_timezone/aliases | 7 + .../targets/ucs_timezone/tasks/main.yml | 126 +++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 lib/ansible/modules/remote_management/ucs/ucs_timezone.py create mode 100644 test/integration/targets/ucs_timezone/aliases create mode 100644 test/integration/targets/ucs_timezone/tasks/main.yml diff --git a/lib/ansible/modules/remote_management/ucs/ucs_timezone.py b/lib/ansible/modules/remote_management/ucs/ucs_timezone.py new file mode 100644 index 0000000000..4e28b49df5 --- /dev/null +++ b/lib/ansible/modules/remote_management/ucs/ucs_timezone.py @@ -0,0 +1,165 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# 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': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = r''' +--- +module: ucs_timezone +short_description: Configures timezone on Cisco UCS Manager +description: +- Configures timezone on Cisco UCS Manager. +- Examples can be used with the L(UCS Platform Emulator,https://communities.cisco.com/ucspe). +extends_documentation_fragment: ucs +options: + state: + description: + - If C(absent), will unset timezone. + - If C(present), will set or update timezone. + choices: [absent, present] + default: present + + admin_state: + description: + - The admin_state setting + - The enabled admin_state indicates the timezone confguration is utilized by UCS Manager. + - The disabled admin_state indicates the timezone confguration is ignored by UCS Manager. + choices: [disabled, enabled] + default: enabled + + description: + description: + - A user-defined description of the timezone. + - Enter up to 256 characters. + - "You can use any characters or spaces except the following:" + - "` (accent mark), \ (backslash), ^ (carat), \" (double quote), = (equal sign), > (greater than), < (less than), or ' (single quote)." + aliases: [ descr ] + default: "" + + timezone: + description: + - The timezone name. + - Time zone names are from the L(tz database,https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) + - The timezone name is case sensitive. + - The timezone name can be between 0 and 510 alphanumeric characters. + - You cannot use spaces or any special characters other than + - "\"-\" (hyphen), \"_\" (underscore), \"/\" (backslash)." + +requirements: +- ucsmsdk +author: +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.7' +''' + +EXAMPLES = r''' +- name: Configure Time Zone + ucs_timezone: + hostname: 172.16.143.150 + username: admin + password: password + state: present + admin_state: enabled + timezone: America/Los_Angeles + description: 'Time Zone for Los Angeles' + +- name: Unconfigure Time Zone + ucs_timezone: + hostname: 172.16.143.150 + username: admin + password: password + state: absent + admin_state: disabled +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.remote_management.ucs import UCSModule, ucs_argument_spec + + +def run_module(): + argument_spec = ucs_argument_spec + argument_spec.update( + timezone=dict(type='str'), + description=dict(type='str', aliases=['descr'], default=''), + admin_state=dict(type='str', default='enabled', choices=['disabled', 'enabled']), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['timezone']], + ], + ) + ucs = UCSModule(module) + + err = False + + changed = False + try: + mo_exists = False + props_match = False + + dn = 'sys/svc-ext/datetime-svc' + + mo = ucs.login_handle.query_dn(dn) + if mo: + mo_exists = True + + if module.params['state'] == 'absent': + # mo must exist but all properties do not have to match + if mo_exists: + if not module.check_mode: + mo.timezone = "" + mo.descr = "" + ucs.login_handle.add_mo(mo, modify_present=True) + ucs.login_handle.commit() + changed = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(descr=module.params['description']) + kwargs['timezone'] = module.params['timezone'] + kwargs['admin_state'] = module.params['admin_state'] + if mo.check_prop_match(**kwargs): + props_match = True + + if not props_match: + if not module.check_mode: + # update mo, timezone mo always exists + mo.timezone = module.params['timezone'] + mo.descr = module.params['description'] + mo.admin_state = module.params['admin_state'] + ucs.login_handle.add_mo(mo, modify_present=True) + ucs.login_handle.commit() + changed = True + + except Exception as e: + err = True + ucs.result['msg'] = "setup error: %s " % str(e) + + ucs.result['changed'] = changed + if err: + module.fail_json(**ucs.result) + module.exit_json(**ucs.result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/ucs_timezone/aliases b/test/integration/targets/ucs_timezone/aliases new file mode 100644 index 0000000000..16a714d47a --- /dev/null +++ b/test/integration/targets/ucs_timezone/aliases @@ -0,0 +1,7 @@ +# Not enabled, but can be used with the UCS Platform Emulator or UCS hardware. +# Example integration_config.yml: +# --- +# ucs_hostname: 172.22.251.170 +# ucs_username: admin +# ucs_password: password +unsupported \ No newline at end of file diff --git a/test/integration/targets/ucs_timezone/tasks/main.yml b/test/integration/targets/ucs_timezone/tasks/main.yml new file mode 100644 index 0000000000..c51aa202a5 --- /dev/null +++ b/test/integration/targets/ucs_timezone/tasks/main.yml @@ -0,0 +1,126 @@ +# Test code for the UCS modules +# Copyright 2018, John McDonough (@movinalot) + +- name: Test that we have a UCS host, UCS username, and UCS password + fail: + msg: 'Please define the following variables: ucs_hostname, ucs_username and ucs_password.' + when: ucs_hostname is not defined or ucs_username is not defined or ucs_password is not defined + vars: + login_info: &login_info + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + + +# Setup (clean environment) +- name: Timezone absent + ucs_timezone: &timezone_absent + <<: *login_info + state: absent + + +# Test present (check_mode) +- name: Timezone present (check_mode) + ucs_timezone: &timezone_present + <<: *login_info + timezone: America/Los_Angeles + description: Timezone for America/Los_Angeles + check_mode: yes + register: cm_timezone_present + + +# Present (normal mode) +- name: Timezone present (normal mode) + ucs_timezone: *timezone_present + register: nm_timezone_present + + +# Test present again (idempotent) +- name: Timezone present again (check_mode) + ucs_timezone: *timezone_present + check_mode: yes + register: cm_timezone_present_again + + +# Present again (normal mode) +- name: Timezone present again (normal mode) + ucs_timezone: *timezone_present + register: nm_timezone_present_again + + +# Verfiy present +- name: Verify Timezone present results + assert: + that: + - cm_timezone_present.changed == nm_timezone_present.changed == true + - cm_timezone_present_again.changed == nm_timezone_present_again.changed == false + + +# Test change (check_mode) +- name: Timezone description change (check_mode) + ucs_timezone: &timezone_change + <<: *timezone_present + descr: Testing Ansible + check_mode: yes + register: cm_timezone_descr_change + + +# Change (normal mode) +- name: Timezone description change (normal mode) + ucs_timezone: *timezone_change + register: nm_timezone_descr_change + + +# Test change again (idempotent) +- name: Timezone description again (check_mode) + ucs_timezone: *timezone_change + check_mode: yes + register: cm_timezone_descr_change_again + + +# Change again (normal mode) +- name: Timezone description change again (normal mode) + ucs_timezone: *timezone_change + register: nm_timezone_descr_change_again + + +# Verfiy change +- name: Verify Timezone change results + assert: + that: + - cm_timezone_descr_change.changed == nm_timezone_descr_change.changed == true + - cm_timezone_descr_change_again.changed == nm_timezone_descr_change_again.changed == false + + +# Teardown (clean environment) +- name: Timezone absent (check_mode) + ucs_timezone: *timezone_absent + check_mode: yes + register: cm_timezone_absent + + +# Absent (normal mode) +- name: Timezone absent (normal mode) + ucs_timezone: *timezone_absent + register: nm_timezone_absent + + +# Test absent again (idempotent) +- name: Timezone absent again (check_mode) + ucs_timezone: *timezone_absent + check_mode: yes + register: cm_timezone_absent_again + + +# Absent again (normal mode) +- name: Timezone absent again (normal mode) + ucs_timezone: *timezone_absent + register: nm_timezone_absent_again + + +# Verfiy absent +- name: Verify Timezone absent results + assert: + that: + - cm_timezone_absent.changed == nm_timezone_absent.changed == true + - cm_timezone_absent_again.changed == nm_timezone_absent_again.changed == false \ No newline at end of file