diff options
Diffstat (limited to 'collections-debian-merged/ansible_collections/cisco/ucs/plugins')
32 files changed, 7383 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/README.md b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/README.md new file mode 100644 index 00000000..6541cf7c --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/README.md @@ -0,0 +1,31 @@ +# Collections Plugins Directory + +This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that +is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that +would contain module utils and modules respectively. + +Here is an example directory of the majority of plugins currently supported by Ansible: + +``` +└── plugins + ├── action + ├── become + ├── cache + ├── callback + ├── cliconf + ├── connection + ├── filter + ├── httpapi + ├── inventory + ├── lookup + ├── module_utils + ├── modules + ├── netconf + ├── shell + ├── strategy + ├── terminal + ├── test + └── vars +``` + +A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible/2.9/plugins/plugins.html).
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/doc_fragments/ucs.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/doc_fragments/ucs.py new file mode 100644 index 00000000..5e03a772 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/doc_fragments/ucs.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# (c) 2016 Red Hat Inc. +# (c) 2017 Cisco Systems Inc. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +class ModuleDocFragment(object): + # Cisco UCS doc fragment + DOCUMENTATION = ''' +options: + hostname: + description: + - IP address or hostname of Cisco UCS Manager. + - Modules can be used with the UCS Platform Emulator U(https://cs.co/ucspe) + type: str + required: yes + username: + description: + - Username for Cisco UCS Manager authentication. + type: str + default: admin + password: + description: + - Password for Cisco UCS Manager authentication. + type: str + required: yes + port: + description: + - Port number to be used during connection (by default uses 443 for https and 80 for http connection). + type: int + use_ssl: + description: + - If C(no), an HTTP connection will be used instead of the default HTTPS connection. + type: bool + default: yes + use_proxy: + description: + - If C(no), will not use the proxy as defined by system environment variable. + type: bool + default: yes + proxy: + description: + - If use_proxy is no, specfies proxy to be used for connection. + e.g. 'http://proxy.xy.z:8080' + type: str +''' diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/module_utils/ucs.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/module_utils/ucs.py new file mode 100644 index 00000000..bbb0a407 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/module_utils/ucs.py @@ -0,0 +1,97 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# (c) 2016 Red Hat Inc. +# (c) 2019 Cisco Systems Inc. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +import traceback + +from ansible.module_utils.basic import missing_required_lib + +UCSMSDK_IMP_ERR = None +try: + import ucsmsdk + HAS_UCSMSDK = True +except Exception: + UCSMSDK_IMP_ERR = traceback.format_exc() + HAS_UCSMSDK = False + +ucs_argument_spec = dict( + hostname=dict(type='str', required=True), + username=dict(type='str', default='admin'), + password=dict(type='str', required=True, no_log=True), + port=dict(type='int', default=None), + use_ssl=dict(type='bool', default=True), + use_proxy=dict(type='bool', default=True), + proxy=dict(type='str', default=None), +) + + +class UCSModule(): + + def __init__(self, module): + self.module = module + self.result = {} + if not HAS_UCSMSDK: + self.module.fail_json(msg=missing_required_lib('ucsmsdk'), exception=UCSMSDK_IMP_ERR) + self.login() + + def __del__(self): + self.logout() + + def login(self): + from ucsmsdk.ucshandle import UcsHandle + + # use_proxy=yes (default) and proxy=None (default) should be using the system defined proxy + # use_proxy=yes (default) and proxy=value should use the provided proxy + # use_proxy=no (user) should not be using a proxy + if self.module.params['use_proxy']: + proxy = self.module.params['proxy'] + else: + # force no proxy to be used. Note that proxy=None in UcsHandle will + # use the system proxy so we must set to something else + proxy = {} + + try: + handle = UcsHandle( + ip=self.module.params['hostname'], + username=self.module.params['username'], + password=self.module.params['password'], + port=self.module.params['port'], + secure=self.module.params['use_ssl'], + proxy=proxy + ) + handle.login() + except Exception as e: + self.result['msg'] = str(e) + self.module.fail_json(**self.result) + self.login_handle = handle + + def logout(self): + if hasattr(self, 'login_handle'): + self.login_handle.logout() + return True + return False diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_disk_group_policy.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_disk_group_policy.py new file mode 100644 index 00000000..86d7eaca --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_disk_group_policy.py @@ -0,0 +1,428 @@ +#!/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_disk_group_policy +short_description: Configures disk group policies on Cisco UCS Manager +description: +- Configures disk group policies on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - Desired state of the disk group policy. + - If C(present), will verify that the disk group policy is present and will create if needed. + - If C(absent), will verify that the disk group policy is absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the disk group policy. + - This name can be between 1 and 16 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the policy is created. + required: yes + description: + description: + - The user-defined description of the storage profile. + - 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 ] + raid_level: + description: + - "The RAID level for the disk group policy. This can be one of the following:" + - "stripe - UCS Manager shows RAID 0 Striped" + - "mirror - RAID 1 Mirrored" + - "mirror-stripe - RAID 10 Mirrored and Striped" + - "stripe-parity - RAID 5 Striped Parity" + - "stripe-dual-parity - RAID 6 Striped Dual Parity" + - "stripe-parity-stripe - RAID 50 Striped Parity and Striped" + - "stripe-dual-parity-stripe - RAID 60 Striped Dual Parity and Striped" + choices: [stripe, mirror, mirror-stripe, stripe-parity, stripe-dual-parity, stripe-parity-stripe, stripe-dual-parity-stripe] + default: stripe + configuration_mode: + description: + - "Disk group configuration mode. Choose one of the following:" + - "automatic - Automatically configures the disks in the disk group." + - "manual - Enables you to manually configure the disks in the disk group." + choices: [automatic, manual] + default: automatic + num_drives: + description: + - Specify the number of drives for the disk group. + - This can be from 0 to 24. + - Option only applies when configuration mode is automatic. + default: 1 + drive_type: + description: + - Specify the drive type to use in the drive group. + - "This can be one of the following:" + - "unspecified — Selects the first available drive type, and applies that to all drives in the group." + - "HDD — Hard disk drive" + - "SSD — Solid state drive" + - Option only applies when configuration mode is automatic. + choices: [unspecified, HDD, SSD] + default: unspecified + num_ded_hot_spares: + description: + - Specify the number of hot spares for the disk group. + - This can be from 0 to 24. + - Option only applies when configuration mode is automatic. + default: unspecified + num_glob_hot_spares: + description: + - Specify the number of global hot spares for the disk group. + - This can be from 0 to 24. + - Option only applies when configuration mode is automatic. + default: unspecified + min_drive_size: + description: + - Specify the minimum drive size or unspecified to allow all drive sizes. + - This can be from 0 to 10240 GB. + - Option only applies when configuration mode is automatic. + default: 'unspecified' + use_remaining_disks: + description: + - Specifies whether you can use all the remaining disks in the disk group or not. + - Option only applies when configuration mode is automatic. + choices: ['yes', 'no'] + default: 'no' + manual_disks: + description: + - List of manually configured disks. + - Options are only used when you choose manual configuration_mode. + suboptions: + name: + description: + - The name of the local LUN. + required: yes + slot_num: + description: + - The slot number of the specific disk. + role: + description: + - "The role of the disk. This can be one of the following:" + - "normal - Normal" + - "ded-hot-spare - Dedicated Hot Spare" + - "glob-hot-spare - Glob Hot Spare" + span_id: + description: + - The Span ID of the specific disk. + default: 'unspecified' + state: + description: + - If C(present), will verify disk slot is configured within policy. + If C(absent), will verify disk slot is absent from policy. + choices: [ present, absent ] + default: present + virtual_drive: + description: + - Configuration of virtual drive options. + suboptions: + access_policy: + description: + - Configure access policy to virtual drive. + choices: [blocked, hidden, platform-default, read-only, read-write, transport-ready] + default: platform-default + drive_cache: + description: + - Configure drive caching. + choices: [disable, enable, no-change, platform-default] + default: platform-default + io_policy: + description: + - Direct or Cached IO path. + choices: [cached, direct, platform-default] + default: platform-default + read_policy: + description: + - Read access policy to virtual drive. + choices: [normal, platform-default, read-ahead] + default: platform-default + strip_size: + description: + - Virtual drive strip size. + choices: [ present, absent ] + default: platform-default + write_cache_policy: + description: + - Write back cache policy. + choices: [always-write-back, platform-default, write-back-good-bbu, write-through] + default: platform-default + org_dn: + description: + - The distinguished name (dn) of the organization where the resource is assigned. + default: org-root +requirements: +- ucsmsdk +author: +- Sindhu Sudhir (@sisudhir) +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +- Brett Johnson (@sdbrett) +- John McDonough (@movinalot) +version_added: '2.8' +''' + +EXAMPLES = r''' +- name: Configure Disk Group Policy + cisco.ucs.ucs_disk_group_policy: + hostname: 172.16.143.150 + username: admin + password: password + name: DEE-DG + raid_level: mirror + configuration_mode: manual + manual_disks: + - slot_num: '1' + role: normal + - slot_num: '2' + role: normal + +- name: Remove Disk Group Policy + cisco.ucs.ucs_disk_group_policy: + name: DEE-DG + hostname: 172.16.143.150 + username: admin + password: password + state: absent + +- name: Remove Disk from Policy + cisco.ucs.ucs_disk_group_policy: + hostname: 172.16.143.150 + username: admin + password: password + name: DEE-DG + description: Testing Ansible + raid_level: stripe + configuration_mode: manual + manual_disks: + - slot_num: '1' + role: normal + - slot_num: '2' + role: normal + state: absent + virtual_drive: + access_policy: platform-default + io_policy: direct + strip_size: 64KB +''' + +RETURN = r''' +# +''' + +from ucsmsdk.mometa.lstorage.LstorageDiskGroupConfigPolicy import LstorageDiskGroupConfigPolicy +from ucsmsdk.mometa.lstorage.LstorageDiskGroupQualifier import LstorageDiskGroupQualifier +from ucsmsdk.mometa.lstorage.LstorageLocalDiskConfigRef import LstorageLocalDiskConfigRef +from ucsmsdk.mometa.lstorage.LstorageVirtualDriveDef import LstorageVirtualDriveDef + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def configure_disk_policy(ucs, module, dn): + # from ucsmsdk.mometa.lstorage.LstorageDiskGroupConfigPolicy import LstorageDiskGroupConfigPolicy + # from ucsmsdk.mometa.lstorage.LstorageDiskGroupQualifier import LstorageDiskGroupQualifier + # from ucsmsdk.mometa.lstorage.LstorageLocalDiskConfigRef import LstorageLocalDiskConfigRef + + if not module.check_mode: + try: + # create if mo does not already exist + mo = LstorageDiskGroupConfigPolicy( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['description'], + raid_level=module.params['raid_level'], + ) + if module.params['configuration_mode'] == 'automatic': + LstorageDiskGroupQualifier( + parent_mo_or_dn=mo, + num_drives=module.params['num_drives'], + drive_type=module.params['drive_type'], + use_remaining_disks=module.params['use_remaining_disks'], + num_ded_hot_spares=module.params['num_ded_hot_spares'], + num_glob_hot_spares=module.params['num_glob_hot_spares'], + min_drive_size=module.params['min_drive_size'], + ) + else: # configuration_mode == 'manual' + for disk in module.params['manual_disks']: + if disk['state'] == 'absent': + child_dn = dn + '/slot-' + disk['slot_num'] + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + ucs.login_handle.remove_mo(mo_1) + else: # state == 'present' + LstorageLocalDiskConfigRef( + parent_mo_or_dn=mo, + slot_num=disk['slot_num'], + role=disk['role'], + span_id=disk['span_id'], + ) + + if module.params['virtual_drive']: + _configure_virtual_drive(module, mo) + + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + except Exception as e: # generic Exception handling because SDK can throw a variety + ucs.result['msg'] = "setup error: %s " % str(e) + module.fail_json(**ucs.result) + + ucs.result['changed'] = True + + +def check_disk_policy_props(ucs, module, mo, dn): + props_match = True + + # check top-level mo props + kwargs = dict(descr=module.params['description']) + kwargs['raid_level'] = module.params['raid_level'] + if mo.check_prop_match(**kwargs): + # top-level props match, check next level mo/props + if module.params['configuration_mode'] == 'automatic': + child_dn = dn + '/disk-group-qual' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(num_drives=module.params['num_drives']) + kwargs['drive_type'] = module.params['drive_type'] + kwargs['use_remaining_disks'] = module.params['use_remaining_disks'] + kwargs['num_ded_hot_spares'] = module.params['num_ded_hot_spares'] + kwargs['num_glob_hot_spares'] = module.params['num_glob_hot_spares'] + kwargs['min_drive_size'] = module.params['min_drive_size'] + props_match = mo_1.check_prop_match(**kwargs) + + else: # configuration_mode == 'manual' + for disk in module.params['manual_disks']: + child_dn = dn + '/slot-' + disk['slot_num'] + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + if disk['state'] == 'absent': + props_match = False + else: # state == 'present' + kwargs = dict(slot_num=disk['slot_num']) + kwargs['role'] = disk['role'] + kwargs['span_id'] = disk['span_id'] + if not mo_1.check_prop_match(**kwargs): + props_match = False + break + if props_match: + if module.params['virtual_drive']: + props_match = check_virtual_drive_props(ucs, module, dn) + else: + props_match = False + return props_match + + +def check_virtual_drive_props(ucs, module, dn): + child_dn = dn + '/virtual-drive-def' + mo_1 = ucs.login_handle.query_dn(child_dn) + return mo_1.check_prop_match(**module.params['virtual_drive']) + + +def _configure_virtual_drive(module, mo): + # from ucsmsdk.mometa.lstorage.LstorageVirtualDriveDef import LstorageVirtualDriveDef + LstorageVirtualDriveDef(parent_mo_or_dn=mo, **module.params['virtual_drive']) + + +def _virtual_drive_argument_spec(): + return dict( + access_policy=dict(type='str', default='platform-default', + choices=["blocked", "hidden", "platform-default", "read-only", "read-write", + "transport-ready"]), + drive_cache=dict(type='str', default='platform-default', + choices=["disable", "enable", "no-change", "platform-default"]), + io_policy=dict(type='str', default='platform-default', + choices=["cached", "direct", "platform-default"]), + read_policy=dict(type='str', default='platform-default', + choices=["normal", "platform-default", "read-ahead"]), + strip_size=dict(type='str', default='platform-default', + choices=["1024KB", "128KB", "16KB", "256KB", "32KB", "512KB", "64KB", "8KB", + "platform-default"]), + write_cache_policy=dict(type='str', default='platform-default', + choices=["always-write-back", "platform-default", "write-back-good-bbu", + "write-through"]), + ) + + +def main(): + manual_disk = dict( + slot_num=dict(type='str', required=True), + role=dict(type='str', default='normal', choices=['normal', 'ded-hot-spare', 'glob-hot-spare']), + span_id=dict(type='str', default='unspecified'), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + description=dict(type='str', aliases=['descr'], default=''), + raid_level=dict( + type='str', + default='stripe', + choices=[ + 'stripe', + 'mirror', + 'mirror-stripe', + 'stripe-parity', + 'stripe-dual-parity', + 'stripe-parity-stripe', + 'stripe-dual-parity-stripe', + ], + ), + num_drives=dict(type='str', default='1'), + configuration_mode=dict(type='str', default='automatic', choices=['automatic', 'manual']), + num_ded_hot_spares=dict(type='str', default='unspecified'), + num_glob_hot_spares=dict(type='str', default='unspecified'), + drive_type=dict(type='str', default='unspecified', choices=['unspecified', 'HDD', 'SSD']), + use_remaining_disks=dict(type='str', default='no', choices=['yes', 'no']), + min_drive_size=dict(type='str', default='unspecified'), + manual_disks=dict(type='list', elements='dict', options=manual_disk), + state=dict(type='str', default='present', choices=['present', 'absent']), + virtual_drive=dict(type='dict', options=_virtual_drive_argument_spec()), + ) + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + ucs = UCSModule(module) + # UCSModule creation above verifies ucsmsdk is present and exits on failure. + # Additional imports are done below or in called functions. + + ucs.result['changed'] = False + props_match = False + # dn is <org_dn>/disk-group-config-<name> + dn = module.params['org_dn'] + '/disk-group-config-' + module.params['name'] + + mo = ucs.login_handle.query_dn(dn) + if mo: + if module.params['state'] == 'absent': + # mo must exist but all properties do not have to match + if not module.check_mode: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + ucs.result['changed'] = True + else: # state == 'present' + props_match = check_disk_policy_props(ucs, module, mo, dn) + + if module.params['state'] == 'present' and not props_match: + configure_disk_policy(ucs, module, dn) + + module.exit_json(**ucs.result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_dns_server.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_dns_server.py new file mode 100644 index 00000000..5271cacc --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_dns_server.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_dns_server +short_description: Configure DNS servers on Cisco UCS Manager +description: +- Configure DNS servers on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(absent), will remove a DNS server. + - If C(present), will add or update a DNS server. + choices: [absent, present] + default: present + type: str + + dns_server: + description: + - DNS server IP address. + - Enter a valid IPV4 Address. + - UCS Manager supports up to 4 DNS Servers + aliases: [ name ] + type: str + + description: + description: + - A user-defined description of the DNS server. + - 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: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) + +version_added: "2.8" +''' + +EXAMPLES = r''' +- name: Configure DNS server + cisco.ucs.ucs_dns_server: + hostname: 172.16.143.150 + username: admin + password: password + dns_server: 10.10.10.10 + description: DNS Server IP address + state: present + delegate_to: localhost + +- name: Remove DNS server + cisco.ucs.ucs_dns_server: + hostname: 172.16.143.150 + username: admin + password: password + dns_server: 10.10.10.10 + state: absent + delegate_to: localhost +''' + +RETURN = r''' +# +''' +from ucsmsdk.mometa.comm.CommDnsProvider import CommDnsProvider + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def run_module(): + argument_spec = ucs_argument_spec + argument_spec.update( + dns_server=dict(type='str', aliases=['name']), + 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', ['dns_server']], + ], + ) + # UCSModule verifies ucsmsdk is present and exits on failure. + # Imports are below for UCS object creation. + ucs = UCSModule(module) + # from ucsmsdk.mometa.comm.CommDnsProvider import CommDnsProvider + + err = False + changed = False + + try: + mo_exists = False + props_match = False + + dn = 'sys/svc-ext/dns-svc/dns-' + module.params['dns_server'] + + 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 = CommDnsProvider(parent_mo_or_dn='sys/svc-ext/dns-svc', + name=module.params['dns_server'], + 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/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_graphics_card_policy.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_graphics_card_policy.py new file mode 100644 index 00000000..ccc8c583 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_graphics_card_policy.py @@ -0,0 +1,261 @@ +#!/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_graphics_card_policy + +short_description: Manages UCS Graphics Card Policies on UCS Manager + +description: + - Manages UCS Graphics Card Policies on UCS Manager. + +extends_documentation_fragment: cisco.ucs.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 + + name: + description: + - The name of the organization. + - 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), ' (single quote)." + required: true + 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), ' (single quote)." + aliases: [ descr ] + type: str + + graphics_card_mode: + description: + - Set the Graphics Card Mode. + choices: [any-configuration, compute, graphics] + type: str + + org_dn: + description: + - Org dn (distinguished name) + default: org-root + type: str + +requirements: +- ucsmsdk + +author: +- John McDonough (@movinalot) +version_added: "2.9" +''' + +EXAMPLES = r''' +- name: Add UCS Graphics Card Policy + cisco.ucs.ucs_graphics_card_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + description: Any Graphics Mode Policy + name: any_graphics + graphics_card_mode: any-configuration + delegate_to: localhost + +- name: Add UCS Graphics Card Policy in an Organization + cisco.ucs.ucs_graphics_card_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + description: Any Graphics Mode Policy + name: prod_graphics + graphics_card_mode: any-configuration + delegate_to: localhost + +- name: Update UCS Graphics Card Policy in an Organization + cisco.ucs.ucs_graphics_card_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + description: Graphics Mode Policy + name: prod_graphics + graphics_card_mode: graphics + delegate_to: localhost + +- name: Update UCS Graphics Card Policy in an Organization + cisco.ucs.ucs_graphics_card_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + description: Compute Mode Policy + name: prod_graphics + graphics_card_mode: compute + delegate_to: localhost + +- name: Delete UCS Graphics Card Policy in an Organization + cisco.ucs.ucs_graphics_card_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: absent + org_dn: org-root/org-prod + name: prod_graphics + delegate_to: localhost + +- name: Delete UCS Graphics Card Policy + cisco.ucs.ucs_graphics_card_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: absent + name: any_graphics + delegate_to: localhost +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import ( + UCSModule, + ucs_argument_spec +) + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(required=True, type='str'), + descr=dict(type='str'), + description=dict(type='str', aliases=['descr']), + graphics_card_mode=dict(type='str', choices=[ + 'any-configuration', + 'compute', + 'graphics' + ]), + state=dict( + type='str', default='present', + choices=['present', 'absent'] + ), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['name']], + ], + ) + + # UCSModule verifies ucsmsdk is present and exits on failure. + # Imports are below for UCS object creation. + ucs = UCSModule(module) + from importlib import import_module + from ucsmsdk.ucscoreutils import get_meta_info + + # The Class(es) this module is managing + module_file = 'ucsmsdk.mometa.compute.ComputeGraphicsCardPolicy' + module_class = 'ComputeGraphicsCardPolicy' + mo_module = import_module(module_file) + mo_class = getattr(mo_module, module_class) + + META = get_meta_info(class_id=module_class) + + err = False + changed = False + requested_state = module.params['state'] + + kwargs = dict() + + # Manage Aliased Attributes + for attribute in ['descr:description']: + attribute_alias = attribute.split(':') + if module.params[attribute_alias[1]] is not None: + kwargs[attribute_alias[0]] = module.params[attribute_alias[1]] + + # Manage Attributes + for attribute in [ + 'graphics_card_mode', 'descr']: + if module.params[attribute] is not None: + kwargs[attribute] = module.params[attribute] + + try: + dn = ( + module.params['org_dn'] + '/' + + META.rn[0:META.rn.rindex('-') + 1] + + module.params['name'] + ) + mo = ucs.login_handle.query_dn(dn) + + # Determine state change + if mo: + # Object exists, if it should exist has anything changed? + if requested_state == 'present': + # Do some or all Object properties not match, that is a change + + if not mo.check_prop_match(**kwargs): + changed = True + + # Object does not exist but should, that is a change + else: + if requested_state == 'present': + changed = True + + # Object exists but should not, that is a change + if mo and requested_state == 'absent': + changed = True + + # Apply state if not check_mode + if changed and not module.check_mode: + if requested_state == 'absent': + ucs.login_handle.remove_mo(mo) + else: + kwargs['parent_mo_or_dn'] = module.params['org_dn'] + kwargs['name'] = module.params['name'] + + mo = mo_class(**kwargs) + ucs.login_handle.add_mo(mo, modify_present=True) + ucs.login_handle.commit() + + 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_ip_pool.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_ip_pool.py new file mode 100644 index 00000000..308ffd4b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_ip_pool.py @@ -0,0 +1,452 @@ +#!/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_ip_pool +short_description: Configures IP address pools on Cisco UCS Manager +description: +- Configures IP address pools and blocks of IP addresses on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify IP pool is present and will create if needed. + - If C(absent), will verify IP pool is absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the IP address pool. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the IP address pool is created. + required: yes + description: + description: + - The user-defined description of the IP address pool. + - 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 ] + order: + description: + - The Assignment Order field. + - "This can be one of the following:" + - "default - Cisco UCS Manager selects a random identity from the pool." + - "sequential - Cisco UCS Manager selects the lowest available identity from the pool." + choices: [default, sequential] + default: default + ip_blocks: + description: + - List of IPv4 blocks used by the IP Pool. + suboptions: + first_addr: + description: + - The first IPv4 address in the IPv4 addresses block. + - This is the From field in the UCS Manager Add IPv4 Blocks menu. + last_addr: + description: + - The last IPv4 address in the IPv4 addresses block. + - This is the To field in the UCS Manager Add IPv4 Blocks menu. + subnet_mask: + description: + - The subnet mask associated with the IPv4 addresses in the block. + default: 255.255.255.0 + default_gw: + description: + - The default gateway associated with the IPv4 addresses in the block. + default: 0.0.0.0 + primary_dns: + description: + - The primary DNS server that this block of IPv4 addresses should access. + default: 0.0.0.0 + secondary_dns: + description: + - The secondary DNS server that this block of IPv4 addresses should access. + default: 0.0.0.0 + ipv6_blocks: + description: + - List of IPv6 blocks used by the IP Pool. + suboptions: + ipv6_first_addr: + description: + - The first IPv6 address in the IPv6 addresses block. + - This is the From field in the UCS Manager Add IPv6 Blocks menu. + ipv6_last_addr: + description: + - The last IPv6 address in the IPv6 addresses block. + - This is the To field in the UCS Manager Add IPv6 Blocks menu. + ipv6_prefix: + description: + - The network address prefix associated with the IPv6 addresses in the block. + default: '64' + ipv6_default_gw: + description: + - The default gateway associated with the IPv6 addresses in the block. + default: '::' + ipv6_primary_dns: + description: + - The primary DNS server that this block of IPv6 addresses should access. + default: '::' + ipv6_secondary_dns: + description: + - The secondary DNS server that this block of IPv6 addresses should access. + default: '::' + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: + - Brett Johnson (@sdbrett) + - David Soper (@dsoper2) + - John McDonough (@movinalot) + - CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure IPv4 and IPv6 address pool + cisco.ucs.ucs_ip_pool: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + name: ip-pool-01 + org_dn: org-root/org-level1 + ipv4_blocks: + - first_addr: 192.168.10.1 + last_addr: 192.168.10.20 + subnet_mask: 255.255.255.128 + default_gw: 192.168.10.2 + - first_addr: 192.168.11.1 + last_addr: 192.168.11.20 + subnet_mask: 255.255.255.128 + default_gw: 192.168.11.2 + ipv6_blocks: + - ipv6_first_addr: fe80::1cae:7992:d7a1:ed07 + ipv6_last_addr: fe80::1cae:7992:d7a1:edfe + ipv6_default_gw: fe80::1cae:7992:d7a1:ecff + - ipv6_first_addr: fe80::1cae:7992:d7a1:ec07 + ipv6_last_addr: fe80::1cae:7992:d7a1:ecfe + ipv6_default_gw: fe80::1cae:7992:d7a1:ecff + +- name: Delete IPv4 and IPv6 address pool blocks + cisco.ucs.ucs_ip_pool: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + name: ip-pool-01 + org_dn: org-root/org-level1 + ipv4_blocks: + - first_addr: 192.168.10.1 + last_addr: 192.168.10.20 + state: absent + ipv6_blocks: + - ipv6_first_addr: fe80::1cae:7992:d7a1:ec07 + ipv6_last_addr: fe80::1cae:7992:d7a1:ecfe + state: absent + +- name: Remove IPv4 and IPv6 address pool + cisco.ucs.ucs_ip_pool: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + name: ip-pool-01 + state: absent +''' + +RETURN = r''' +# +''' + + +def update_ip_pool(ucs, module): + from ucsmsdk.mometa.ippool.IppoolPool import IppoolPool + + mo = IppoolPool( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['descr'], + assignment_order=module.params['order'], + ) + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + + return mo + + +def match_existing_ipv4_block(ucs, dn, ipv4_block): + # ipv4 block specified, check properties + mo_1 = get_ip_block(ucs, dn, ipv4_block['first_addr'], ipv4_block['last_addr'], 'v4') + if not mo_1: + if ipv4_block['state'] == 'absent': + return True + return False + else: + if ipv4_block['state'] == 'absent': + return False + kwargs = dict(subnet=ipv4_block['subnet_mask']) + kwargs['def_gw'] = ipv4_block['default_gw'] + kwargs['prim_dns'] = ipv4_block['primary_dns'] + kwargs['sec_dns'] = ipv4_block['secondary_dns'] + return mo_1.check_prop_match(**kwargs) + + +def match_existing_ipv6_block(ucs, dn, ipv6_block): + # ipv6 block specified, check properties + mo_1 = get_ip_block(ucs, dn, ipv6_block['ipv6_first_addr'], ipv6_block['ipv6_last_addr'], 'v6') + if not mo_1: + if ipv6_block['state'] == 'absent': + return True + return False + else: + if ipv6_block['state'] == 'absent': + return False + kwargs = dict(prefix=ipv6_block['ipv6_prefix']) + kwargs['def_gw'] = ipv6_block['ipv6_default_gw'] + kwargs['prim_dns'] = ipv6_block['ipv6_primary_dns'] + kwargs['sec_dns'] = ipv6_block['ipv6_secondary_dns'] + return mo_1.check_prop_match(**kwargs) + + +def remove_ip_block(ucs, dn, ip_block, ip_version): + if ip_version == 'v6': + first_addr = ip_block['ipv6_first_addr'] + last_addr = ip_block['ipv6_last_addr'] + else: + first_addr = ip_block['first_addr'] + last_addr = ip_block['last_addr'] + + mo_1 = get_ip_block(ucs, dn, first_addr, last_addr, ip_version) + if mo_1: + ucs.login_handle.remove_mo(mo_1) + ucs.login_handle.commit() + + +def update_ip_block(ucs, mo, ip_block, ip_version): + + remove_ip_block(ucs, mo.dn, ip_block, ip_version) + if not ip_block['state'] == 'absent': + if ip_version == 'v6': + from ucsmsdk.mometa.ippool.IppoolIpV6Block import IppoolIpV6Block + IppoolIpV6Block( + parent_mo_or_dn=mo, + to=ip_block['ipv6_last_addr'], + r_from=ip_block['ipv6_first_addr'], + prefix=ip_block['ipv6_prefix'], + def_gw=ip_block['ipv6_default_gw'], + prim_dns=ip_block['ipv6_primary_dns'], + sec_dns=ip_block['ipv6_secondary_dns'] + ) + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + else: + from ucsmsdk.mometa.ippool.IppoolBlock import IppoolBlock + IppoolBlock( + parent_mo_or_dn=mo, + to=ip_block['last_addr'], + r_from=ip_block['first_addr'], + subnet=ip_block['subnet_mask'], + def_gw=ip_block['default_gw'], + prim_dns=ip_block['primary_dns'], + sec_dns=ip_block['secondary_dns'] + ) + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + + +def get_ip_block(ucs, pool_dn, first_addr, last_addr, ip_version): + if ip_version == 'v6': + dn_type = '/v6block-' + else: + dn_type = '/block-' + + block_dn = pool_dn + dn_type + first_addr + '-' + last_addr + return ucs.login_handle.query_dn(block_dn) + + +def main(): + from ansible.module_utils.basic import AnsibleModule + from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + ipv4_configuration_spec = dict( + first_addr=dict(type='str'), + last_addr=dict(type='str'), + subnet_mask=dict(type='str', default='255.255.255.0'), + default_gw=dict(type='str', default='0.0.0.0'), + primary_dns=dict(type='str', default='0.0.0.0'), + secondary_dns=dict(type='str', default='0.0.0.0'), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + ipv6_configuration_spec = dict( + ipv6_first_addr=dict(type='str'), + ipv6_last_addr=dict(type='str'), + ipv6_prefix=dict(type='str', default='64'), + ipv6_default_gw=dict(type='str', default='::'), + ipv6_primary_dns=dict(type='str', default='::'), + ipv6_secondary_dns=dict(type='str', default='::'), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + descr=dict(type='str', default='', aliases=['description']), + order=dict(type='str', default='default', choices=['default', 'sequential']), + first_addr=dict(type='str'), + last_addr=dict(type='str'), + subnet_mask=dict(type='str', default='255.255.255.0'), + default_gw=dict(type='str', default='0.0.0.0'), + primary_dns=dict(type='str', default='0.0.0.0'), + secondary_dns=dict(type='str', default='0.0.0.0'), + ipv6_first_addr=dict(type='str'), + ipv6_last_addr=dict(type='str'), + ipv6_prefix=dict(type='str', default='64'), + ipv6_default_gw=dict(type='str', default='::'), + ipv6_primary_dns=dict(type='str', default='::'), + ipv6_secondary_dns=dict(type='str', default='::'), + state=dict(type='str', default='present', choices=['present', 'absent']), + ipv4_blocks=dict(type='list', default=None, elements='dict', options=ipv4_configuration_spec), + ipv6_blocks=dict(type='list', default=None, elements='dict', options=ipv6_configuration_spec), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + # UCSModule verifies ucsmsdk is present and exits on failure. Imports are below ucs object creation. + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.ippool.IppoolBlock import IppoolBlock + from ucsmsdk.mometa.ippool.IppoolIpV6Block import IppoolIpV6Block + + changed = False + try: + mo_exists = False + ipv4_props_match = True + ipv6_props_match = True + # dn is <org_dn>/ip-pool-<name> + dn = module.params['org_dn'] + '/ip-pool-' + module.params['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 not mo_exists: + if not module.check_mode: + mo = update_ip_pool(ucs, module) + changed = True + if mo_exists: + # check top-level mo props + kwargs = dict(assignment_order=module.params['order']) + kwargs['descr'] = module.params['descr'] + if not mo.check_prop_match(**kwargs): + if not module.check_mode: + mo = update_ip_pool(ucs, module) + changed = True + # top-level props match, check next level mo/props + if module.params['ipv4_blocks']: + for ipv4_block in module.params['ipv4_blocks']: + if not match_existing_ipv4_block(ucs, dn, ipv4_block): + if not module.check_mode: + update_ip_block(ucs, mo, ipv4_block, 'v4') + changed = True + elif module.params['last_addr'] and module.params['first_addr']: + # ipv4 block specified, check properties + mo_1 = get_ip_block(ucs, dn, module.params['first_addr'], module.params['last_addr'], 'v4') + if mo_1: + kwargs = dict(subnet=module.params['subnet_mask']) + kwargs['def_gw'] = module.params['default_gw'] + kwargs['prim_dns'] = module.params['primary_dns'] + kwargs['sec_dns'] = module.params['secondary_dns'] + if not mo_1.check_prop_match(**kwargs): + # ipv4 block exists and properties match + ipv4_props_match = False + else: + ipv4_props_match = False + + # only check ipv6 props if the top-level and ipv4 props matched + if module.params['ipv6_blocks']: + for ipv6_block in module.params['ipv6_blocks']: + if not match_existing_ipv6_block(ucs, dn, ipv6_block): + if not module.check_mode: + update_ip_block(ucs, mo, ipv6_block, 'v6') + changed = True + elif module.params['ipv6_last_addr'] and module.params['ipv6_first_addr']: + # ipv6 block specified, check properties + block_dn = dn + '/v6block-' + module.params['ipv6_first_addr'].lower() + '-' + module.params[ + 'ipv6_last_addr'].lower() + mo_1 = ucs.login_handle.query_dn(block_dn) + if mo_1: + kwargs = dict(prefix=module.params['ipv6_prefix']) + kwargs['def_gw'] = module.params['ipv6_default_gw'] + kwargs['prim_dns'] = module.params['ipv6_primary_dns'] + kwargs['sec_dns'] = module.params['ipv6_secondary_dns'] + if not mo_1.check_prop_match(**kwargs): + # ipv6 block exists and properties match + ipv6_props_match = False + else: + ipv6_props_match = False + + if not ipv4_props_match or not ipv6_props_match: + if not module.check_mode: + if module.params['last_addr'] and module.params['first_addr']: + IppoolBlock( + parent_mo_or_dn=mo, + to=module.params['last_addr'], + r_from=module.params['first_addr'], + subnet=module.params['subnet_mask'], + def_gw=module.params['default_gw'], + prim_dns=module.params['primary_dns'], + sec_dns=module.params['secondary_dns'], + ) + + if module.params['ipv6_last_addr'] and module.params['ipv6_first_addr']: + IppoolIpV6Block( + parent_mo_or_dn=mo, + to=module.params['ipv6_last_addr'], + r_from=module.params['ipv6_first_addr'], + prefix=module.params['ipv6_prefix'], + def_gw=module.params['ipv6_default_gw'], + prim_dns=module.params['ipv6_primary_dns'], + sec_dns=module.params['ipv6_secondary_dns'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_lan_connectivity.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_lan_connectivity.py new file mode 100644 index 00000000..7638091f --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_lan_connectivity.py @@ -0,0 +1,355 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_lan_connectivity +short_description: Configures LAN Connectivity Policies on Cisco UCS Manager +description: +- Configures LAN Connectivity Policies on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify LAN Connectivity Policies are present and will create if needed. + - If C(absent), will verify LAN Connectivity Policies are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the LAN Connectivity Policy. + - This name can be between 1 and 16 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the policy is created. + required: yes + description: + description: + - A description of the LAN Connectivity Policy. + - Cisco recommends including information about where and when to use the policy. + - 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 ] + vnic_list: + description: + - List of vNICs used by the LAN Connectivity Policy. + - vNICs used by the LAN Connectivity Policy must be created from a vNIC template. + suboptions: + name: + description: + - The name of the vNIC. + required: yes + vnic_template: + description: + - The name of the vNIC template. + required: yes + adapter_policy: + description: + - The name of the Ethernet adapter policy. + - A user defined policy can be used, or one of the system defined policies. + order: + description: + - String specifying the vNIC assignment order (e.g., '1', '2'). + default: 'unspecified' + state: + description: + - If C(present), will verify vnic is configured within policy. + If C(absent), will verify vnic is absent from policy. + choices: [ present, absent ] + default: present + version_added: '2.8' + iscsi_vnic_list: + description: + - List of iSCSI vNICs used by the LAN Connectivity Policy. + suboptions: + name: + description: + - The name of the iSCSI vNIC. + required: yes + overlay_vnic: + description: + - The LAN vNIC associated with this iSCSI vNIC. + iscsi_adapter_policy: + description: + - The iSCSI adapter policy associated with this iSCSI vNIC. + mac_address: + description: + - The MAC address associated with this iSCSI vNIC. + - If the MAC address is not set, Cisco UCS Manager uses a derived MAC address. + default: derived + vlan_name: + description: + - The VLAN used for the iSCSI vNIC. + default: default + state: + description: + - If C(present), will verify iscsi vnic is configured within policy. + If C(absent), will verify iscsi vnic is absent from policy. + choices: [ present, absent ] + default: present + version_added: '2.8' + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure LAN Connectivity Policy + cisco.ucs.ucs_lan_connectivity: + hostname: 172.16.143.150 + username: admin + password: password + name: Cntr-FC-Boot + vnic_list: + - name: eno1 + vnic_template: Cntr-Template + adapter_policy: Linux + - name: eno2 + vnic_template: Container-NFS-A + adapter_policy: Linux + - name: eno3 + vnic_template: Container-NFS-B + adapter_policy: Linux + iscsi_vnic_list: + - name: iSCSIa + overlay_vnic: eno1 + iscsi_adapter_policy: default + vlan_name: Container-MGMT-VLAN + - name: iSCSIb + overlay_vnic: eno3 + iscsi_adapter_policy: default + vlan_name: Container-TNT-A-NFS + +- name: Remove LAN Connectivity Policy + cisco.ucs.ucs_lan_connectivity: + hostname: 172.16.143.150 + username: admin + password: password + name: Cntr-FC-Boot + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def configure_lan_connectivity(ucs, module, dn): + from ucsmsdk.mometa.vnic.VnicLanConnPolicy import VnicLanConnPolicy + from ucsmsdk.mometa.vnic.VnicEther import VnicEther + from ucsmsdk.mometa.vnic.VnicIScsiLCP import VnicIScsiLCP + from ucsmsdk.mometa.vnic.VnicVlan import VnicVlan + + if not module.check_mode: + try: + # create if mo does not already exist + mo = VnicLanConnPolicy( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['description'], + ) + + if module.params.get('vnic_list'): + for vnic in module.params['vnic_list']: + if vnic['state'] == 'absent': + child_dn = dn + '/ether-' + vnic['name'] + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + ucs.login_handle.remove_mo(mo_1) + else: # state == 'present' + mo_1 = VnicEther( + addr='derived', + parent_mo_or_dn=mo, + name=vnic['name'], + adaptor_profile_name=vnic['adapter_policy'], + nw_templ_name=vnic['vnic_template'], + order=vnic['order'], + ) + + if module.params.get('iscsi_vnic_list'): + for iscsi_vnic in module.params['iscsi_vnic_list']: + if iscsi_vnic['state'] == 'absent': + child_dn = dn + '/iscsi-' + iscsi_vnic['name'] + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + ucs.login_handle.remove_mo(mo_1) + else: # state == 'present' + mo_1 = VnicIScsiLCP( + parent_mo_or_dn=mo, + name=iscsi_vnic['name'], + adaptor_profile_name=iscsi_vnic['iscsi_adapter_policy'], + vnic_name=iscsi_vnic['overlay_vnic'], + addr=iscsi_vnic['mac_address'], + ) + VnicVlan( + parent_mo_or_dn=mo_1, + vlan_name=iscsi_vnic['vlan_name'], + ) + + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + except Exception as e: # generic Exception handling because SDK can throw a variety of exceptions + ucs.result['msg'] = "setup error: %s " % str(e) + module.fail_json(**ucs.result) + + ucs.result['changed'] = True + + +def check_vnic_props(ucs, module, dn): + props_match = True + + if module.params.get('vnic_list'): + # check vnicEther props + for vnic in module.params['vnic_list']: + child_dn = dn + '/ether-' + vnic['name'] + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + if vnic['state'] == 'absent': + props_match = False + break + else: # state == 'present' + kwargs = dict(adaptor_profile_name=vnic['adapter_policy']) + kwargs['order'] = vnic['order'] + kwargs['nw_templ_name'] = vnic['vnic_template'] + if not (mo_1.check_prop_match(**kwargs)): + props_match = False + break + else: # mo_1 did not exist + if vnic['state'] == 'present': + props_match = False + break + + return props_match + + +def check_iscsi_vnic_props(ucs, module, dn): + props_match = True + + if module.params.get('iscsi_vnic_list'): + # check vnicIScsiLCP props + for iscsi_vnic in module.params['iscsi_vnic_list']: + child_dn = dn + '/iscsi-' + iscsi_vnic['name'] + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + if iscsi_vnic['state'] == 'absent': + props_match = False + break + else: # state == 'present' + kwargs = dict(vnic_name=iscsi_vnic['overlay_vnic']) + kwargs['adaptor_profile_name'] = iscsi_vnic['iscsi_adapter_policy'] + kwargs['addr'] = iscsi_vnic['mac_address'] + if (mo_1.check_prop_match(**kwargs)): + # check vlan + child_dn = child_dn + '/vlan' + mo_2 = ucs.login_handle.query_dn(child_dn) + if mo_2: + kwargs = dict(vlan_name=iscsi_vnic['vlan_name']) + if not (mo_2.check_prop_match(**kwargs)): + props_match = False + break + else: # mo_1 props did not match + props_match = False + break + else: # mo_1 did not exist + if iscsi_vnic['state'] == 'present': + props_match = False + break + + return props_match + + +def check_lan_connecivity_props(ucs, module, mo, dn): + props_match = False + + # check top-level mo props + kwargs = dict(descr=module.params['description']) + if (mo.check_prop_match(**kwargs)): + # top-level props match, check next level mo/props + # check vnic 1st + props_match = check_vnic_props(ucs, module, dn) + + if props_match: + props_match = check_iscsi_vnic_props(ucs, module, dn) + + return props_match + + +def main(): + vnic = dict( + name=dict(type='str', required=True), + vnic_template=dict(type='str', required=True), + adapter_policy=dict(type='str', default=''), + order=dict(type='str', default='unspecified'), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + iscsi_vnic = dict( + name=dict(type='str', required=True), + overlay_vnic=dict(type='str', default=''), + iscsi_adapter_policy=dict(type='str', default=''), + mac_address=dict(type='str', default='derived'), + vlan_name=dict(type='str', default='default'), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + description=dict(type='str', aliases=['descr'], default=''), + vnic_list=dict(type='list', elements='dict', options=vnic), + iscsi_vnic_list=dict(type='list', elements='dict', options=iscsi_vnic), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + ucs = UCSModule(module) + # UCSModule creation above verifies ucsmsdk is present and exits on failure. + # Additional imports are done below or in called functions. + + ucs.result['changed'] = False + props_match = False + # dn is <org_dn>/lan-conn-pol-<name> + dn = module.params['org_dn'] + '/lan-conn-pol-' + module.params['name'] + + mo = ucs.login_handle.query_dn(dn) + if mo: + if module.params['state'] == 'absent': + # mo must exist but all properties do not have to match + if not module.check_mode: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + ucs.result['changed'] = True + else: # state == 'present' + props_match = check_lan_connecivity_props(ucs, module, mo, dn) + + if module.params['state'] == 'present' and not props_match: + configure_lan_connectivity(ucs, module, dn) + + module.exit_json(**ucs.result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_mac_pool.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_mac_pool.py new file mode 100644 index 00000000..35bdbfa5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_mac_pool.py @@ -0,0 +1,185 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_mac_pool +short_description: Configures MAC address pools on Cisco UCS Manager +description: +- Configures MAC address pools and MAC address blocks on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify MAC pool is present and will create if needed. + - If C(absent), will verify MAC pool is absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the MAC pool. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the MAC pool is created. + required: yes + description: + description: + - A description of the MAC pool. + - 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 ] + order: + description: + - The Assignment Order field. + - "This can be one of the following:" + - "default - Cisco UCS Manager selects a random identity from the pool." + - "sequential - Cisco UCS Manager selects the lowest available identity from the pool." + choices: [default, sequential] + default: default + first_addr: + description: + - The first MAC address in the block of addresses. + - This is the From field in the UCS Manager MAC Blocks menu. + last_addr: + description: + - The last MAC address in the block of addresses. + - This is the To field in the UCS Manager Add MAC Blocks menu. + org_dn: + description: + - The distinguished name (dn) of the organization where the resource is assigned. + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure MAC address pool + cisco.ucs.ucs_mac_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: mac-A + first_addr: 00:25:B5:00:66:00 + last_addr: 00:25:B5:00:67:F3 + order: sequential + +- name: Remove MAC address pool + cisco.ucs.ucs_mac_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: mac-A + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + descr=dict(type='str', default='', aliases=['description']), + order=dict(type='str', default='default', choices=['default', 'sequential']), + first_addr=dict(type='str'), + last_addr=dict(type='str'), + state=dict(default='present', choices=['present', 'absent'], type='str'), + ) + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + # UCSModule verifies ucsmsdk is present and exits on failure. Imports are below ucs object creation. + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.macpool.MacpoolPool import MacpoolPool + from ucsmsdk.mometa.macpool.MacpoolBlock import MacpoolBlock + + changed = False + try: + mo_exists = False + props_match = False + # dn is <org_dn>/mac-pool-<name> + dn = module.params['org_dn'] + '/mac-pool-' + module.params['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(assignment_order=module.params['order']) + kwargs['descr'] = module.params['descr'] + if mo.check_prop_match(**kwargs): + # top-level props match, check next level mo/props + if module.params['last_addr'] and module.params['first_addr']: + # mac address block specified, check properties + block_dn = dn + '/block-' + module.params['first_addr'].upper() + '-' + module.params['last_addr'].upper() + mo_1 = ucs.login_handle.query_dn(block_dn) + if mo_1: + props_match = True + else: + # no MAC address block specified, but top-level props matched + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = MacpoolPool( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['descr'], + assignment_order=module.params['order'], + ) + + if module.params['last_addr'] and module.params['first_addr']: + mo_1 = MacpoolBlock( + parent_mo_or_dn=mo, + to=module.params['last_addr'], + r_from=module.params['first_addr'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_managed_objects.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_managed_objects.py new file mode 100644 index 00000000..7e679e12 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_managed_objects.py @@ -0,0 +1,256 @@ +#!/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_managed_objects +short_description: Configures Managed Objects on Cisco UCS Manager +description: +- Configures Managed Objects on Cisco UCS Manager. +- The Python SDK module, Python class within the module (UCSM Class), and all properties must be directly specified. +- More information on the UCSM Python SDK and how to directly configure Managed Objects is available at L(UCSM Python SDK,http://ucsmsdk.readthedocs.io/). +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify that the Managed Objects are present and will create if needed. + - If C(absent), will verify that the Managed Objects are absent and will delete if needed. + choices: [ absent, present ] + default: present + objects: + description: + - List of managed objects to configure. Each managed object has suboptions the specify the Python SDK module, class, and properties to configure. + suboptions: + module: + description: + - Name of the Python SDK module implementing the required class. + required: yes + class_name: + description: + - Name of the Python class that will be used to configure the Managed Object. + required: yes + properties: + description: + - List of properties to configure on the Managed Object. See the UCSM Python SDK for information on properties for each class. + required: yes + children: + description: + - Optional list of child objects. Each child has its own module, class, and properties suboptions. + - The parent_mo_or_dn property for child objects is automatically set as the list of children is configured. + required: yes +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +version_added: '2.8' +''' + +EXAMPLES = r''' +- name: Configure Network Control Policy + cisco.ucs.ucs_managed_objects: + hostname: 172.16.143.150 + username: admin + password: password + objects: + - module: ucsmsdk.mometa.nwctrl.NwctrlDefinition + class: NwctrlDefinition + properties: + parent_mo_or_dn: org-root + cdp: enabled + descr: '' + lldp_receive: enabled + lldp_transmit: enabled + name: Enable-CDP-LLDP + +- name: Remove Network Control Policy + cisco.ucs.ucs_managed_objects: + hostname: 172.16.143.150 + username: admin + password: password + objects: + - module: ucsmsdk.mometa.nwctrl.NwctrlDefinition + class: NwctrlDefinition + properties: + parent_mo_or_dn: org-root + name: Enable-CDP-LLDP + state: absent + +- name: Configure Boot Policy Using JSON objects list with children + cisco.ucs.ucs_managed_objects: + hostname: 172.16.143.150 + username: admin + password: password + objects: + - { + "module": "ucsmsdk.mometa.lsboot.LsbootPolicy", + "class": "LsbootPolicy", + "properties": { + "parent_mo_or_dn": "org-root", + "name": "Python_SDS", + "enforce_vnic_name": "yes", + "boot_mode": "legacy", + "reboot_on_update": "no" + }, + "children": [ + { + "module": "ucsmsdk.mometa.lsboot.LsbootVirtualMedia", + "class": "LsbootVirtualMedia", + "properties": { + "access": "read-only-local", + "lun_id": "0", + "order": "2" + } + }, + { + "module": "ucsmsdk.mometa.lsboot.LsbootStorage", + "class": "LsbootStorage", + "properties": { + "order": "1" + }, + "children": [ + { + "module": "ucsmsdk.mometa.lsboot.LsbootLocalStorage", + "class": "LsbootLocalStorage", + "properties": {}, + "children": [ + { + "module": "ucsmsdk.mometa.lsboot.LsbootDefaultLocalImage", + "class": "LsbootDefaultLocalImage", + "properties": { + "order": "1" + } + } + ] + } + ] + } + ] + } + +- name: Remove Boot Policy Using JSON objects list + cisco.ucs.ucs_managed_objects: + hostname: 172.16.143.150 + username: admin + password: password + objects: + - { + "module": "ucsmsdk.mometa.lsboot.LsbootPolicy", + "class": "LsbootPolicy", + "properties": { + "parent_mo_or_dn": "org-root", + "name": "Python_SDS" + } + } + state: absent + + +''' + +RETURN = r''' +# +''' + +try: + from importlib import import_module + HAS_IMPORT_MODULE = True +except ImportError: + HAS_IMPORT_MODULE = False + +from copy import deepcopy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def traverse_objects(module, ucs, managed_object, mo=''): + props_match = False + + mo_module = import_module(managed_object['module']) + mo_class = getattr(mo_module, managed_object['class']) + + if not managed_object['properties'].get('parent_mo_or_dn'): + managed_object['properties']['parent_mo_or_dn'] = mo + + mo = mo_class(**managed_object['properties']) + + existing_mo = ucs.login_handle.query_dn(mo.dn) + + if module.params['state'] == 'absent': + # mo must exist, but all properties do not have to match + if existing_mo: + if not module.check_mode: + ucs.login_handle.remove_mo(existing_mo) + ucs.result['changed'] = True + else: + if existing_mo: + # check mo props + kwargs = dict(managed_object['properties']) + # remove parent info and passwords because those aren't presented in the actual props + kwargs.pop('parent_mo_or_dn', None) + kwargs.pop('pwd', None) + kwargs.pop('password', None) + if existing_mo.check_prop_match(**kwargs): + props_match = True + + if not props_match: + if not module.check_mode: + ucs.login_handle.add_mo(mo, modify_present=True) + ucs.result['changed'] = True + + if managed_object.get('children'): + for child in managed_object['children']: + # explicit deep copy of child object since traverse_objects may modify parent mo information + copy_of_child = deepcopy(child) + traverse_objects(module, ucs, copy_of_child, mo) + + +def main(): + object_dict = dict( + module=dict(type='str', required=True), + class_name=dict(type='str', aliases=['class'], required=True), + properties=dict(type='dict', required=True), + children=dict(type='list'), + ) + argument_spec = ucs_argument_spec + argument_spec.update( + objects=dict(type='list', elements='dict', options=object_dict, required=True), + state=dict(type='str', choices=['present', 'absent'], default='present'), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + + if not HAS_IMPORT_MODULE: + module.fail_json(msg='import_module is required for this module') + ucs = UCSModule(module) + + # note that all objects specified in the object list report a single result (including a single changed). + ucs.result['changed'] = False + + for managed_object in module.params['objects']: + traverse_objects(module, ucs, managed_object) + # single commit for object and any children + if not module.check_mode and ucs.result['changed']: + try: + ucs.login_handle.commit() + except Exception as e: + # generic Exception because UCSM can throw a variety of exceptions + ucs.result['msg'] = "setup error: %s " % str(e) + module.fail_json(**ucs.result) + + module.exit_json(**ucs.result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_ntp_server.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_ntp_server.py new file mode 100644 index 00000000..a917ed60 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_ntp_server.py @@ -0,0 +1,169 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_ntp_server +short_description: Configures NTP server on Cisco UCS Manager +extends_documentation_fragment: cisco.ucs.ucs +description: +- Configures NTP server on Cisco UCS Manager. +options: + state: + description: + - If C(absent), will remove an NTP server. + - If C(present), will add or update an NTP server. + choices: [absent, present] + default: present + + ntp_server: + description: + - NTP server IP address or hostname. + - Enter up to 63 characters that form a valid hostname. + - Enter a valid IPV4 Address. + aliases: [ name ] + default: "" + + description: + description: + - A user-defined description of the NTP server. + - 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: "" + +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: "2.7" +''' + +EXAMPLES = r''' +- name: Configure NTP server + cisco.ucs.ucs_ntp_server: + hostname: 172.16.143.150 + username: admin + password: password + ntp_server: 10.10.10.10 + description: Internal NTP Server by IP address + state: present + +- name: Configure NTP server + cisco.ucs.ucs_ntp_server: + hostname: 172.16.143.150 + username: admin + password: password + ntp_server: pool.ntp.org + description: External NTP Server by hostname + state: present + +- name: Remove NTP server + cisco.ucs.ucs_ntp_server: + hostname: 172.16.143.150 + username: admin + password: password + ntp_server: 10.10.10.10 + state: absent + +- name: Remove NTP server + cisco.ucs.ucs_ntp_server: + hostname: 172.16.143.150 + username: admin + password: password + ntp_server: pool.ntp.org + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def run_module(): + argument_spec = ucs_argument_spec + argument_spec.update( + ntp_server=dict(type='str', aliases=['name']), + description=dict(type='str', aliases=['descr'], default=''), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['ntp_server']], + ], + ) + # UCSModule verifies ucsmsdk is present and exits on failure. Imports are below ucs object creation. + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.comm.CommNtpProvider import CommNtpProvider + + changed = False + try: + mo_exists = False + props_match = False + + dn = 'sys/svc-ext/datetime-svc/ntp-' + module.params['ntp_server'] + + 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 = CommNtpProvider(parent_mo_or_dn='sys/svc-ext/datetime-svc', + name=module.params['ntp_server'], + 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/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_org.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_org.py new file mode 100644 index 00000000..51237ca6 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_org.py @@ -0,0 +1,227 @@ +#!/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. + +extends_documentation_fragment: cisco.ucs.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 organization. + - 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 + 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: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: "2.8" +''' + +EXAMPLES = r''' +- name: Add UCS Organization + cisco.ucs.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 + cisco.ucs.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 + cisco.ucs.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 + cisco.ucs.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 + cisco.ucs.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 + cisco.ucs.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_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + 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']), + 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 + requested_state = module.params['state'] + + kwargs = dict() + + if module.params['description'] is not None: + kwargs['descr'] = module.params['description'] + + try: + 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) + + # Determine state change + if mo: + # Object exists, if it should exist has anything changed? + if requested_state == 'present': + # Do some or all Object properties not match, that is a change + if not mo.check_prop_match(**kwargs): + changed = True + + # Object does not exist but should, that is a change + else: + if requested_state == 'present': + changed = True + + # Object exists but should not, that is a change + if mo and requested_state == 'absent': + changed = True + + # Apply state if not check_mode + if changed and not module.check_mode: + if requested_state == 'absent': + ucs.login_handle.remove_mo(mo) + else: + kwargs['parent_mo_or_dn'] = parent_org_dn + kwargs['name'] = module.params['org_name'] + if module.params['description'] is not None: + kwargs['descr'] = module.params['description'] + + mo = OrgOrg(**kwargs) + ucs.login_handle.add_mo(mo, modify_present=True) + ucs.login_handle.commit() + + 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_query.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_query.py new file mode 100644 index 00000000..f9a7a1a0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_query.py @@ -0,0 +1,172 @@ +#!/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_query + +short_description: Queries UCS Manager objects by class or distinguished name + +description: + -Queries UCS Manager objects by class or distinguished name. + +extends_documentation_fragment: cisco.ucs.ucs + +options: + class_ids: + description: + - One or more UCS Manager Class IDs to query. + - As a comma separated list + type: str + + distinguished_names: + description: + - One or more UCS Manager Distinguished Names to query. + - As a comma separated list + 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: Query UCS Class ID + cisco.ucs.ucs_query: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + class_ids: computeBlade + delegate_to: localhost + +- name: Query UCS Class IDs + cisco.ucs.ucs_query: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + class_ids: computeBlade, fabricVlan + delegate_to: localhost + +- name: Query UCS Distinguished Name + cisco.ucs.ucs_query: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + distinguished_names: org-root + delegate_to: localhost + +- name: Query UCS Distinguished Names + cisco.ucs.ucs_query: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + distinguished_names: org-root, sys/rack-unit-1, sys/chassis-1/blade-2 + delegate_to: localhost +''' + +RETURN = ''' +objects: + description: results JSON encodded + type: dict +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def retrieve_class_id(class_id, ucs): + return ucs.login_handle.query_classid(class_id) + + +def retrieve_distinguished_name(distinguished_name, ucs): + return ucs.login_handle.query_dn(distinguished_name) + + +def make_mo_dict(ucs_mo): + obj_dict = {} + for mo_property in ucs_mo.prop_map.values(): + obj_dict[mo_property] = getattr(ucs_mo, mo_property) + return obj_dict + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + class_ids=dict(type='str'), + distinguished_names=dict(type='str'), + delegate_to=dict(type='str', default='localhost'), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=False, + mutually_exclusive=[ + ['class_ids', 'distinguished_names'], + ], + ) + + # UCSModule verifies ucsmsdk is present and exits on failure. + # Imports are below for UCS object creation. + ucs = UCSModule(module) + err = False + query_result = {} + + try: + if module.params['class_ids']: + class_ids = [ + x.strip() for x in module.params['class_ids'].split(',') + ] + for class_id in class_ids: + query_result[class_id] = [] + ucs_mos = retrieve_class_id(class_id, ucs) + if ucs_mos: + for ucs_mo in ucs_mos: + query_result[class_id].append(make_mo_dict(ucs_mo)) + + ucs.result['objects'] = query_result + + elif module.params['distinguished_names']: + distinguished_names = [ + x.strip() + for x in module.params['distinguished_names'].split(',') + ] + for distinguished_name in distinguished_names: + query_result[distinguished_name] = {} + ucs_mo = retrieve_distinguished_name(distinguished_name, ucs) + + if ucs_mo: + query_result[distinguished_name] = make_mo_dict(ucs_mo) + + ucs.result['objects'] = query_result + + except Exception as e: + err = True + ucs.result['msg'] = "setup error: %s " % str(e) + + if err: + module.fail_json(**ucs.result) + + module.exit_json(**ucs.result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_san_connectivity.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_san_connectivity.py new file mode 100644 index 00000000..7e9c1054 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_san_connectivity.py @@ -0,0 +1,248 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_san_connectivity +short_description: Configures SAN Connectivity Policies on Cisco UCS Manager +description: +- Configures SAN Connectivity Policies on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify SAN Connectivity Policies are present and will create if needed. + - If C(absent), will verify SAN Connectivity Policies are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the SAN Connectivity Policy. + - This name can be between 1 and 16 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the policy is created. + required: yes + description: + description: + - A description of the policy. + - Cisco recommends including information about where and when to use the policy. + - 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 ] + wwnn_pool: + description: + - Name of the WWNN pool to use for WWNN assignment. + default: default + vhba_list: + description: + - List of vHBAs used by the SAN Connectivity Policy. + - vHBAs used by the SAN Connectivity Policy must be created from a vHBA template. + - "Each list element has the following suboptions:" + - "= name" + - " The name of the virtual HBA (required)." + - "= vhba_template" + - " The name of the virtual HBA template (required)." + - "- adapter_policy" + - " The name of the Fibre Channel adapter policy." + - " A user defined policy can be used, or one of the system defined policies (default, Linux, Solaris, VMware, Windows, WindowsBoot)" + - " [Default: default]" + - "- order" + - " String specifying the vHBA assignment order (e.g., '1', '2')." + - " [Default: unspecified]" + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure SAN Connectivity Policy + cisco.ucs.ucs_san_connectivity: + hostname: 172.16.143.150 + username: admin + password: password + name: Cntr-FC-Boot + wwnn_pool: WWNN-Pool + vhba_list: + - name: Fabric-A + vhba_template: vHBA-Template-A + adapter_policy: Linux + - name: Fabric-B + vhba_template: vHBA-Template-B + adapter_policy: Linux + +- name: Remove SAN Connectivity Policy + cisco.ucs.ucs_san_connectivity: + hostname: 172.16.143.150 + username: admin + password: password + name: Cntr-FC-Boot + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str'), + descr=dict(type='str'), + wwnn_pool=dict(type='str', default='default'), + vhba_list=dict(type='list'), + state=dict(type='str', default='present', choices=['present', 'absent']), + san_connectivity_list=dict(type='list'), + ) + + # Note that use of san_connectivity_list is an experimental feature which allows multiple resource updates with a single UCSM connection. + # Support for san_connectivity_list may change or be removed once persistent UCS connections are supported. + # Either san_connectivity_list or name is required (user can specify either a list or single resource). + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_one_of=[ + ['san_connectivity_list', 'name'], + ], + mutually_exclusive=[ + ['san_connectivity_list', 'name'], + ], + ) + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.vnic.VnicSanConnPolicy import VnicSanConnPolicy + from ucsmsdk.mometa.vnic.VnicFcNode import VnicFcNode + from ucsmsdk.mometa.vnic.VnicFc import VnicFc + from ucsmsdk.mometa.vnic.VnicFcIf import VnicFcIf + + changed = False + try: + # Only documented use is a single resource, but to also support experimental + # feature allowing multiple updates all params are converted to a san_connectivity_list below. + + if module.params['san_connectivity_list']: + # directly use the list (single resource and list are mutually exclusive + san_connectivity_list = module.params['san_connectivity_list'] + else: + # single resource specified, create list from the current params + san_connectivity_list = [module.params] + for san_connectivity in san_connectivity_list: + mo_exists = False + props_match = False + # set default params. Done here to set values for lists which can't be done in the argument_spec + if not san_connectivity.get('descr'): + san_connectivity['descr'] = '' + if not san_connectivity.get('wwnn_pool'): + san_connectivity['wwnn_pool'] = 'default' + if san_connectivity.get('vhba_list'): + for vhba in san_connectivity['vhba_list']: + if not vhba.get('adapter_policy'): + vhba['adapter_policy'] = '' + if not vhba.get('order'): + vhba['order'] = 'unspecified' + # dn is <org_dn>/san-conn-pol-<name> + dn = module.params['org_dn'] + '/san-conn-pol-' + san_connectivity['name'] + + mo = ucs.login_handle.query_dn(dn) + if mo: + mo_exists = True + # check top-level mo props + kwargs = dict(descr=san_connectivity['descr']) + if (mo.check_prop_match(**kwargs)): + # top-level props match, check next level mo/props + # vnicFcNode object + child_dn = dn + '/fc-node' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(ident_pool_name=san_connectivity['wwnn_pool']) + if (mo_1.check_prop_match(**kwargs)): + if not san_connectivity.get('vhba_list'): + props_match = True + else: + # check vnicFc props + for vhba in san_connectivity['vhba_list']: + child_dn = dn + '/fc-' + vhba['name'] + mo_2 = ucs.login_handle.query_dn(child_dn) + kwargs = {} + kwargs['adaptor_profile_name'] = vhba['adapter_policy'] + kwargs['order'] = vhba['order'] + kwargs['nw_templ_name'] = vhba['vhba_template'] + if (mo_2.check_prop_match(**kwargs)): + props_match = 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = VnicSanConnPolicy( + parent_mo_or_dn=module.params['org_dn'], + name=san_connectivity['name'], + descr=san_connectivity['descr'], + ) + mo_1 = VnicFcNode( + parent_mo_or_dn=mo, + ident_pool_name=san_connectivity['wwnn_pool'], + addr='pool-derived', + ) + if san_connectivity.get('vhba_list'): + for vhba in san_connectivity['vhba_list']: + mo_2 = VnicFc( + parent_mo_or_dn=mo, + name=vhba['name'], + adaptor_profile_name=vhba['adapter_policy'], + nw_templ_name=vhba['vhba_template'], + order=vhba['order'], + ) + mo_2_1 = VnicFcIf( + parent_mo_or_dn=mo_2, + name='default', + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_scrub_policy.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_scrub_policy.py new file mode 100644 index 00000000..f6c262e6 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_scrub_policy.py @@ -0,0 +1,320 @@ +#!/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_scrub_policy + +short_description: Manages UCS Scrub Policies on UCS Manager + +description: + - Manages UCS Scrub Policies on UCS Manager. + +extends_documentation_fragment: cisco.ucs.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 + + name: + description: + - The name of the organization. + - 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), ' (single quote)." + required: true + 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), ' (single quote)." + aliases: [ descr ] + type: str + + bios_settings_scrub: + description: + - Scrub the BIOS settings. + - If the field is set to Yes, when a service profile containing this + - scrub policy is disassociated from a server, the BIOS settings for + - that server are erased and reset to the defaults for that server + - type and vendor. If this field is set to No, the BIOS settings are + - preserved. + - yes scrub the BIOS settings. + - no do not scrub the BIOS settings. + choices: [yes, no] + type: str + + disk_scrub: + description: + - Scrub the BIOS settings. + - If this field is set to Yes, when a service profile containing this + - scrub policy is disassociated from a server, all data on the server + - local drives is completely erased. If this field is set to No, the + - data on the local drives is preserved, including all local storage + - configuration. + - yes scrub the server disks. + - no do not scrub the server disks. + choices: [yes, no] + type: str + + flex_flash_scrub: + description: + - Scrub the BIOS settings. + - If the field is set to Yes, the HV partition on the SD card is + - formatted using the PNUOS formatting utility when the server is + - reacknowledged. If this field is set to No, the SD card is preserved. + - yes scrub the flex flash. + - no do not scrub the flex flash. + choices: [yes, no] + type: str + + persistent_memory_scrub: + description: + - Scrub the BIOS settings. + - If the field is set to Yes, when a service profile containing this + - scrub policy is disassociated from a server, all persistent memory + - modules for that server are erased and reset to the defaults for that + - server type and vendor. If this field is set to No, the persistent + - memory modules are preserved. + - yes scrub the persistent memory. + - no do not scrub the persistent memory. + choices: [yes, no] + type: str + + org_dn: + description: + - Org dn (distinguished name) + default: org-root + type: str + +requirements: +- ucsmsdk + +author: +- John McDonough (@movinalot) +version_added: "2.9" +''' + +EXAMPLES = r''' +- name: Add UCS Scrub Policy + cisco.ucs.ucs_scrub_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + description: Scrub All Policy + name: all_scrub + bios_settings_scrub: yes + disk_scrub: yes + flex_flash_scrub: yes + persistent_memory_scrub: yes + delegate_to: localhost + +- name: Add UCS Scrub Policy in an Organization + cisco.ucs.ucs_scrub_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + name: all_scrub + description: Scrub All Policy Org Prod servers + bios_settings_scrub: yes + disk_scrub: yes + flex_flash_scrub: yes + persistent_memory_scrub: yes + delegate_to: localhost + +- name: Update UCS Scrub Policy + cisco.ucs.ucs_scrub_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + name: BD_scrub + description: Scrub BIOS and Disk Policy Org Prod servers + bios_settings_scrub: yes + disk_scrub: yes + flex_flash_scrub: no + persistent_memory_scrub: no + delegate_to: localhost + +- name: Update UCS Scrub Policy + cisco.ucs.ucs_scrub_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + name: BD_scrub + description: Scrub BIOS and Disk Policy Org Prod servers + bios_settings_scrub: yes + disk_scrub: yes + flex_flash_scrub: yes + delegate_to: localhost + +- name: Delete UCS Scrub Policy + cisco.ucs.ucs_scrub_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: absent + org_dn: org-root/org-prod + name: BD_scrub + delegate_to: localhost + +- name: Delete UCS Scrub Policy + cisco.ucs.ucs_scrub_policy: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: absent + name: BD_scrub + delegate_to: localhost +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import ( + UCSModule, + ucs_argument_spec +) + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(required=True, type='str'), + descr=dict(type='str'), + description=dict(type='str', aliases=['descr']), + bios_settings_scrub=dict(type='str', choices=['yes', 'no']), + disk_scrub=dict(type='str', choices=['yes', 'no']), + flex_flash_scrub=dict(type='str', choices=['yes', 'no']), + persistent_memory_scrub=dict(type='str', choices=['yes', 'no']), + state=dict( + type='str', default='present', + choices=['present', 'absent'] + ), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['name']], + ], + ) + + # UCSModule verifies ucsmsdk is present and exits on failure. + # Imports are below for UCS object creation. + ucs = UCSModule(module) + from importlib import import_module + from ucsmsdk.ucscoreutils import get_meta_info + + # The Class(es) this module is managing + module_file = 'ucsmsdk.mometa.compute.ComputeScrubPolicy' + module_class = 'ComputeScrubPolicy' + mo_module = import_module(module_file) + mo_class = getattr(mo_module, module_class) + + META = get_meta_info(class_id=module_class) + + err = False + changed = False + requested_state = module.params['state'] + + kwargs = dict() + + # Manage Aliased Attributes + for attribute in ['descr:description']: + attribute_alias = attribute.split(':') + if module.params[attribute_alias[1]] is not None: + kwargs[attribute_alias[0]] = module.params[attribute_alias[1]] + + # Manage Attributes + for attribute in [ + 'bios_settings_scrub', + 'descr', + 'disk_scrub', + 'flex_flash_scrub', + 'persistent_memory_scrub' + ]: + if module.params[attribute] is not None: + kwargs[attribute] = module.params[attribute] + + try: + dn = ( + module.params['org_dn'] + '/' + + META.rn[0:META.rn.index('-') + 1] + + module.params['name'] + ) + mo = ucs.login_handle.query_dn(dn) + + # Determine state change + if mo: + # Object exists, if it should exist has anything changed? + if requested_state == 'present': + # Do some or all Object properties not match, that is a change + + if not mo.check_prop_match(**kwargs): + changed = True + + # Object does not exist but should, that is a change + else: + if requested_state == 'present': + changed = True + + # Object exists but should not, that is a change + if mo and requested_state == 'absent': + changed = True + + # Apply state if not check_mode + if changed and not module.check_mode: + if requested_state == 'absent': + ucs.login_handle.remove_mo(mo) + else: + kwargs['parent_mo_or_dn'] = module.params['org_dn'] + kwargs['name'] = module.params['name'] + + mo = mo_class(**kwargs) + ucs.login_handle.add_mo(mo, modify_present=True) + ucs.login_handle.commit() + + 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_serial_over_lan_policy.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_serial_over_lan_policy.py new file mode 100644 index 00000000..0dd9ba57 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_serial_over_lan_policy.py @@ -0,0 +1,271 @@ +#!/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_serial_over_lan_policy + +short_description: Manages UCS Serial Over Lan Policies on UCS Manager + +description: + - Manages UCS Serial Over Lan Policies on UCS Manager. + +extends_documentation_fragment: cisco.ucs.ucs + +options: + state: + description: + - If C(absent), will remove Serial Over Lan Policy. + - If C(present), will create or update Serial Over Lan Policy. + choices: [absent, present] + default: present + type: str + + name: + description: + - The name of the serial over lan policy. + - 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), ' (single quote)." + required: true + type: str + + description: + description: + - A user-defined description of the serial over lan policy. + - 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), ' (single quote)." + aliases: [ descr ] + type: str + + admin_state: + description: + - The administrative state of the serial over lan policy. + - disable Serial over LAN access is blocked. + - enable Serial over LAN access is permitted. + choices: [disable, enable] + type: str + + speed: + description: + - The transmission speed of the serial over lan policy. + choices: [9600, 19200, 38400, 57600, 115200] + type: str + + org_dn: + description: + - Org dn (distinguished name) of the serial over lan policy. + default: org-root + type: str + +requirements: +- ucsmsdk + +author: +- John McDonough (@movinalot) +version_added: "2.9" +''' + +EXAMPLES = r''' +- name: Add UCS Serial Over Lan Policy + cisco.ucs.ucs_serial_over_lan: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + name: sol_org_root + description: Serial Over Lan for Org root servers + admin_state: enable + speed: 115200 + delegate_to: localhost + +- name: Add UCS Serial Over Lan Policy in Organization + cisco.ucs.ucs_serial_over_lan: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + name: sol_org_prod + description: Serial Over Lan for Org Prod servers + admin_state: enable + speed: 115200 + delegate_to: localhost + +- name: Update UCS Serial Over Lan Policy in Organization + cisco.ucs.ucs_serial_over_lan: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + name: sol_org_prod + description: Serial Over Lan for Org Prod servers + admin_state: enable + speed: 38400 + delegate_to: localhost + +- name: Update UCS Serial Over Lan Policy in Organization + cisco.ucs.ucs_serial_over_lan: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: present + org_dn: org-root/org-prod + name: sol_org_prod + descr: Serial Over Lan for Org Prod servers + admin_state: enable + speed: 57600 + delegate_to: localhost + +- name: Delete UCS Serial Over Lan Policy in Organization + cisco.ucs.ucs_serial_over_lan: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: absent + org_dn: org-root/org-prod + name: sol_org_prod + delegate_to: localhost + +- name: Delete UCS Serial Over Lan Policy + cisco.ucs.ucs_serial_over_lan: + hostname: "{{ ucs_hostname }}" + username: "{{ ucs_username }}" + password: "{{ ucs_password }}" + state: absent + name: sol_org_root + delegate_to: localhost +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import ( + UCSModule, + ucs_argument_spec +) + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(required=True, type='str'), + descr=dict(type='str'), + description=dict(type='str', aliases=['descr']), + admin_state=dict(type='str', choices=['enable', 'disable']), + speed=dict(type='str', choices=[ + '9600', '19200', '38400', '57600', '115200' + ]), + state=dict( + type='str', default='present', + choices=['present', 'absent'] + ), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['name']], + ], + ) + + # UCSModule verifies ucsmsdk is present and exits on failure. + # Imports are below for UCS object creation. + ucs = UCSModule(module) + from importlib import import_module + from ucsmsdk.ucscoreutils import get_meta_info + + # The Class(es) this module is managing + module_file = 'ucsmsdk.mometa.sol.SolPolicy' + module_class = 'SolPolicy' + mo_module = import_module(module_file) + mo_class = getattr(mo_module, module_class) + + META = get_meta_info(class_id=module_class) + + err = False + changed = False + requested_state = module.params['state'] + + kwargs = dict() + + # Manage Aliased Attributes + for attribute in ['descr:description']: + attribute_alias = attribute.split(':') + if module.params[attribute_alias[1]] is not None: + kwargs[attribute_alias[0]] = module.params[attribute_alias[1]] + + # Manage Attributes + for attribute in ['admin_state', 'descr', 'speed']: + if module.params[attribute] is not None: + kwargs[attribute] = module.params[attribute] + + try: + dn = ( + module.params['org_dn'] + '/' + + META.rn[0:META.rn.index('-') + 1] + + module.params['name'] + ) + mo = ucs.login_handle.query_dn(dn) + + # Determine state change + if mo: + # Object exists, if it should exist has anything changed? + if requested_state == 'present': + # Do some or all Object properties not match, that is a change + + if not mo.check_prop_match(**kwargs): + changed = True + + # Object does not exist but should, that is a change + else: + if requested_state == 'present': + changed = True + + # Object exists but should not, that is a change + if mo and requested_state == 'absent': + changed = True + + # Apply state if not check_mode + if changed and not module.check_mode: + if requested_state == 'absent': + ucs.login_handle.remove_mo(mo) + else: + kwargs['parent_mo_or_dn'] = module.params['org_dn'] + kwargs['name'] = module.params['name'] + + mo = mo_class(**kwargs) + ucs.login_handle.add_mo(mo, modify_present=True) + ucs.login_handle.commit() + + 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_server_maintenance.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_server_maintenance.py new file mode 100644 index 00000000..a8aca943 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_server_maintenance.py @@ -0,0 +1,158 @@ +#!/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_server_maintenance +short_description: Creates Server Maintenance Policy on Cisco UCS Manager +version_added: 2.10 +description: +- Configures Server Maintenance Policy on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify Server Maintenance Policy is present and will create if needed. + - If C(absent), will verify Server Maintenance Policy is absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name assigned to the Server Maintenance Policy. + - The Server Maintenance Policy name is case sensitive. + - This name can be between 1 and 16 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the Server Maintenance Policy is created. + required: yes + description: + description: + - A description of the Server Maintenance Package Policy. + - Cisco recommends including information about where and when to use the policy. + - 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 ] + trigger_config: + description: + - This option is used in combination with either User Ack (user-ack) or Timer Automatic (timer-automatic). + - When the On Next Boot option is enabled, the host OS reboot, shutdown, or server reset also triggers the associated FSM to apply the changes. + - Note that de-selecting the On Next Boot option disables the Maintenance Policy on the BMC. + choices: [on-next-boot] + uptime_disr: + description: + - When a Server profile is associated with a Server, or when changes are made to a Server profile that is already associated with a Server, you must reboot the Server to complete the process. + - The Reboot Policy field determines when the reboot occurs for Server associated with any Server profiles that include this maintenance policy. + choices: [immediate, timer-automatic, user-ack] + required: true +requirements: +- ucsmsdk +author: +- Brett Johnson (@brettjohnson008) +''' + +EXAMPLES = r''' +- name: Add Server Maintenance Policy + cisco.ucs.ucs_server_maintenance: + hostname: 172.16.143.150 + username: admin + password: password + name: user-ack + uptime_disr: user-ack + trigger_config: on-next-boot +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + name=dict(type='str', required=True), + description=dict(type='str', default=''), + trigger_config=dict(type='str', default='', choices=['on-next-boot']), + uptime_disr=dict(type='str', required=True, choices=['immediate', 'timer-automatic', 'user-ack']), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + + ucs = UCSModule(module) + + err = False + + # UCSModule creation above verifies ucsmsdk is present and exits on failure, so additional imports are done below. + from ucsmsdk.mometa.lsmaint.LsmaintMaintPolicy import LsmaintMaintPolicy + + changed = False + try: + mo_exists = False + props_match = False + dn_base = 'org-root' + dn = dn_base + '/maint-' + module.params['name'] + + 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(name=module.params['name']) + kwargs['descr'] = module.params['description'] + kwargs['trigger_config'] = module.params['trigger_config'] + kwargs['uptime_disr'] = module.params['uptime_disr'] + if mo.check_prop_match(**kwargs): + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = LsmaintMaintPolicy( + parent_mo_or_dn=dn_base, + name=module.params['name'], + descr=module.params['description'], + trigger_config=module.params['trigger_config'], + uptime_disr=module.params['uptime_disr'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_association.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_association.py new file mode 100644 index 00000000..81d9aa4b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_association.py @@ -0,0 +1,252 @@ +#!/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_service_profile_association +short_description: Configures Service Profile Association on Cisco UCS Manager +description: +- Configures Service Profile Association (change association or disassociate) on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify service profile association and associate with specified server or server pool if needed. + - If C(absent), will verify service profile is not associated and will disassociate if needed. This is the same as specifying Assign Later in the webUI. + choices: [present, absent] + default: present + service_profile_name: + description: + - The name of the Service Profile being associated or disassociated. + required: yes + server_assignment: + description: + - "Specifies how to associate servers with this service profile using the following choices:" + - "server - Use to pre-provision a slot or select an existing server. Slot or server is specified by the server_dn option." + - "pool - Use to select from a server pool. The server_pool option specifies the name of the server pool to use." + - Option is not valid if the service profile is bound to a template. + - Optional if the state is absent. + choices: [server, pool] + required: yes + server_dn: + description: + - The Distinguished Name (dn) of the server object used for pre-provisioning or selecting an existing server. + - Required if the server_assignment option is server. + - Optional if the state is absent. + server_pool_name: + description: + - Name of the server pool used for server pool based assignment. + - Required if the server_assignment option is pool. + - Optional if the state is absent. + restrict_migration: + description: + - Restricts the migration of the service profile after it has been associated with a server. + - If set to no, Cisco UCS Manager does not perform any compatibility checks on the new server before migrating the existing service profile. + - If set to no and the hardware of both servers used in migration are not similar, the association might fail. + choices: ['yes', 'no'] + default: 'no' + org_dn: + description: + - The distinguished name (dn) of the organization where the resource is assigned. + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +version_added: 2.10 +''' + +EXAMPLES = r''' +- name: Change Service Profile Association to server pool Container-Pool and restrict migration + cisco.ucs.ucs_service_profile_association: + hostname: 172.16.143.150 + username: admin + password: password + service_profile_name: test-sp + server_assignment: pool + server_pool_name: Container-Pool + restrict_migration: 'yes' + +- name: Attempt to change association once a minute for up to 10 minutes + cisco.ucs.ucs_service_profile_association: + hostname: 172.16.143.150 + username: admin + password: password + service_profile_name: test-sp + server_assignment: server + server_dn: sys/chassis-2/blade-1 + register: result + until: result.assign_state == 'assigned' and result.assoc_state == 'associated' + retries: 10 + delay: 60 + +- name: Disassociate Service Profile + cisco.ucs.ucs_service_profile_association: + hostname: 172.16.143.150 + username: admin + password: password + service_profile_name: test-sp + state: absent +''' + +RETURN = r''' +assign_state: + description: The logical server Assigned State (assigned, unassigned, or failed). + returned: success + type: string + sample: assigned +assoc_state: + description: The logical server Association State (associated or unassociated). + returned: success + type: string + sample: associated +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + service_profile_name=dict(type='str', required=True), + server_assignment=dict(type='str', choices=['server', 'pool']), + server_dn=dict(type='str'), + server_pool_name=dict(type='str'), + restrict_migration=dict(type='str', default='no', choices=['yes', 'no']), + state=dict(default='present', choices=['present', 'absent'], type='str'), + ) + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['server_assignment']], + ['server_assignment', 'server', ['server_dn']], + ['server_assignment', 'pool', ['server_pool_name']], + ], + mutually_exclusive=[ + ['server_dn', 'server_pool_name'], + ], + ) + # UCSModule verifies ucsmsdk is present and exits on failure. Imports are below ucs object creation. + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.ls.LsRequirement import LsRequirement + from ucsmsdk.mometa.ls.LsBinding import LsBinding + from ucsmsdk.mometa.ls.LsServer import LsServer + + changed = False + ucs.result['assign_state'] = 'unassigned' + ucs.result['assoc_state'] = 'unassociated' + try: + ls_mo_exists = False + pn_mo_exists = False + pn_req_mo_exists = False + props_match = False + + # logical server distinguished name is <org>/ls-<name> and physical node dn appends 'pn' or 'pn-req' + ls_dn = module.params['org_dn'] + '/ls-' + module.params['service_profile_name'] + ls_mo = ucs.login_handle.query_dn(ls_dn) + if ls_mo: + ls_mo_exists = True + pn_dn = ls_dn + '/pn' + pn_mo = ucs.login_handle.query_dn(pn_dn) + if pn_mo: + pn_mo_exists = True + + pn_req_dn = ls_dn + '/pn-req' + pn_req_mo = ucs.login_handle.query_dn(pn_req_dn) + if pn_req_mo: + pn_req_mo_exists = True + + if module.params['state'] == 'absent': + if ls_mo_exists and ls_mo.assign_state != 'unassigned': + if pn_mo_exists: + if not module.check_mode: + ucs.login_handle.remove_mo(pn_mo) + ucs.login_handle.commit() + changed = True + elif pn_req_mo_exists: + if not module.check_mode: + ucs.login_handle.remove_mo(pn_req_mo) + ucs.login_handle.commit() + changed = True + elif ls_mo_exists: + # check if logical server is assigned and associated + ucs.result['assign_state'] = ls_mo.assign_state + ucs.result['assoc_state'] = ls_mo.assoc_state + if module.params['server_assignment'] == 'pool' and pn_req_mo_exists: + # check the current pool + kwargs = dict(name=module.params['server_pool_name']) + kwargs['restrict_migration'] = module.params['restrict_migration'] + if pn_req_mo.check_prop_match(**kwargs): + props_match = True + elif pn_mo_exists: + kwargs = dict(pn_dn=module.params['server_dn']) + kwargs['restrict_migration'] = module.params['restrict_migration'] + if pn_mo.check_prop_match(**kwargs): + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist in desired state + mo = LsServer( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['service_profile_name'], + ) + if module.params['server_assignment'] == 'pool': + if pn_mo_exists: + ucs.login_handle.remove_mo(pn_mo) + + mo_1 = LsRequirement( + parent_mo_or_dn=mo, + name=module.params['server_pool_name'], + restrict_migration=module.params['restrict_migration'], + ) + else: + mo_1 = LsBinding( + parent_mo_or_dn=mo, + pn_dn=module.params['server_dn'], + restrict_migration=module.params['restrict_migration'], + ) + ucs.login_handle.add_mo(mo_1, True) + ucs.login_handle.commit() + + pn_req_mo = ucs.login_handle.query_dn(pn_req_dn) + if pn_req_mo: + # profiles from templates will add a server pool, so remove and add the server again + ucs.login_handle.remove_mo(pn_req_mo) + + ucs.login_handle.add_mo(mo_1, True) + ucs.login_handle.commit() + ls_mo = ucs.login_handle.query_dn(ls_dn) + if ls_mo: + ucs.result['assign_state'] = ls_mo.assign_state + ucs.result['assoc_state'] = ls_mo.assoc_state + 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_from_template.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_from_template.py new file mode 100644 index 00000000..0c1bc60d --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_from_template.py @@ -0,0 +1,177 @@ +#!/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_service_profile_from_template +short_description: Configures Service Profiles from templates on Cisco UCS Manager +description: +- Configures Service Profile created from templates on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify Service Profiles are present and will create if needed. + - If C(absent), will verify Service Profiles are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the service profile. + - This name can be between 2 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - This name must be unique across all service profiles and service profile templates within the same organization. + required: yes + source_template: + description: + - The name of the service profile template used to create this serivce profile. + required: yes + power_state: + description: + - The power state to be applied when this service profile is associated with a server. + - If no value is provided, the power_state for the service profile will not be modified. + choices: [up, down] + user_label: + description: + - The User Label you want to assign to this service profile. + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure Service Profile from Template + cisco.ucs.ucs_service_profile_from_template: + hostname: 172.16.143.150 + username: admin + password: password + name: test-sp-instance1 + source_template: test-sp + +- name: Remove Service Profile + cisco.ucs.ucs_service_profile_from_template: + hostname: 172.16.143.150 + username: admin + password: password + name: test-sp-instance1 + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + source_template=dict(type='str', required=True), + user_label=dict(type='str', default=''), + power_state=dict(type='str', choices=['up', 'down']), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + ucs = UCSModule(module) + + err = False + + # UCSModule creation above verifies ucsmsdk is present and exits on failure. Additional imports are done below. + from ucsmsdk.mometa.ls.LsServer import LsServer + from ucsmsdk.mometa.ls.LsPower import LsPower + + changed = False + try: + mo_exists = False + props_match = False + dn = module.params['org_dn'] + '/ls-' + module.params['name'] + + 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(src_templ_name=module.params['source_template']) + kwargs['usr_lbl'] = module.params['user_label'] + # service profiles are of type 'instance' + kwargs['type'] = 'instance' + + if mo.check_prop_match(**kwargs): + # top-level props match + if module.params.get('power_state'): + child_dn = dn + '/power' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(state=module.params['power_state']) + if mo_1.check_prop_match(**kwargs): + props_match = True + else: + # no power state provided, use existing state as match + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = LsServer( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + src_templ_name=module.params['source_template'], + type='instance', + usr_lbl=module.params['user_label'], + ) + if module.params.get('power_state'): + admin_state = 'admin-' + module.params['power_state'] + mo_1 = LsPower( + parent_mo_or_dn=mo, + state=admin_state, + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_template.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_template.py new file mode 100644 index 00000000..0c6f2e71 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_service_profile_template.py @@ -0,0 +1,523 @@ +#!/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_service_profile_template +short_description: Configures Service Profile Templates on Cisco UCS Manager +description: +- Configures Service Profile Templates on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify Service Profile Templates are present and will create if needed. + - If C(absent), will verify Service Profile Templates are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the service profile template. + - This name can be between 2 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - This name must be unique across all service profiles and service profile templates within the same organization. + required: yes + template_type: + description: + - "The template type field which can be one of the following:" + - "initial-template — Any service profiles created from this template are not updated if the template changes." + - "updating-template — Any service profiles created from this template are updated if the template changes." + choices: [initial-template, updating-template] + default: initial-template + uuid_pool: + description: + - Specifies how the UUID will be set on a server associated with a service profile created from this template. + - "The uuid_pool option can be the name of the UUID pool to use or '' (the empty string)." + - An empty string will use the UUID assigned to the server by the manufacturer, and the + - UUID remains unassigned until a service profile created from this template is associated with a server. At that point, + - the UUID is set to the UUID value assigned to the server by the manufacturer. If the service profile is later moved to + - a different server, the UUID is changed to match the new server." + default: default + description: + description: + - A user-defined description of the service profile template. + - 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 ] + storage_profile: + description: + - The name of the storage profile you want to associate with service profiles created from this template + local_disk_policy: + description: + - The name of the local disk policy you want to associate with service profiles created from this template. + lan_connectivity_policy: + description: + - The name of the LAN connectivity policy you want to associate with service profiles created from this template. + iqn_pool: + description: + - The name of the IQN pool (initiator) you want to apply to all iSCSI vNICs for service profiles created from this template. + san_connectivity_policy: + description: + - The name of the SAN connectivity policy you want to associate with service profiles created from this template. + vmedia_policy: + description: + - The name of the vMedia policy you want to associate with service profiles created from this template. + boot_policy: + description: + - The name of the boot order policy you want to associate with service profiles created from this template. + default: default + maintenance_policy: + description: + - The name of the maintenance policy you want to associate with service profiles created from this template. + server_pool: + description: + - The name of the server pool you want to associate with this service profile template. + server_pool_qualification: + description: + - The name of the server pool policy qualificaiton you want to use for this service profile template. + power_state: + description: + - The power state to be applied when a service profile created from this template is associated with a server. + choices: [up, down] + default: up + host_firmware_package: + description: + - The name of the host firmware package you want to associate with service profiles created from this template. + bios_policy: + description: + - The name of the BIOS policy you want to associate with service profiles created from this template. + ipmi_access_profile: + description: + - The name of the IPMI access profile you want to associate with service profiles created from this template. + sol_policy: + description: + - The name of the Serial over LAN (SoL) policy you want to associate with service profiles created from this template. + mgmt_ip_state: + description: + - The state for the Outband Management IP pool you want to use with service profiles created from this template. + choices: [none, pooled] + default: pooled + mgmt_ip_pool: + description: + - The name of the Outband Management IP pool you want to use with service profiles created from this template. + default: ext-mgmt + power_control_policy: + description: + - The name of the power control policy you want to associate with service profiles created from this template. + default: default + power_sync_policy: + description: + - The name of the power sync policy you want to associate with service profiles created from this template. + scrub_policy: + description: + - The name of the scrub policy you want to associate with service profiles created from this template. + kvm_mgmt_policy: + description: + - The name of the KVM management policy you want to associate with service profiles created from this template. + graphics_card_policy: + description: + - The name of the graphics card policy you want to associate with service profiles created from this template. + threshold_policy: + description: + - The name of the threshold policy you want to associate with service profiles created from this template. + default: default + user_label: + description: + - The User Label you want to assign to service profiles created from this template. + mgmt_interface_mode: + description: + - The Management Interface you want to assign to service profiles created from this template. + choices: ['', in-band] + mgmt_vnet_name: + description: + - A VLAN selected from the associated VLAN group. + mgmt_inband_pool_name: + description: + - How the inband management IPv4 address is derived for the server associated with this service profile. + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +version_added: '2.8' +''' + +EXAMPLES = r''' +- name: Configure Service Profile Template with LAN/SAN Connectivity and all other options defaulted + cisco.ucs.ucs_service_profile_template: + hostname: 172.16.143.150 + username: admin + password: password + name: DEE-Ctrl + template_type: updating-template + uuid_pool: UUID-Pool + storage_profile: DEE-StgProf + lan_connectivity_policy: Cntr-FC-Boot + iqn_pool: iSCSI-Boot-A + san_connectivity_policy: Cntr-FC-Boot + boot_policy: DEE-vMedia + maintenance_policy: default + server_pool: Container-Pool + host_firmware_package: 3.1.2b + bios_policy: Docker + +- name: Remove Service Profile Template + cisco.ucs.ucs_service_profile_template: + hostname: 172.16.143.150 + username: admin + password: password + name: DEE-Ctrl + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def configure_service_profile_template(ucs, module): + from ucsmsdk.mometa.ls.LsServer import LsServer + from ucsmsdk.mometa.vnic.VnicConnDef import VnicConnDef + from ucsmsdk.mometa.vnic.VnicIScsiNode import VnicIScsiNode + from ucsmsdk.mometa.ls.LsRequirement import LsRequirement + from ucsmsdk.mometa.ls.LsPower import LsPower + from ucsmsdk.mometa.lstorage.LstorageProfileBinding import LstorageProfileBinding + from ucsmsdk.mometa.mgmt.MgmtInterface import MgmtInterface + from ucsmsdk.mometa.mgmt.MgmtVnet import MgmtVnet + from ucsmsdk.mometa.vnic.VnicIpV4MgmtPooledAddr import VnicIpV4MgmtPooledAddr + + if not module.check_mode: + try: + # create if mo does not already exist + mo = LsServer( + parent_mo_or_dn=module.params['org_dn'], + bios_profile_name=module.params['bios_policy'], + boot_policy_name=module.params['boot_policy'], + descr=module.params['description'], + ext_ip_state=module.params['mgmt_ip_state'], + ext_ip_pool_name=module.params['mgmt_ip_pool'], + # graphics_card_policy_name=module.params['graphics_card_policy'], + host_fw_policy_name=module.params['host_firmware_package'], + ident_pool_name=module.params['uuid_pool'], + kvm_mgmt_policy_name=module.params['kvm_mgmt_policy'], + local_disk_policy_name=module.params['local_disk_policy'], + maint_policy_name=module.params['maintenance_policy'], + mgmt_access_policy_name=module.params['ipmi_access_profile'], + name=module.params['name'], + power_policy_name=module.params['power_control_policy'], + power_sync_policy_name=module.params['power_sync_policy'], + scrub_policy_name=module.params['scrub_policy'], + sol_policy_name=module.params['sol_policy'], + stats_policy_name=module.params['threshold_policy'], + type=module.params['template_type'], + usr_lbl=module.params['user_label'], + vmedia_policy_name=module.params['vmedia_policy'], + ) + + if module.params['storage_profile']: + # Storage profile + mo_1 = LstorageProfileBinding( + parent_mo_or_dn=mo, + storage_profile_name=module.params['storage_profile'], + ) + + if module.params['mgmt_interface_mode']: + # Management Interface + mo_1 = MgmtInterface( + parent_mo_or_dn=mo, + mode=module.params['mgmt_interface_mode'], + ip_v4_state='pooled', + ) + mo_2 = MgmtVnet( + parent_mo_or_dn=mo_1, + id='1', + name=module.params['mgmt_vnet_name'], + ) + VnicIpV4MgmtPooledAddr( + parent_mo_or_dn=mo_2, + name=module.params['mgmt_inband_pool_name'], + ) + + # LAN/SAN connectivity policy + mo_1 = VnicConnDef( + parent_mo_or_dn=mo, + lan_conn_policy_name=module.params['lan_connectivity_policy'], + san_conn_policy_name=module.params['san_connectivity_policy'], + ) + + if module.params['iqn_pool']: + # IQN pool + mo_1 = VnicIScsiNode( + parent_mo_or_dn=mo, + iqn_ident_pool_name=module.params['iqn_pool'] + ) + + # power state + admin_state = 'admin-' + module.params['power_state'] + mo_1 = LsPower( + parent_mo_or_dn=mo, + state=admin_state, + ) + + if module.params['server_pool']: + # server pool + mo_1 = LsRequirement( + parent_mo_or_dn=mo, + name=module.params['server_pool'], + qualifier=module.params['server_pool_qualification'], + ) + + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + except Exception as e: # generic Exception handling because SDK can throw a variety of exceptions + ucs.result['msg'] = "setup error: %s " % str(e) + module.fail_json(**ucs.result) + + ucs.result['changed'] = True + + +def check_storage_profile_props(ucs, module, dn): + props_match = False + + child_dn = dn + '/profile-binding' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(storage_profile_name=module.params['storage_profile']) + if mo_1.check_prop_match(**kwargs): + props_match = True + elif not module.params['storage_profile']: + # no stroage profile mo or desired state + props_match = True + + return props_match + + +def check_connectivity_policy_props(ucs, module, dn): + props_match = False + + child_dn = dn + '/conn-def' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(lan_conn_policy_name=module.params['lan_connectivity_policy']) + kwargs['san_conn_policy_name'] = module.params['san_connectivity_policy'] + if mo_1.check_prop_match(**kwargs): + props_match = True + elif not module.params['lan_connectivity_policy'] and not module.params['san_connectivity_policy']: + # no mo and no desired state + props_match = True + + return props_match + + +def check_iqn_pool_props(ucs, module, dn): + props_match = False + + child_dn = dn + '/iscsi-node' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(iqn_ident_pool_name=module.params['iqn_pool']) + if mo_1.check_prop_match(**kwargs): + props_match = True + elif not module.params['iqn_pool']: + # no mo and no desired state + props_match = True + + return props_match + + +def check_inband_management_props(ucs, module, dn): + props_match = False + + child_dn = dn + '/iface-in-band' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(mode=module.params['mgmt_interface_mode']) + if mo_1.check_prop_match(**kwargs): + child_dn = child_dn + '/network' + mo_2 = ucs.login_handle.query_dn(child_dn) + if mo_2: + kwargs = dict(name=module.params['mgmt_vnet_name']) + if mo_2.check_prop_match(**kwargs): + child_dn = child_dn + '/ipv4-pooled-addr' + mo_3 = ucs.login_handle.query_dn(child_dn) + if mo_3: + kwargs = dict(name=module.params['mgmt_inband_pool_name']) + if mo_3.check_prop_match(**kwargs): + props_match = True + elif not module.params['mgmt_interface_mode']: + # no mo and no desired state + props_match = True + + return props_match + + +def check_power_props(ucs, module, dn): + props_match = False + + child_dn = dn + '/power' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(state=module.params['power_state']) + if mo_1.check_prop_match(**kwargs): + props_match = True + elif not module.params['power_state']: + # no mo and no desired state + props_match = True + + return props_match + + +def check_server_pool(ucs, module, dn): + props_match = False + + child_dn = dn + '/pn-req' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(name=module.params['server_pool']) + kwargs['qualifier'] = module.params['server_pool_qualification'] + if mo_1.check_prop_match(**kwargs): + props_match = True + elif not module.params['server_pool']: + # no pn-req object and no server pool name provided + props_match = True + + return props_match + + +def check_serivce_profile_templates_props(ucs, module, mo, dn): + props_match = False + + # check top-level mo props + kwargs = dict(bios_profile_name=module.params['bios_policy']) + kwargs['boot_policy_name'] = module.params['boot_policy'] + kwargs['descr'] = module.params['description'] + kwargs['ext_ip_state'] = module.params['mgmt_ip_state'] + kwargs['ext_ip_pool_name'] = module.params['mgmt_ip_pool'] + # kwargs['graphics_card_policy_name'] = module.params['graphics_card_policy'] + kwargs['host_fw_policy_name'] = module.params['host_firmware_package'] + kwargs['ident_pool_name'] = module.params['uuid_pool'] + kwargs['kvm_mgmt_policy_name'] = module.params['kvm_mgmt_policy'] + kwargs['local_disk_policy_name'] = module.params['local_disk_policy'] + kwargs['maint_policy_name'] = module.params['maintenance_policy'] + kwargs['mgmt_access_policy_name'] = module.params['ipmi_access_profile'] + kwargs['power_policy_name'] = module.params['power_control_policy'] + kwargs['power_sync_policy_name'] = module.params['power_sync_policy'] + kwargs['scrub_policy_name'] = module.params['scrub_policy'] + kwargs['sol_policy_name'] = module.params['sol_policy'] + kwargs['stats_policy_name'] = module.params['threshold_policy'] + kwargs['type'] = module.params['template_type'] + kwargs['usr_lbl'] = module.params['user_label'] + kwargs['vmedia_policy_name'] = module.params['vmedia_policy'] + + if mo.check_prop_match(**kwargs): + # top-level props match, check next level mo/props + # code below should discontinue checks once any mismatch is found + + # check storage profile 1st + props_match = check_storage_profile_props(ucs, module, dn) + + if props_match: + props_match = check_connectivity_policy_props(ucs, module, dn) + + if props_match: + props_match = check_iqn_pool_props(ucs, module, dn) + + if props_match: + props_match = check_inband_management_props(ucs, module, dn) + + if props_match: + props_match = check_power_props(ucs, module, dn) + + if props_match: + props_match = check_server_pool(ucs, module, dn) + + return props_match + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + bios_policy=dict(type='str', default=''), + boot_policy=dict(type='str', default='default'), + description=dict(type='str', aliases=['descr'], default=''), + mgmt_ip_state=dict(type='str', default='pooled'), + mgmt_ip_pool=dict(type='str', default='ext-mgmt'), + graphics_card_policy=dict(type='str', default=''), + host_firmware_package=dict(type='str', default=''), + uuid_pool=dict(type='str', default='default'), + kvm_mgmt_policy=dict(type='str', default=''), + local_disk_policy=dict(type='str', default=''), + maintenance_policy=dict(type='str', default=''), + ipmi_access_profile=dict(type='str', default=''), + power_control_policy=dict(type='str', default='default'), + power_sync_policy=dict(type='str', default=''), + scrub_policy=dict(type='str', default=''), + sol_policy=dict(type='str', default=''), + threshold_policy=dict(type='str', default='default'), + template_type=dict(type='str', default='initial-template', choices=['initial-template', 'updating-template']), + user_label=dict(type='str', default=''), + vmedia_policy=dict(type='str', default=''), + storage_profile=dict(type='str', default=''), + lan_connectivity_policy=dict(type='str', default=''), + iqn_pool=dict(type='str', default=''), + san_connectivity_policy=dict(type='str', default=''), + server_pool=dict(type='str', default=''), + server_pool_qualification=dict(type='str', default=''), + power_state=dict(type='str', default='up', choices=['up', 'down']), + mgmt_interface_mode=dict(type='str', default='', choices=['', 'in-band']), + mgmt_vnet_name=dict(type='str', default=''), + mgmt_inband_pool_name=dict(type='str', default=''), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + ucs = UCSModule(module) + # UCSModule creation above verifies ucsmsdk is present and exits on failure. + # Additional imports are done below or in called functions. + + ucs.result['changed'] = False + props_match = False + # dn is <org_dn>/ls-<name> + dn = module.params['org_dn'] + '/ls-' + module.params['name'] + + mo = ucs.login_handle.query_dn(dn) + if mo: + if module.params['state'] == 'absent': + # mo must exist but all properties do not have to match + if not module.check_mode: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + ucs.result['changed'] = True + else: # state == 'present' + props_match = check_serivce_profile_templates_props(ucs, module, mo, dn) + + if module.params['state'] == 'present' and not props_match: + configure_service_profile_template(ucs, module) + + module.exit_json(**ucs.result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_sp_vnic_order.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_sp_vnic_order.py new file mode 100644 index 00000000..6498323c --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_sp_vnic_order.py @@ -0,0 +1,230 @@ +#!/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.0', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = r''' +--- +module: ucs_sp_vnic_order + +short_description: Configures vNIC order for service profiles and templates on Cisco UCS Manager + +version_added: 2.10 + +description: + - Configures Configures vNIC order for service profiles and templates on Cisco UCS Manager + +options: + sp_name: + description: DN of the service profile + vnics: + description: List of vNIC order properties + suboptions: + name: + description: Name of the vNIC + required: true + admin_vcon: + description: Name of the virtual connection + choices: ["1","2","3","4","any"] + order: + description: vNIC connection order + choices: ["unspecified", "0-256"] + transport: + description: transport medium + choices: ["ethernet", "fc"] + required: true + state: + description: Desired state of the vNIC. + choices: [present, absent] + default: present + org_dn: + description: root org dn +extends_documentation_fragment: + - cisco.ucs.ucs +requirements: + - ucsmsdk +author: + - Brett Johnson (@sdbrett) + +''' + +EXAMPLES = r''' +- name: Configure vnic order + cisco.ucs.ucs_sp_vnic_order: + sp_name: my_sp + vnics: + - name: 'my_vnic' + admin_vcon: '1' + order: '1' + transport: 'ethernet' + hostname: 192.168.99.100 + username: admin + password: password +- name: Configure vhba order + cisco.ucs.ucs_sp_vnic_order: + sp_name: my_sp + vnics: + - name: 'my_vhba' + admin_vcon: '2' + order: '1' + transport: 'fc' + hostname: 192.168.99.100 + username: admin + password: password +- name: Configure vnic and vhba order + cisco.ucs.ucs_sp_vnic_order: + sp_name: my_sp + vnics: + - name: my_vhba + admin_vcon: '2' + order: '1' + transport: fc + - name: my_vnic + admin_vcon: '1' + order: '1' + transport: ethernet + hostname: 192.168.99.100 + username: admin + password: password +- name: Remove vnic order configuration from my_vnic + cisco.ucs.ucs_sp_vnic_order: + sp_name: my_sp + vnics: + - name: 'my_vnic' + transport: ethernet + state: absent + hostname: 192.168.99.100 + username: admin + password: password + +''' + +RETURN = r''' +# +''' + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def get_service_profile(handle, org_dn, sp_name): + dn = org_dn + "/ls-" + sp_name + sp = handle.query_dn(dn) + return sp + + +def update_vnic_assignment_order(ucs, vnic, sp): + from ucsmsdk.mometa.ls.LsVConAssign import LsVConAssign + + mo = LsVConAssign(parent_mo_or_dn=sp, admin_vcon=vnic['admin_vcon'], + order=vnic['order'], transport=vnic['transport'], + vnic_name=vnic['name']) + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + + +def remove_vnic_assignment_order(ucs, vnic, sp): + from ucsmsdk.mometa.ls.LsVConAssign import LsVConAssign + + mo = LsVConAssign(parent_mo_or_dn=sp, admin_vcon='any', + order='unspecified', transport=vnic['transport'], + vnic_name=vnic['name']) + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + + +def get_vnic(ucs, dn): + return ucs.login_handle.query_dn(dn) + + +def get_vnic_dn(sp_dn, transport, name): + if transport == 'ethernet': + return sp_dn + '/ether-' + name + return sp_dn + '/fc-' + name + + +def matches_existing_vnic_order(vnic, vnic_mo): + if vnic['state'] == 'absent': + kwargs = dict(admin_vcon='any') + kwargs['order'] = 'unspecified' + else: + kwargs = dict(admin_vcon=vnic['admin_vcon']) + kwargs['order'] = vnic['order'] + + if vnic['transport'] == 'ethernet': + kwargs['type'] = 'ether' + else: + kwargs['type'] = vnic['transport'] + return vnic_mo.check_prop_match(**kwargs) + + +def main(): + vnic_spec = dict( + name=dict(type='str', required=True), + admin_vcon=dict(type='str', choices=['1', '2', '3', '4', 'any']), + order=dict(type='str'), + transport=dict(type='str', required=True, choices=['ethernet', 'fc']), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + argument_spec = ucs_argument_spec + argument_spec.update( + sp_name=dict(required=True, type='str'), + vnics=dict(required=True, type='list', elements='dict', options=vnic_spec), + org_dn=dict(required=False, type='str', default='org-root'), + ) + module = AnsibleModule(argument_spec, + supports_check_mode=True) + ucs = UCSModule(module) + + err = False + changed = False + + try: + sp_dn = dn = module.params['org_dn'] + "/ls-" + module.params['sp_name'] + sp = ucs.login_handle.query_dn(dn) + if not sp: + raise ValueError("SP '%s' does not exist" % sp_dn) + + for vnic in module.params['vnics']: + vnic_mo = get_vnic(ucs, (get_vnic_dn(sp_dn, vnic['transport'], vnic['name']))) + + if vnic['state'] != 'absent' and not vnic_mo: + raise ValueError("vNIC '%s' is not assigned to service profile '%s'" % (vnic['name'], sp_dn)) + + if vnic_mo: + if not matches_existing_vnic_order(vnic, vnic_mo): + changed = True + break + + if changed and not module.check_mode: + for vnic in module.params['vnics']: + vnic_mo = get_vnic(ucs, (get_vnic_dn(sp_dn, vnic['transport'], vnic['name']))) + if vnic['state'] == 'absent' and vnic_mo: + remove_vnic_assignment_order(ucs, vnic, sp) + elif not vnic_mo: + + update_vnic_assignment_order(ucs, vnic, sp) + elif not matches_existing_vnic_order(vnic, vnic_mo): + update_vnic_assignment_order(ucs, vnic, sp) + + 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_storage_profile.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_storage_profile.py new file mode 100644 index 00000000..9ca825a8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_storage_profile.py @@ -0,0 +1,254 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_storage_profile +short_description: Configures storage profiles on Cisco UCS Manager +description: +- Configures storage profiles on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify that the storage profile is present and will create if needed. + - If C(absent), will verify that the storage profile is absent and will delete if needed. + choices: [ absent, present ] + default: present + name: + description: + - The name of the storage profile. + - This name can be between 1 and 16 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after profile is created. + required: yes + description: + description: + - The user-defined description of the storage profile. + - 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 ] + local_luns: + description: + - List of Local LUNs used by the storage profile. + suboptions: + name: + description: + - The name of the local LUN. + required: yes + size: + description: + - Size of this LUN in GB. + - The size can range from 1 to 10240 GB. + default: '1' + auto_deploy: + description: + - Whether the local LUN should be automatically deployed or not. + choices: [ auto-deploy, no-auto-deploy ] + default: auto-deploy + expand_to_avail: + description: + - Specifies that this LUN can be expanded to use the entire available disk group. + - For each service profile, only one LUN can use this option. + - Expand To Available option is not supported for already deployed LUN. + type: bool + default: 'no' + fractional_size: + description: + - Fractional size of this LUN in MB. + default: '0' + disk_policy_name: + description: + - The disk group configuration policy to be applied to this local LUN. + state: + description: + - If C(present), will verify local LUN is present on profile. + If C(absent), will verify local LUN is absent on profile. + choices: [ absent, present ] + default: present + org_dn: + description: + - The distinguished name (dn) of the organization where the resource is assigned. + default: org-root +requirements: +- ucsmsdk +author: +- Sindhu Sudhir (@sisudhir) +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.7' +''' + +EXAMPLES = r''' +- name: Configure Storage Profile + cisco.ucs.ucs_storage_profile: + hostname: 172.16.143.150 + username: admin + password: password + name: DEE-StgProf + local_luns: + - name: Boot-LUN + size: '60' + disk_policy_name: DEE-DG + - name: Data-LUN + size: '200' + disk_policy_name: DEE-DG + +- name: Remove Storage Profile + cisco.ucs.ucs_storage_profile: + hostname: 172.16.143.150 + username: admin + password: password + name: DEE-StgProf + state: absent + +- name: Remove Local LUN from Storage Profile + cisco.ucs.ucs_storage_profile: + hostname: 172.16.143.150 + username: admin + password: password + name: DEE-StgProf + local_luns: + - name: Data-LUN + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + local_lun = dict( + name=dict(type='str', required=True), + state=dict(type='str', default='present', choices=['present', 'absent']), + size=dict(type='str', default='1'), + auto_deploy=dict(type='str', default='auto-deploy', choices=['auto-deploy', 'no-auto-deploy']), + expand_to_avail=dict(type='str', default='no', choices=['no', 'yes']), + fractional_size=dict(type='str', default='0'), + disk_policy_name=dict(type='str', default=''), + ) + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + description=dict(type='str', aliases=['descr'], default=''), + local_luns=dict(type='list', elements='dict', options=local_lun), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + ucs = UCSModule(module) + + err = False + + # UCSModule creation above verifies ucsmsdk is present and exits on failure. Additional imports are done below. + from ucsmsdk.mometa.lstorage.LstorageProfile import LstorageProfile + from ucsmsdk.mometa.lstorage.LstorageDasScsiLun import LstorageDasScsiLun + + ucs.result['changed'] = False + try: + mo_exists = False + props_match = False + # dn is <org_dn>/profile-<name> + dn = module.params['org_dn'] + '/profile-' + module.params['name'] + + 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + ucs.result['changed'] = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(descr=module.params['description']) + if mo.check_prop_match(**kwargs): + # top-level props match, check next level mo/props + if not module.params.get('local_luns'): + props_match = True + else: + # check local lun props + for lun in module.params['local_luns']: + child_dn = dn + '/das-scsi-lun-' + lun['name'] + mo_1 = ucs.login_handle.query_dn(child_dn) + if lun['state'] == 'absent': + if mo_1: + props_match = False + break + else: + if mo_1: + kwargs = dict(size=str(lun['size'])) + kwargs['auto_deploy'] = lun['auto_deploy'] + kwargs['expand_to_avail'] = lun['expand_to_avail'] + kwargs['fractional_size'] = str(lun['fractional_size']) + kwargs['local_disk_policy_name'] = lun['disk_policy_name'] + if mo_1.check_prop_match(**kwargs): + props_match = True + else: + props_match = False + break + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = LstorageProfile( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['description'], + ) + + if module.params.get('local_luns'): + for lun in module.params['local_luns']: + if lun['state'] == 'absent': + child_dn = dn + '/das-scsi-lun-' + lun['name'] + mo_1 = ucs.login_handle.query_dn(child_dn) + ucs.login_handle.remove_mo(mo_1) + else: + mo_1 = LstorageDasScsiLun( + parent_mo_or_dn=mo, + name=lun['name'], + size=str(lun['size']), + auto_deploy=lun['auto_deploy'], + expand_to_avail=lun['expand_to_avail'], + fractional_size=str(lun['fractional_size']), + local_disk_policy_name=lun['disk_policy_name'], + ) + + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + ucs.result['changed'] = True + + except Exception as e: + err = True + ucs.result['msg'] = "setup error: %s " % str(e) + + if err: + module.fail_json(**ucs.result) + module.exit_json(**ucs.result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_system_qos.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_system_qos.py new file mode 100644 index 00000000..6dcf7aac --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_system_qos.py @@ -0,0 +1,152 @@ +#!/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_system_qos +short_description: Configures system QoS settings +version_added: 2.10 +description: + - Configures system QoS settings +extends_documentation_fragment: cisco.ucs.ucs +options: + priority: + description: Priority to configure + choices: ["best-effort", "bronze", "fc", "gold","platinum", "silver"] + required: true + admin_state: + description: Admin state of QoS Policy + choices: ['disabled', 'enabled'] + default: enabled + cos: + description: CoS setting + choices: ['any', '0-6'] + required: true + weight: + description: CoS profile weight + choices: ['best-effort', 'none', '0-10'] + required: true + mtu: + description: MTU size + choices: ['fc', 'normal', '0-4294967295'] + default: normal + multicast_optimize: + description: Set multicast optimization options + choices: ['false', 'no', 'true', 'yes'] + drop: + description: Set multicast optimization options + default: 'drop' + choices: ['drop', 'no-drop'] +requirements: ['ucsmsdk'] +author: "Brett Johnson (@sdbrett)" +''' + +EXAMPLES = ''' +- name: + cisco.ucs.ucs_system_qos: + priority: platinum + admin_state: enabled + multicast_optimize: no + cos: '5' + weight: '10' + mtu: '9216' + hostname: 192.168.99.100 + username: admin + password: password +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +# TODO Add ranges for cos, weight and mtu +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + priority=dict(required=True, type='str', choices=["best-effort", "bronze", "fc", "gold", "platinum", "silver"]), + cos=dict(required=True, type='str'), + weight=dict(required=True, type='str'), + admin_state=dict(required=False, type='str', default='enabled', choices=['disabled', 'enabled']), + drop=dict(required=False, type='str', default='drop', choices=['drop', 'no-drop']), + mtu=dict(required=False, type='str', default='normal'), + multicast_optimize=dict(required=False, type='str', default='no', choices=['false', 'no', 'true', 'yes']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + ucs = UCSModule(module) + + err = False + + changed = False + try: + dn = "fabric/lan/classes/class-" + module.params['priority'] + mo = ucs.login_handle.query_dn(dn) + # check top-level mo props + if module.params['priority'] == 'best-effort': + kwargs = dict(weight=module.params['weight']) + kwargs['mtu'] = module.params['mtu'] + kwargs['multicast_optimize'] = module.params['multicast_optimize'] + if not mo.check_prop_match(**kwargs): + if not module.check_mode: + mo.weight = module.params['weight'] + mo.mtu = module.params['mtu'] + mo.multicast_optimize = module.params['multicast_optimize'] + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + changed = True + elif module.params['priority'] == 'fc': + kwargs = dict(weight=module.params['weight']) + kwargs['cos'] = module.params['cos'] + if not mo.check_prop_match(**kwargs): + if not module.check_mode: + mo.weight = module.params['weight'] + mo.cos = module.params['cos'] + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + changed = True + + else: + kwargs = dict(weight=module.params['weight']) + kwargs['priority'] = module.params['priority'] + kwargs['mtu'] = module.params['mtu'] + kwargs['cos'] = module.params['cos'] + kwargs['drop'] = module.params['drop'] + kwargs['admin_state'] = module.params['admin_state'] + kwargs['multicast_optimize'] = module.params['multicast_optimize'] + if not mo.check_prop_match(**kwargs): + if not module.check_mode: + mo.weight = module.params['weight'] + mo.mtu = module.params['mtu'] + mo.cos = module.params['cos'] + mo.drop = module.params['drop'] + mo.admin_state = module.params['admin_state'] + mo.multicast_optimize = module.params['multicast_optimize'] + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_timezone.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_timezone.py new file mode 100644 index 00000000..d7a22e78 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_timezone +short_description: Configures timezone on Cisco UCS Manager +description: +- Configures timezone on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.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 configuration is utilized by UCS Manager. + - The disabled admin_state indicates the timezone configuration 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: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.7' +''' + +EXAMPLES = r''' +- name: Configure Time Zone + cisco.ucs.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 + cisco.ucs.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_collections.cisco.ucs.plugins.module_utils.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/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_uuid_pool.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_uuid_pool.py new file mode 100644 index 00000000..d314a9ba --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_uuid_pool.py @@ -0,0 +1,196 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_uuid_pool +short_description: Configures server UUID pools on Cisco UCS Manager +description: +- Configures server UUID pools and UUID blocks on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify UUID pool is present and will create if needed. + - If C(absent), will verify UUID pool is absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the UUID pool. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the UUID pool is created. + required: yes + description: + description: + - "The user-defined description of the UUID pool." + - 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 ] + prefix: + description: + - UUID prefix used for the range of server UUIDs. + - "If no value is provided, the system derived prefix will be used (equivalent to selecting 'derived' option in UI)." + - "If the user provides a value, the user provided prefix will be used (equivalent to selecting 'other' option in UI)." + - A user provided value should be in the format XXXXXXXX-XXXX-XXXX. + order: + description: + - The Assignment Order field. + - "This can be one of the following:" + - "default - Cisco UCS Manager selects a random identity from the pool." + - "sequential - Cisco UCS Manager selects the lowest available identity from the pool." + choices: [default, sequential] + default: default + first_uuid: + description: + - The first UUID in the block of UUIDs. + - This is the From field in the UCS Manager UUID Blocks menu. + last_uuid: + description: + - The last UUID in the block of UUIDs. + - This is the To field in the UCS Manager Add UUID Blocks menu. + org_dn: + description: + - The distinguished name (dn) of the organization where the resource is assigned. + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +version_added: '2.7' +''' + +EXAMPLES = r''' +- name: Configure UUID address pool + cisco.ucs.ucs_uuid_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: UUID-Pool + order: sequential + first_uuid: 0000-000000000001 + last_uuid: 0000-000000000078 + +- name: Remove UUID address pool + cisco.ucs.ucs_uuid_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: UUID-Pool + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + description=dict(type='str', aliases=['descr'], default=''), + order=dict(type='str', default='default', choices=['default', 'sequential']), + prefix=dict(type='str', default=''), + first_uuid=dict(type='str'), + last_uuid=dict(type='str'), + state=dict(default='present', choices=['present', 'absent'], type='str'), + ) + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + ) + # UCSModule verifies ucsmsdk is present and exits on failure. Imports are below ucs object creation. + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.uuidpool.UuidpoolPool import UuidpoolPool + from ucsmsdk.mometa.uuidpool.UuidpoolBlock import UuidpoolBlock + + ucs.result['changed'] = False + try: + mo_exists = False + props_match = False + # dn is <org_dn>/uuid-pool-<name> + dn = module.params['org_dn'] + '/uuid-pool-' + module.params['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() + ucs.result['changed'] = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(assignment_order=module.params['order']) + kwargs['descr'] = module.params['description'] + if module.params['prefix']: + kwargs['prefix'] = module.params['prefix'] + if mo.check_prop_match(**kwargs): + # top-level props match, check next level mo/props + if module.params['last_uuid'] and module.params['first_uuid']: + # uuid address block specified, check properties + block_dn = dn + '/block-from-' + module.params['first_uuid'].upper() + '-to-' + module.params['last_uuid'].upper() + mo_1 = ucs.login_handle.query_dn(block_dn) + if mo_1: + props_match = True + else: + # no UUID address block specified, but top-level props matched + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + if not module.params['prefix']: + module.params['prefix'] = 'derived' + mo = UuidpoolPool( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['description'], + assignment_order=module.params['order'], + prefix=module.params['prefix'] + ) + + if module.params['last_uuid'] and module.params['first_uuid']: + mo_1 = UuidpoolBlock( + parent_mo_or_dn=mo, + to=module.params['last_uuid'], + r_from=module.params['first_uuid'], + ) + + ucs.login_handle.add_mo(mo, True) + ucs.login_handle.commit() + ucs.result['changed'] = True + + except Exception as e: + err = True + ucs.result['msg'] = "setup error: %s " % str(e) + + if err: + module.fail_json(**ucs.result) + module.exit_json(**ucs.result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vhba_template.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vhba_template.py new file mode 100644 index 00000000..597e8c91 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vhba_template.py @@ -0,0 +1,274 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_vhba_template +short_description: Configures vHBA templates on Cisco UCS Manager +description: +- Configures vHBA templates on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify vHBA templates are present and will create if needed. + - If C(absent), will verify vHBA templates are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the virtual HBA template. + - This name can be between 1 and 16 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the template is created. + required: yes + description: + description: + - A user-defined description of the template. + - 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 ] + fabric: + description: + - The Fabric ID field. + - The name of the fabric interconnect that vHBAs created with this template are associated with. + choices: [A, B] + default: A + redundancy_type: + description: + - The Redundancy Type used for template pairing from the Primary or Secondary redundancy template. + - "primary — Creates configurations that can be shared with the Secondary template." + - Any other shared changes on the Primary template are automatically synchronized to the Secondary template. + - "secondary — All shared configurations are inherited from the Primary template." + - "none - Legacy vHBA template behavior. Select this option if you do not want to use redundancy." + choices: [none, primary, secondary] + default: none + vsan: + description: + - The VSAN to associate with vHBAs created from this template. + default: default + template_type: + description: + - The Template Type field. + - "This can be one of the following:" + - "initial-template — vHBAs created from this template are not updated if the template changes." + - "updating-template - vHBAs created from this template are updated if the template changes." + choices: [initial-template, updating-template] + default: initial-template + max_data: + description: + - The Max Data Field Size field. + - The maximum size of the Fibre Channel frame payload bytes that the vHBA supports. + - Enter an string between '256' and '2112'. + default: '2048' + wwpn_pool: + description: + - The WWPN pool that a vHBA created from this template uses to derive its WWPN address. + default: default + qos_policy: + description: + - The QoS policy that is associated with vHBAs created from this template. + pin_group: + description: + - The SAN pin group that is associated with vHBAs created from this template. + stats_policy: + description: + - The statistics collection policy that is associated with vHBAs created from this template. + default: default + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure vHBA template + cisco.ucs.ucs_vhba_template: + hostname: 172.16.143.150 + username: admin + password: password + name: vHBA-A + fabric: A + vsan: VSAN-A + wwpn_pool: WWPN-Pool-A + +- name: Remote vHBA template + cisco.ucs.ucs_vhba_template: + hostname: 172.16.143.150 + username: admin + password: password + name: vHBA-A + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str'), + descr=dict(type='str'), + fabric=dict(type='str', default='A', choices=['A', 'B']), + redundancy_type=dict(type='str', default='none', choices=['none', 'primary', 'secondary']), + vsan=dict(type='str', default='default'), + template_type=dict(type='str', default='initial-template', choices=['initial-template', 'updating-template']), + max_data=dict(type='str', default='2048'), + wwpn_pool=dict(type='str', default='default'), + qos_policy=dict(type='str'), + pin_group=dict(type='str'), + stats_policy=dict(type='str', default='default'), + state=dict(type='str', default='present', choices=['present', 'absent']), + vhba_template_list=dict(type='list'), + ) + + # Note that use of vhba_template_list is an experimental feature which allows multiple resource updates with a single UCSM connection. + # Support for vhba_template_list may change or be removed once persistent UCS connections are supported. + # Either vhba_template_list or name is required (user can specify either a list of single resource). + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_one_of=[ + ['vhba_template_list', 'name'] + ], + mutually_exclusive=[ + ['vhba_template_list', 'name'] + ], + ) + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.vnic.VnicSanConnTempl import VnicSanConnTempl + from ucsmsdk.mometa.vnic.VnicFcIf import VnicFcIf + + changed = False + try: + # Only documented use is a single resource, but to also support experimental + # feature allowing multiple updates all params are converted to a vhba_template_list below. + + if module.params['vhba_template_list']: + # directly use the list (single resource and list are mutually exclusive + vhba_template_list = module.params['vhba_template_list'] + else: + # single resource specified, create list from the current params + vhba_template_list = [module.params] + for vhba_template in vhba_template_list: + mo_exists = False + props_match = False + # set default params. Done here to set values for lists which can't be done in the argument_spec + if not vhba_template.get('descr'): + vhba_template['descr'] = '' + if not vhba_template.get('fabric'): + vhba_template['fabric'] = 'A' + if not vhba_template.get('redundancy_type'): + vhba_template['redundancy_type'] = 'none' + if not vhba_template.get('vsan'): + vhba_template['vsan'] = 'default' + if not vhba_template.get('template_type'): + vhba_template['template_type'] = 'initial-template' + if not vhba_template.get('max_data'): + vhba_template['max_data'] = '2048' + if not vhba_template.get('wwpn_pool'): + vhba_template['wwpn_pool'] = 'default' + if not vhba_template.get('qos_policy'): + vhba_template['qos_policy'] = '' + if not vhba_template.get('pin_group'): + vhba_template['pin_group'] = '' + if not vhba_template.get('stats_policy'): + vhba_template['stats_policy'] = 'default' + # dn is <org_dn>/san-conn-templ-<name> + dn = module.params['org_dn'] + '/san-conn-templ-' + vhba_template['name'] + + mo = ucs.login_handle.query_dn(dn) + if mo: + mo_exists = True + # check top-level mo props + kwargs = dict(descr=vhba_template['descr']) + kwargs['switch_id'] = vhba_template['fabric'] + kwargs['redundancy_pair_type'] = vhba_template['redundancy_type'] + kwargs['templ_type'] = vhba_template['template_type'] + kwargs['max_data_field_size'] = vhba_template['max_data'] + kwargs['ident_pool_name'] = vhba_template['wwpn_pool'] + kwargs['qos_policy_name'] = vhba_template['qos_policy'] + kwargs['pin_to_group_name'] = vhba_template['pin_group'] + kwargs['stats_policy_name'] = vhba_template['stats_policy'] + if (mo.check_prop_match(**kwargs)): + # top-level props match, check next level mo/props + child_dn = dn + '/if-default' + mo_1 = ucs.login_handle.query_dn(child_dn) + if mo_1: + kwargs = dict(name=vhba_template['vsan']) + if (mo_1.check_prop_match(**kwargs)): + props_match = 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = VnicSanConnTempl( + parent_mo_or_dn=module.params['org_dn'], + name=vhba_template['name'], + descr=vhba_template['descr'], + switch_id=vhba_template['fabric'], + redundancy_pair_type=vhba_template['redundancy_type'], + templ_type=vhba_template['template_type'], + max_data_field_size=vhba_template['max_data'], + ident_pool_name=vhba_template['wwpn_pool'], + qos_policy_name=vhba_template['qos_policy'], + pin_to_group_name=vhba_template['pin_group'], + stats_policy_name=vhba_template['stats_policy'], + ) + + mo_1 = VnicFcIf( + parent_mo_or_dn=mo, + name=vhba_template['vsan'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlan_find.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlan_find.py new file mode 100644 index 00000000..595fb596 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlan_find.py @@ -0,0 +1,123 @@ +#!/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_vlan_find +short_description: Find VLANs on Cisco UCS Manager +description: +- Find VLANs on Cisco UCS Manager based on different criteria. +extends_documentation_fragment: cisco.ucs.ucs +options: + pattern: + description: + - Regex pattern to find within the name property of the fabricVlan class. + - This is required if C(vlanid) parameter is not supplied. + type: str + fabric: + description: + - "The fabric configuration of the VLAN. This can be one of the following:" + - "common - The VLAN applies to both fabrics and uses the same configuration parameters in both cases." + - "A — The VLAN only applies to fabric A." + - "B — The VLAN only applies to fabric B." + choices: [common, A, B] + default: common + type: str + vlanid: + description: + - The unique string identifier assigned to the VLAN. + - A VLAN ID can be between '1' and '3967', or between '4048' and '4093'. + - This is required if C(pattern) parameter is not supplied. + type: str +requirements: +- ucsmsdk +author: +- David Martinez (@dx0xm) +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.9' +''' + +EXAMPLES = r''' +- name: Get all vlans in fabric A + cisco.ucs.ucs_vlan_find: + hostname: 172.16.143.150 + username: admin + password: password + fabric: 'A' + pattern: '.' +- name: Confirm if vlan 15 is present + cisco.ucs.ucs_vlan_find: + hostname: 172.16.143.150 + username: admin + password: password + vlanid: '15' +''' + +RETURN = r''' +vlan_list: + description: basic details of vlans found + returned: on success + type: list + sample: [ + { + "id": "0", + "name": "vlcloud1" + } + ] +''' + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + fabric=dict(type='str', default='common', choices=['common', 'A', 'B']), + pattern=dict(type='str'), + vlanid=dict(type='str') + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_one_of=[['pattern', 'vlanid']] + ) + + ucs = UCSModule(module) + + filtls = ['(cloud,"ethlan")'] + if module.params['fabric'] != 'common': + filtls.append('(switch_id,"' + module.params['fabric'] + '")') + if module.params['vlanid']: + filtls.append('(id,"' + module.params['vlanid'] + '")') + else: + filtls.append('(name,"' + module.params['pattern'] + '")') + + object_dict = ucs.login_handle.query_classid("fabricVlan", filter_str=' and '.join(filtls)) + + if object_dict is None: + module.fail_json(msg="Failed to query vlan objects") + + vlnlist = [] + for ob in object_dict: + vlnlist.append(dict(name=ob.name, id=ob.id)) + + module.exit_json(changed=False, + vlan_list=vlnlist) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlan_to_group.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlan_to_group.py new file mode 100644 index 00000000..c7b6e81c --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlan_to_group.py @@ -0,0 +1,158 @@ +#!/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_vlan_to_group +short_description: Add VLANs to a VLAN Group. Requires VLAN and VLAN Group to already be created on UCS prior to running module. +description: +- Add VLANs to VLAN Groups on Cisco UCS Manager. +extends_documentation_fragment: ucs +options: + state: + description: + - If C(present), will verify VLANs are present and will create if needed. + - If C(absent), will verify VLANs are absent and will delete if needed. + choices: [present, absent] + default: present + vlanname: + description: + - The name assigned to the VLAN. + - The VLAN name is case sensitive. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + required: yes + vlangroup: + description: + - The name assigned to the VLAN Group. + - The VLAN Group name is case sensitive. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + required: yes +requirements: +- ucsmsdk +author: +- Derrick Johnson @derricktj +version_added: '2.10' +''' + +EXAMPLES = r''' +- name: Configure VLAN + cisco.ucs.ucs_vlan_to_group: + hostname: 1.1.1.1 + username: admin + password: password + vlangroup: VLANGROUP + vlanname: VLANNAME + state: present +- name: Remove VLAN + cisco.ucs.ucs_vlan_to_group: + hostname: 1.1.1.1 + username: admin + password: password + vlangroup: VLANGROUP + vlanname: VLANNAME + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + vlangroup=dict(type='str', required=True), + vlanname=dict(type='str', required=True), + state=dict(default='present', choices=['present', 'absent'], type='str'), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['vlangroup', 'vlanname']], + ], + ) + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.fabric.FabricNetGroup import FabricNetGroup + from ucsmsdk.mometa.fabric.FabricPooledVlan import FabricPooledVlan + + changed = False + try: + dnpooled1_exists = False + + # dn = fabric/lan/net-group-VLANGROUP + # Check for VLAN Group + dngroup = 'fabric/lan/net-group-' + module.params['vlangroup'] + dngroup1 = ucs.login_handle.query_dn(dngroup) + + # dn = fabric/lan/net-VLANNAME + # Check for VLAN + dnvlan = 'fabric/lan/net-' + module.params['vlanname'] + dnvlan1 = ucs.login_handle.query_dn(dnvlan) + + # dn = fabric/lan/net-group-VLANGROUP/net-VLANNAME + # Check for VLAN within VLAN Group + dnpooled = 'fabric/lan/net-group-' + module.params['vlangroup'] + '/net-' + module.params['vlanname'] + dnpooled1 = ucs.login_handle.query_dn(dnpooled) + + # Configuration MOs. Couldn't really get this to work off the DNs, so I built additional objects. + mo = FabricNetGroup(parent_mo_or_dn="fabric/lan", name=module.params['vlangroup']) + mo_1 = FabricPooledVlan(parent_mo_or_dn=mo, name=module.params['vlanname']) + + if not dngroup1: + # Error out if the VLAN Group is missing + err = True + ucs.result['msg'] = module.params['vlangroup'] + " VLAN Group not configured in UCS" + + if not dnvlan1: + # Error out if VLAN is missing + err = True + ucs.result['msg'] = module.params['vlanname'] + " VLAN not configured in UCS. Use ucs_vlans module to create the VLAN first" + + if dnpooled1: + dnpooled1_exists = True + + if module.params['state'] == 'absent': + if dnpooled1_exists: + if not module.check_mode: + ucs.login_handle.remove_mo(mo_1) + ucs.login_handle.commit() + changed = True + + if module.params['state'] == 'present': + if not dnpooled1_exists: + if not module.check_mode: + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlans.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlans.py new file mode 100644 index 00000000..a0376f9b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vlans.py @@ -0,0 +1,192 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_vlans +short_description: Configures VLANs on Cisco UCS Manager +description: +- Configures VLANs on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify VLANs are present and will create if needed. + - If C(absent), will verify VLANs are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name assigned to the VLAN. + - The VLAN name is case sensitive. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the VLAN is created. + required: yes + multicast_policy: + description: + - The multicast policy associated with this VLAN. + - This option is only valid if the Sharing Type field is set to None or Primary. + default: '' + fabric: + description: + - "The fabric configuration of the VLAN. This can be one of the following:" + - "common - The VLAN applies to both fabrics and uses the same configuration parameters in both cases." + - "A — The VLAN only applies to fabric A." + - "B — The VLAN only applies to fabric B." + - For upstream disjoint L2 networks, Cisco recommends that you choose common to create VLANs that apply to both fabrics. + choices: [common, A, B] + default: common + id: + description: + - The unique string identifier assigned to the VLAN. + - A VLAN ID can be between '1' and '3967', or between '4048' and '4093'. + - You cannot create VLANs with IDs from 4030 to 4047. This range of VLAN IDs is reserved. + - The VLAN IDs you specify must also be supported on the switch that you are using. + - VLANs in the LAN cloud and FCoE VLANs in the SAN cloud must have different IDs. + - Optional if state is absent. + required: yes + sharing: + description: + - The Sharing Type field. + - "Whether this VLAN is subdivided into private or secondary VLANs. This can be one of the following:" + - "none - This VLAN does not have any secondary or private VLANs. This is a regular VLAN." + - "primary - This VLAN can have one or more secondary VLANs, as shown in the Secondary VLANs area. This VLAN is a primary VLAN in the private VLAN domain." + - "isolated - This is a private VLAN associated with a primary VLAN. This VLAN is an Isolated VLAN." + - "community - This VLAN can communicate with other ports on the same community VLAN as well as the promiscuous port. This VLAN is a Community VLAN." + choices: [none, primary, isolated, community] + default: none + native: + description: + - Designates the VLAN as a native VLAN. + choices: ['yes', 'no'] + default: 'no' +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure VLAN + cisco.ucs.ucs_vlans: + hostname: 172.16.143.150 + username: admin + password: password + name: vlan2 + id: '2' + native: 'yes' + +- name: Remove VLAN + cisco.ucs.ucs_vlans: + hostname: 172.16.143.150 + username: admin + password: password + name: vlan2 + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + name=dict(type='str', required=True), + multicast_policy=dict(type='str', default=''), + fabric=dict(type='str', default='common', choices=['common', 'A', 'B']), + id=dict(type='str'), + sharing=dict(type='str', default='none', choices=['none', 'primary', 'isolated', 'community']), + native=dict(type='str', default='no', choices=['yes', 'no']), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['id']], + ], + ) + ucs = UCSModule(module) + + err = False + + # UCSModule creation above verifies ucsmsdk is present and exits on failure, so additional imports are done below. + from ucsmsdk.mometa.fabric.FabricVlan import FabricVlan + + changed = False + try: + mo_exists = False + props_match = False + # dn is fabric/lan/net-<name> for common vlans or fabric/lan/[A or B]/net-<name> for A or B + dn_base = 'fabric/lan' + if module.params['fabric'] != 'common': + dn_base += '/' + module.params['fabric'] + dn = dn_base + '/net-' + module.params['name'] + + 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(id=module.params['id']) + kwargs['default_net'] = module.params['native'] + kwargs['sharing'] = module.params['sharing'] + kwargs['mcast_policy_name'] = module.params['multicast_policy'] + if mo.check_prop_match(**kwargs): + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = FabricVlan( + parent_mo_or_dn=dn_base, + name=module.params['name'], + id=module.params['id'], + default_net=module.params['native'], + sharing=module.params['sharing'], + mcast_policy_name=module.params['multicast_policy'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vnic_template.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vnic_template.py new file mode 100644 index 00000000..544af9a0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vnic_template.py @@ -0,0 +1,377 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_vnic_template +short_description: Configures vNIC templates on Cisco UCS Manager +description: +- Configures vNIC templates on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify vNIC templates are present and will create if needed. + - If C(absent), will verify vNIC templates are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the vNIC template. + - This name can be between 1 and 16 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the template is created. + required: yes + description: + description: + - A user-defined description of the vNIC template. + - 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 ] + fabric: + description: + - The Fabric ID field specifying the fabric interconnect associated with vNICs created from this template. + - If you want fabric failover enabled on vNICs created from this template, use of of the following:" + - "A-B to use Fabric A by default with failover enabled." + - "B-A to use Fabric B by default with failover enabled." + - "Do not enable vNIC fabric failover under the following circumstances:" + - "- If the Cisco UCS domain is running in Ethernet switch mode. vNIC fabric failover is not supported in that mode." + - "- If you plan to associate one or more vNICs created from this template to a server with an adapter that does not support fabric failover." + choices: [A, B, A-B, B-A] + default: A + redundancy_type: + description: + - The Redundancy Type used for vNIC redundancy pairs during fabric failover. + - "This can be one of the following:" + - "primary — Creates configurations that can be shared with the Secondary template." + - "secondary — All shared configurations are inherited from the Primary template." + - "none - Legacy vNIC template behavior. Select this option if you do not want to use redundancy." + choices: [none, primary, secondary] + default: none + peer_redundancy_template: + description: + - The Peer Redundancy Template. + - The name of the vNIC template sharing a configuration with this template. + - If the redundancy_type is primary, the name of the secondary template should be provided. + - If the redundancy_type is secondary, the name of the primary template should be provided. + - Secondary templates can only configure non-shared properties (name, description, and mac_pool). + aliases: [ peer_redundancy_templ ] + target: + description: + - The possible target for vNICs created from this template. + - The target determines whether or not Cisco UCS Manager automatically creates a VM-FEX port profile with the appropriate settings for the vNIC template. + - "This can be one of the following:" + - "adapter — The vNICs apply to all adapters. No VM-FEX port profile is created if you choose this option." + - "vm - The vNICs apply to all virtual machines. A VM-FEX port profile is created if you choose this option." + default: adapter + template_type: + description: + - The Template Type field. + - "This can be one of the following:" + - "initial-template — vNICs created from this template are not updated if the template changes." + - "updating-template - vNICs created from this template are updated if the template changes." + choices: [initial-template, updating-template] + default: initial-template + vlans_list: + description: + - List of VLANs used by the vNIC template. + - "Each list element has the following suboptions:" + - "= name" + - " The name of the VLAN (required)." + - "- native" + - " Designates the VLAN as a native VLAN. Only one VLAN in the list can be a native VLAN." + - " [choices: 'no', 'yes']" + - " [Default: 'no']" + - "- state" + - " If present, will verify VLAN is present on template." + - " If absent, will verify VLAN is absent on template." + - " choices: [present, absent]" + - " default: present" + cdn_source: + description: + - CDN Source field. + - "This can be one of the following options:" + - "vnic-name - Uses the vNIC template name of the vNIC instance as the CDN name. This is the default option." + - "user-defined - Uses a user-defined CDN name for the vNIC template. If this option is chosen, cdn_name must also be provided." + choices: [vnic-name, user-defined] + default: vnic-name + cdn_name: + description: + - CDN Name used when cdn_source is set to user-defined. + mtu: + description: + - The MTU field. + - The maximum transmission unit, or packet size, that vNICs created from this vNIC template should use. + - Enter a string between '1500' and '9000'. + - If the vNIC template has an associated QoS policy, the MTU specified here must be equal to or less than the MTU specified in the QoS system class. + default: '1500' + mac_pool: + description: + - The MAC address pool that vNICs created from this vNIC template should use. + qos_policy: + description: + - The quality of service (QoS) policy that vNICs created from this vNIC template should use. + network_control_policy: + description: + - The network control policy that vNICs created from this vNIC template should use. + pin_group: + description: + - The LAN pin group that vNICs created from this vNIC template should use. + stats_policy: + description: + - The statistics collection policy that vNICs created from this vNIC template should use. + default: default + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure vNIC template + cisco.ucs.ucs_vnic_template: + hostname: 172.16.143.150 + username: admin + password: password + name: vNIC-A + fabric: A + vlans_list: + - name: default + native: 'yes' + +- name: Configure vNIC template with failover + cisco.ucs.ucs_vnic_template: + hostname: 172.16.143.150 + username: admin + password: password + name: vNIC-A-B + fabric: A-B + vlans_list: + - name: default + native: 'yes' + state: present + +- name: Remove vNIC template + cisco.ucs.ucs_vnic_template: + hostname: 172.16.143.150 + username: admin + password: password + name: vNIC-A + state: absent + +- name: Remove another vNIC template + cisco.ucs.ucs_vnic_template: + hostname: 172.16.143.150 + username: admin + password: password + name: vNIC-A-B + state: absent + +- name: Remove VLAN from template + cisco.ucs.ucs_vnic_template: + hostname: 172.16.143.150 + username: admin + password: password + name: vNIC-A-B + fabric: A-B + vlans_list: + - name: default + native: 'yes' + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str', required=True), + description=dict(type='str', aliases=['descr'], default=''), + fabric=dict(type='str', default='A', choices=['A', 'B', 'A-B', 'B-A']), + redundancy_type=dict(type='str', default='none', choices=['none', 'primary', 'secondary']), + peer_redundancy_template=dict(type='str', aliases=['peer_redundancy_templ'], default=''), + target=dict(type='str', default='adapter', choices=['adapter', 'vm']), + template_type=dict(type='str', default='initial-template', choices=['initial-template', 'updating-template']), + vlans_list=dict(type='list'), + cdn_source=dict(type='str', default='vnic-name', choices=['vnic-name', 'user-defined']), + cdn_name=dict(type='str', default=''), + mtu=dict(type='str', default='1500'), + mac_pool=dict(type='str', default=''), + qos_policy=dict(type='str', default=''), + network_control_policy=dict(type='str', default=''), + pin_group=dict(type='str', default=''), + stats_policy=dict(type='str', default='default'), + state=dict(type='str', default='present', choices=['present', 'absent']), + ) + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_if=[ + ['cdn_source', 'user-defined', ['cdn_name']], + ], + ) + ucs = UCSModule(module) + + err = False + + # UCSModule creation above verifies ucsmsdk is present and exits on failure. Additional imports are done below. + from ucsmsdk.mometa.vnic.VnicLanConnTempl import VnicLanConnTempl + from ucsmsdk.mometa.vnic.VnicEtherIf import VnicEtherIf + + changed = False + try: + mo_exists = False + props_match = False + # dn is <org_dn>/lan-conn-templ-<name> + dn = module.params['org_dn'] + '/lan-conn-templ-' + module.params['name'] + + 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + # set default params for lists which can't be done in the argument_spec + if module.params.get('vlans_list'): + for vlan in module.params['vlans_list']: + if not vlan.get('native'): + vlan['native'] = 'no' + if not vlan.get('state'): + vlan['state'] = 'present' + # for target 'adapter', change to internal UCS Manager spelling 'adaptor' + if module.params['target'] == 'adapter': + module.params['target'] = 'adaptor' + if mo_exists: + # check top-level mo props + kwargs = dict(descr=module.params['description']) + kwargs['switch_id'] = module.params['fabric'] + kwargs['redundancy_pair_type'] = module.params['redundancy_type'] + kwargs['peer_redundancy_templ_name'] = module.params['peer_redundancy_template'] + kwargs['ident_pool_name'] = module.params['mac_pool'] + # do not check shared props if this is a secondary template + if module.params['redundancy_type'] != 'secondary': + kwargs['target'] = module.params['target'] + kwargs['templ_type'] = module.params['template_type'] + kwargs['cdn_source'] = module.params['cdn_source'] + kwargs['admin_cdn_name'] = module.params['cdn_name'] + kwargs['mtu'] = module.params['mtu'] + kwargs['qos_policy_name'] = module.params['qos_policy'] + kwargs['nw_ctrl_policy_name'] = module.params['network_control_policy'] + kwargs['pin_to_group_name'] = module.params['pin_group'] + kwargs['stats_policy_name'] = module.params['stats_policy'] + if mo.check_prop_match(**kwargs): + # top-level props match, check next level mo/props + if not module.params.get('vlans_list'): + props_match = True + else: + # check vlan props + for vlan in module.params['vlans_list']: + child_dn = dn + '/if-' + str(vlan['name']) + mo_1 = ucs.login_handle.query_dn(child_dn) + if vlan['state'] == 'absent': + if mo_1: + props_match = False + break + else: + if mo_1: + kwargs = dict(default_net=vlan['native']) + if mo_1.check_prop_match(**kwargs): + props_match = True + else: + props_match = False + break + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + # secondary template only sets non shared props + if module.params['redundancy_type'] == 'secondary': + mo = VnicLanConnTempl( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['description'], + switch_id=module.params['fabric'], + redundancy_pair_type=module.params['redundancy_type'], + peer_redundancy_templ_name=module.params['peer_redundancy_template'], + ident_pool_name=module.params['mac_pool'], + ) + else: + mo = VnicLanConnTempl( + parent_mo_or_dn=module.params['org_dn'], + name=module.params['name'], + descr=module.params['description'], + switch_id=module.params['fabric'], + redundancy_pair_type=module.params['redundancy_type'], + peer_redundancy_templ_name=module.params['peer_redundancy_template'], + target=module.params['target'], + templ_type=module.params['template_type'], + cdn_source=module.params['cdn_source'], + admin_cdn_name=module.params['cdn_name'], + mtu=module.params['mtu'], + ident_pool_name=module.params['mac_pool'], + qos_policy_name=module.params['qos_policy'], + nw_ctrl_policy_name=module.params['network_control_policy'], + pin_to_group_name=module.params['pin_group'], + stats_policy_name=module.params['stats_policy'], + ) + + if module.params.get('vlans_list'): + for vlan in module.params['vlans_list']: + if vlan['state'] == 'absent': + child_dn = dn + '/if-' + str(vlan['name']) + mo_1 = ucs.login_handle.query_dn(child_dn) + ucs.login_handle.remove_mo(mo_1) + else: + mo_1 = VnicEtherIf( + parent_mo_or_dn=mo, + name=str(vlan['name']), + default_net=vlan['native'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vsans.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vsans.py new file mode 100644 index 00000000..cf4c656e --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_vsans.py @@ -0,0 +1,204 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_vsans +short_description: Configures VSANs on Cisco UCS Manager +description: +- Configures VSANs on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify VSANs are present and will create if needed. + - If C(absent), will verify VSANs are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name assigned to the VSAN. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the VSAN is created. + required: yes + vsan_id: + description: + - The unique identifier assigned to the VSAN. + - The ID can be a string between '1' and '4078', or between '4080' and '4093'. '4079' is a reserved VSAN ID. + - In addition, if you plan to use FC end-host mode, the range between '3840' to '4079' is also a reserved VSAN ID range. + - Optional if state is absent. + required: yes + vlan_id: + description: + - The unique string identifier assigned to the VLAN used for Fibre Channel connections. + - Note that Cisco UCS Manager uses VLAN '4048'. See the UCS Manager configuration guide if you want to assign '4048' to a VLAN. + - Optional if state is absent. + required: yes + fc_zoning: + description: + - Fibre Channel zoning configuration for the Cisco UCS domain. + - "Fibre Channel zoning can be set to one of the following values:" + - "disabled — The upstream switch handles Fibre Channel zoning, or Fibre Channel zoning is not implemented for the Cisco UCS domain." + - "enabled — Cisco UCS Manager configures and controls Fibre Channel zoning for the Cisco UCS domain." + - If you enable Fibre Channel zoning, do not configure the upstream switch with any VSANs that are being used for Fibre Channel zoning. + choices: [disabled, enabled] + default: disabled + fabric: + description: + - "The fabric configuration of the VSAN. This can be one of the following:" + - "common - The VSAN maps to the same VSAN ID in all available fabrics." + - "A - The VSAN maps to the a VSAN ID that exists only in fabric A." + - "B - The VSAN maps to the a VSAN ID that exists only in fabric B." + choices: [common, A, B] + default: common +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure VSAN + cisco.ucs.ucs_vsans: + hostname: 172.16.143.150 + username: admin + password: password + name: vsan110 + fabric: common + vsan_id: '110' + vlan_id: '110' + +- name: Remove VSAN + cisco.ucs.ucs_vsans: + hostname: 172.16.143.150 + username: admin + password: password + name: vsan110 + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + name=dict(type='str'), + vsan_id=dict(type='str'), + vlan_id=dict(type='str'), + fc_zoning=dict(type='str', default='disabled', choices=['disabled', 'enabled']), + fabric=dict(type='str', default='common', choices=['common', 'A', 'B']), + state=dict(type='str', default='present', choices=['present', 'absent']), + vsan_list=dict(type='list'), + ) + + # Note that use of vsan_list is an experimental feature which allows multiple resource updates with a single UCSM connection. + # Support for vsan_list may change or be removed once persistent UCS connections are supported. + # Either vsan_list or name/vsan_id/vlan_id is required (user can specify either a list or single resource). + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_one_of=[ + ['vsan_list', 'name'] + ], + mutually_exclusive=[ + ['vsan_list', 'name'] + ], + ) + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.fabric.FabricVsan import FabricVsan + + changed = False + try: + # Only documented use is a single resource, but to also support experimental + # feature allowing multiple updates all params are converted to a vsan_list below. + + if module.params['vsan_list']: + # directly use the list (single resource and list are mutually exclusive + vsan_list = module.params['vsan_list'] + else: + # single resource specified, create list from the current params + vsan_list = [module.params] + for vsan in vsan_list: + mo_exists = False + props_match = False + # set default params. Done here to set values for lists which can't be done in the argument_spec + if not vsan.get('fc_zoning'): + vsan['fc_zoning'] = 'disabled' + if not vsan.get('fabric'): + vsan['fabric'] = 'common' + # dn is fabric/san/net-<name> for common vsans or fabric/san/[A or B]/net-<name> for A or B + dn_base = 'fabric/san' + if vsan['fabric'] != 'common': + dn_base += '/' + vsan['fabric'] + dn = dn_base + '/net-' + vsan['name'] + + 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: + ucs.login_handle.remove_mo(mo) + ucs.login_handle.commit() + changed = True + else: + if mo_exists: + # check top-level mo props + kwargs = dict(id=vsan['vsan_id']) + kwargs['fcoe_vlan'] = vsan['vlan_id'] + kwargs['zoning_state'] = vsan['fc_zoning'] + if (mo.check_prop_match(**kwargs)): + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = FabricVsan( + parent_mo_or_dn=dn_base, + name=vsan['name'], + id=vsan['vsan_id'], + fcoe_vlan=vsan['vlan_id'], + zoning_state=vsan['fc_zoning'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_wwn_pool.py b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_wwn_pool.py new file mode 100644 index 00000000..9751ebcb --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ucs/plugins/modules/ucs_wwn_pool.py @@ -0,0 +1,239 @@ +#!/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': 'certified'} + +DOCUMENTATION = r''' +--- +module: ucs_wwn_pool +short_description: Configures WWNN or WWPN pools on Cisco UCS Manager +description: +- Configures WWNNs or WWPN pools on Cisco UCS Manager. +extends_documentation_fragment: cisco.ucs.ucs +options: + state: + description: + - If C(present), will verify WWNNs/WWPNs are present and will create if needed. + - If C(absent), will verify WWNNs/WWPNs are absent and will delete if needed. + choices: [present, absent] + default: present + name: + description: + - The name of the World Wide Node Name (WWNN) or World Wide Port Name (WWPN) pool. + - This name can be between 1 and 32 alphanumeric characters. + - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." + - You cannot change this name after the WWNN or WWPN pool is created. + required: yes + purpose: + description: + - Specify whether this is a node (WWNN) or port (WWPN) pool. + - Optional if state is absent. + choices: [node, port] + required: yes + description: + description: + - A description of the WWNN or WWPN pool. + - 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 ] + order: + description: + - The Assignment Order field. + - "This can be one of the following:" + - "default - Cisco UCS Manager selects a random identity from the pool." + - "sequential - Cisco UCS Manager selects the lowest available identity from the pool." + choices: [default, sequential] + default: default + first_addr: + description: + - The first initiator in the World Wide Name (WWN) block. + - This is the From field in the UCS Manager Add WWN Blocks menu. + last_addr: + description: + - The last initiator in the World Wide Name (WWN) block. + - This is the To field in the UCS Manager Add WWN Blocks menu. + - For WWxN pools, the pool size must be a multiple of ports-per-node + 1. + - For example, if there are 7 ports per node, the pool size must be a multiple of 8. + - If there are 63 ports per node, the pool size must be a multiple of 64. + org_dn: + description: + - Org dn (distinguished name) + default: org-root +requirements: +- ucsmsdk +author: +- David Soper (@dsoper2) +- John McDonough (@movinalot) +- CiscoUcs (@CiscoUcs) +version_added: '2.5' +''' + +EXAMPLES = r''' +- name: Configure WWNN/WWPN pools + cisco.ucs.ucs_wwn_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: WWNN-Pool + purpose: node + first_addr: 20:00:00:25:B5:48:00:00 + last_addr: 20:00:00:25:B5:48:00:0F +- cisco.ucs.ucs_wwn_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: WWPN-Pool-A + purpose: port + order: sequential + first_addr: 20:00:00:25:B5:48:0A:00 + last_addr: 20:00:00:25:B5:48:0A:0F + +- name: Remove WWNN/WWPN pools + cisco.ucs.ucs_wwn_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: WWNN-Pool + state: absent +- cisco.ucs.ucs_wwn_pool: + hostname: 172.16.143.150 + username: admin + password: password + name: WWPN-Pool-A + state: absent +''' + +RETURN = r''' +# +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec + + +def main(): + argument_spec = ucs_argument_spec + argument_spec.update( + org_dn=dict(type='str', default='org-root'), + name=dict(type='str'), + purpose=dict(type='str', choices=['node', 'port']), + descr=dict(type='str'), + order=dict(type='str', default='default', choices=['default', 'sequential']), + first_addr=dict(type='str'), + last_addr=dict(type='str'), + state=dict(type='str', default='present', choices=['present', 'absent']), + wwn_list=dict(type='list'), + ) + + # Note that use of wwn_list is an experimental feature which allows multiple resource updates with a single UCSM connection. + # Support for wwn_list may change or be removed once persistent UCS connections are supported. + # Either wwn_list or name is required (user can specify either a list or single resource). + + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + required_one_of=[ + ['wwn_list', 'name'] + ], + mutually_exclusive=[ + ['wwn_list', 'name'] + ], + ) + ucs = UCSModule(module) + + err = False + + from ucsmsdk.mometa.fcpool.FcpoolInitiators import FcpoolInitiators + from ucsmsdk.mometa.fcpool.FcpoolBlock import FcpoolBlock + + changed = False + try: + # Only documented use is a single resource, but to also support experimental + # feature allowing multiple updates all params are converted to a wwn_list below. + + if module.params['wwn_list']: + # directly use the list (single resource and list are mutually exclusive + wwn_list = module.params['wwn_list'] + else: + # single resource specified, create list from the current params + wwn_list = [module.params] + for wwn in wwn_list: + mo_exists = False + props_match = False + # set default params. Done here to set values for lists which can't be done in the argument_spec + if not wwn.get('descr'): + wwn['descr'] = '' + if not wwn.get('order'): + wwn['order'] = 'default' + # dn is <org_dn>/wwn-pool-<name> for WWNN or WWPN + dn = module.params['org_dn'] + '/wwn-pool-' + wwn['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: + # append purpose param with suffix used by UCSM + purpose_param = wwn['purpose'] + '-wwn-assignment' + if mo_exists: + # check top-level mo props + kwargs = dict(assignment_order=wwn['order']) + kwargs['descr'] = wwn['descr'] + kwargs['purpose'] = purpose_param + if (mo.check_prop_match(**kwargs)): + # top-level props match, check next level mo/props + if 'last_addr' in wwn and 'first_addr' in wwn: + block_dn = dn + '/block-' + wwn['first_addr'].upper() + '-' + wwn['last_addr'].upper() + mo_1 = ucs.login_handle.query_dn(block_dn) + if mo_1: + props_match = True + else: + props_match = True + + if not props_match: + if not module.check_mode: + # create if mo does not already exist + mo = FcpoolInitiators( + parent_mo_or_dn=module.params['org_dn'], + name=wwn['name'], + descr=wwn['descr'], + assignment_order=wwn['order'], + purpose=purpose_param, + ) + if 'last_addr' in wwn and 'first_addr' in wwn: + mo_1 = FcpoolBlock( + parent_mo_or_dn=mo, + to=wwn['last_addr'], + r_from=wwn['first_addr'], + ) + + ucs.login_handle.add_mo(mo, 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) + + +if __name__ == '__main__': + main() |