From 9c83640d75a047aa20c5cf3b9324265eef50d9b0 Mon Sep 17 00:00:00 2001 From: John McDonough Date: Thu, 8 Nov 2018 05:50:46 -0500 Subject: [PATCH] Add module for UCS Org (#46785) * Add module for UCS DNS Server --- .../modules/remote_management/ucs/ucs_org.py | 220 ++++++++++++++++++ test/integration/targets/ucs_org/aliases | 7 + .../targets/ucs_org/tasks/main.yml | 123 ++++++++++ 3 files changed, 350 insertions(+) create mode 100644 lib/ansible/modules/remote_management/ucs/ucs_org.py create mode 100644 test/integration/targets/ucs_org/aliases create mode 100644 test/integration/targets/ucs_org/tasks/main.yml diff --git a/lib/ansible/modules/remote_management/ucs/ucs_org.py b/lib/ansible/modules/remote_management/ucs/ucs_org.py new file mode 100644 index 00000000000..27a0f0e90c6 --- /dev/null +++ b/lib/ansible/modules/remote_management/ucs/ucs_org.py @@ -0,0 +1,220 @@ +#!/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_org + +short_description: Manages UCS Organizations for UCS Manager + +description: + - Manages UCS Organizations for 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 remove organization. + - If C(present), will create or update organization. + choices: [absent, present] + default: present + type: str + + org_name: + description: + - The name of the orgranization. + - Enter up to 16 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: [ name ] + type: str + + parent_org_path: + description: + - A forward slash / separated hierarchical path from the root organization to the parent of the organization to be added or updated. + - UCS Manager supports a hierarchical structure of organizations up to five levels deep not including the root organization. + - For example the parent_org_path for an organization named level5 could be root/level1/level2/level3/level4/level5 + default: root + type: str + + description: + description: + - A user-defined description of the organization. + - 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 ] + type: str + + delegate_to: + description: + - Where the module will be run + default: localhost + type: str + +requirements: + - ucsmsdk + +author: + - John McDonough (@movinalot) + - CiscoUcs (@CiscoUcs) +version_added: "2.8" +''' + +EXAMPLES = r''' +- name: Add UCS Organization + ucs_org: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + org_name: test + description: testing org + state: present + delegate_to: localhost + +- name: Update UCS Organization + ucs_org: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + org_name: test + description: Testing org + state: present + delegate_to: localhost + +- name: Add UCS Organization + ucs_org: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + org_name: level1 + parent_org_path: root + description: level1 org + state: present + delegate_to: localhost + +- name: Add UCS Organization + ucs_org: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + org_name: level2 + parent_org_path: root/level1 + description: level2 org + state: present + +- name: Add UCS Organization + ucs_org: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + org_name: level3 + parent_org_path: root/level1/level2 + description: level3 org + state: present + +- name: Remove UCS Organization + ucs_org: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + org_name: level2 + parent_org_path: root/level1/ + state: absent +''' + +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( + org_name=dict(type='str', aliases=['name']), + parent_org_path=dict(type='str', default='root'), + description=dict(type='str', aliases=['descr'], default=''), + state=dict(type='str', default='present', choices=['present', 'absent']), + delegate_to=dict(type='str', default='localhost'), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['org_name']], + ], + ) + + # UCSModule verifies ucsmsdk is present and exits on failure. + # Imports are below for UCS object creation. + ucs = UCSModule(module) + from ucsmsdk.mometa.org.OrgOrg import OrgOrg + + err = False + changed = False + + try: + mo_exists = False + props_match = False + + parent_org_dn = 'org-' + module.params['parent_org_path'].replace('/', '/org-') + dn = parent_org_dn + '/org-' + module.params['org_name'] + + mo = ucs.login_handle.query_dn(dn) + if mo: + mo_exists = True + + if module.params['state'] == 'absent': + if mo_exists: + if not module.check_mode: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(descr=module.params['description']) + if mo.check_prop_match(**kwargs): + props_match = True + + if not props_match: + if not module.check_mode: + # update/add mo + mo = OrgOrg(parent_mo_or_dn=parent_org_dn, + name=module.params['org_name'], + descr=module.params['description']) + 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_org/aliases b/test/integration/targets/ucs_org/aliases new file mode 100644 index 00000000000..0689fba3e4a --- /dev/null +++ b/test/integration/targets/ucs_org/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.16.143.136 +# ucs_username: admin +# ucs_password: password +unsupported diff --git a/test/integration/targets/ucs_org/tasks/main.yml b/test/integration/targets/ucs_org/tasks/main.yml new file mode 100644 index 00000000000..13c0294d295 --- /dev/null +++ b/test/integration/targets/ucs_org/tasks/main.yml @@ -0,0 +1,123 @@ +# Test code for the UCS Org module +# 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 + <<: *login_info + +# Setup (clean environment) +- name: org absent + ucs_org: &org_absent + <<: *login_info + org_name: testorg + state: absent + + +# Test present (check_mode) +- name: org present (check_mode) + ucs_org: &org_present + <<: *login_info + org_name: testorg + check_mode: yes + register: cm_org_present + + +# Present (normal mode) +- name: org present (normal mode) + ucs_org: *org_present + register: nm_org_present + + +# Test present again (idempotent) +- name: org present again (check_mode) + ucs_org: *org_present + check_mode: yes + register: cm_org_present_again + + +# Present again (normal mode) +- name: org present again (normal mode) + ucs_org: *org_present + register: nm_org_present_again + + +# Verfiy present +- name: Verify org present results + assert: + that: + - cm_org_present.changed == nm_org_present.changed == true + - cm_org_present_again.changed == nm_org_present_again.changed == false + + +# Test change (check_mode) +- name: org description change (check_mode) + ucs_org: &org_change + <<: *org_present + description: 'testorg' + check_mode: yes + register: cm_org_description_change + + +# Change (normal mode) +- name: org description change (normal mode) + ucs_org: *org_change + register: nm_org_description_change + + +# Test change again (idempotent) +- name: org description change again (check_mode) + ucs_org: *org_change + check_mode: yes + register: cm_org_description_change_again + + +# Change again (normal mode) +- name: org description change again (normal mode) + ucs_org: *org_change + register: nm_org_description_change_again + + +# Verfiy change +- name: Verify org change results + assert: + that: + - cm_org_description_change.changed == nm_org_description_change.changed == true + - cm_org_description_change_again.changed == nm_org_description_change_again.changed == false + + +# Teardown (clean environment) +- name: org absent (check_mode) + ucs_org: *org_absent + check_mode: yes + register: cm_org_absent + + +# Absent (normal mode) +- name: org absent (normal mode) + ucs_org: *org_absent + register: nm_org_absent + + +# Test absent again (idempotent) +- name: org absent again (check_mode) + ucs_org: *org_absent + check_mode: yes + register: cm_org_absent_again + + +# Absent again (normal mode) +- name: org absent again (normal mode) + ucs_org: *org_absent + register: nm_org_absent_again + + +# Verfiy absent +- name: Verify org absent results + assert: + that: + - cm_org_absent.changed == nm_org_absent.changed == true + - cm_org_absent_again.changed == nm_org_absent_again.changed == false