From d1eb4fe58c0eaba76ea18e9b62dec9604f6a6299 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Sun, 4 Mar 2018 10:20:47 +0530 Subject: [PATCH] VMware: Refactor vmware_target_canonical_facts (#36964) Signed-off-by: Abhijeet Kasurde --- CHANGELOG.md | 2 + .../vmware/vmware_target_canonical_facts.py | 185 +++++++++++++----- .../vmware_target_canonical_facts/aliases | 3 + .../tasks/main.yml | 90 +++++++++ 4 files changed, 235 insertions(+), 45 deletions(-) create mode 100644 test/integration/targets/vmware_target_canonical_facts/aliases create mode 100644 test/integration/targets/vmware_target_canonical_facts/tasks/main.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f8c6a98122..47ced3d3443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ See [Porting Guide](http://docs.ansible.com/ansible/devel/porting_guides/porting ### Minor Changes +* Ansible 2.6 and onwards, `target_id` parameter in `vmware_target_canonical_facts` module is an optional parameter. + #### Removed modules (previously deprecated) ### New Modules diff --git a/lib/ansible/modules/cloud/vmware/vmware_target_canonical_facts.py b/lib/ansible/modules/cloud/vmware/vmware_target_canonical_facts.py index 32fc5d936a8..0b00cea6084 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_target_canonical_facts.py +++ b/lib/ansible/modules/cloud/vmware/vmware_target_canonical_facts.py @@ -1,90 +1,185 @@ #!/usr/bin/python # -*- coding: utf-8 -*- - # Copyright: (c) 2015, Joseph Callen +# Copyright: (c) 2018, Ansible Project # 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'} +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} DOCUMENTATION = ''' --- module: vmware_target_canonical_facts -short_description: Return canonical (NAA) from an ESXi host +short_description: Return canonical (NAA) from an ESXi host system description: - - Return canonical (NAA) from an ESXi host based on SCSI target ID + - This module can be used to gather facts about canonical (NAA) from an ESXi host based on SCSI target ID. + version_added: "2.0" author: - Joseph Callen (@jcpowermac) +- Abhijeet Kasurde (@akasurde) notes: requirements: - - Tested on vSphere 5.5 + - Tested on vSphere 5.5 and 6.5 - PyVmomi installed options: - target_id: - description: - - The target id based on order of scsi device - required: True + target_id: + description: + - The target id based on order of scsi device. + - version 2.6 onwards, this parameter is optional. + required: False + cluster_name: + description: + - Name of the cluster. + - Facts about all SCSI devices for all host system in the given cluster is returned. + - This parameter is required, if C(esxi_hostname) is not provided. + version_added: 2.6 + esxi_hostname: + description: + - Name of the ESXi host system. + - Facts about all SCSI devices for the given ESXi host system is returned. + - This parameter is required, if C(cluster_name) is not provided. + version_added: 2.6 extends_documentation_fragment: vmware.documentation ''' EXAMPLES = ''' -# Example vmware_target_canonical_facts command from Ansible Playbooks -- name: Get Canonical name +- name: Get Canonical name of particular target on particular ESXi host system local_action: module: vmware_target_canonical_facts - hostname: "{{ ansible_ssh_host }}" - username: root - password: vmware + hostname: vcenter_hostname + username: vcenter_user + password: vcenter_pass target_id: 7 + esxi_hostname: esxi_hostname + +- name: Get Canonical name of all target on particular ESXi host system + local_action: + module: vmware_target_canonical_facts + hostname: vcenter_hostname + username: vcenter_user + password: vcenter_pass + esxi_hostname: esxi_hostname + +- name: Get Canonical name of all ESXi hostname on particular Cluster + local_action: + module: vmware_target_canonical_facts + hostname: vcenter_hostname + username: vcenter_user + password: vcenter_pass + cluster_name: cluster_name ''' +RETURN = r""" +canonical: + description: metadata about SCSI Target device + returned: if host system and target id is given + type: str + sample: "mpx.vmhba0:C0:T0:L0" + +scsi_tgt_facts: + description: metadata about all SCSI Target devices + returned: if host system or cluster is given + type: dict + sample: { + "DC0_C0_H0": { + "scsilun_canonical": { + "key-vim.host.ScsiDisk-0000000000766d686261303a303a30": "mpx.vmhba0:C0:T0:L0", + "key-vim.host.ScsiLun-0005000000766d686261313a303a30": "mpx.vmhba1:C0:T0:L0" + }, + "target_lun_uuid": { + "0": "key-vim.host.ScsiDisk-0000000000766d686261303a303a30" + } + }, + "DC0_C0_H1": { + "scsilun_canonical": { + "key-vim.host.ScsiDisk-0000000000766d686261303a303a30": "mpx.vmhba0:C0:T0:L0", + "key-vim.host.ScsiLun-0005000000766d686261313a303a30": "mpx.vmhba1:C0:T0:L0" + }, + "target_lun_uuid": { + "0": "key-vim.host.ScsiDisk-0000000000766d686261303a303a30" + } + }, + } +""" + try: from pyVmomi import vim, vmodl - HAS_PYVMOMI = True except ImportError: - HAS_PYVMOMI = False + pass from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.vmware import HAS_PYVMOMI, connect_to_api, get_all_objs, vmware_argument_spec +from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec -def find_hostsystem(content): - host_system = get_all_objs(content, [vim.HostSystem]) - for host in host_system: - return host - return None +class ScsiTargetFactsManager(PyVmomi): + def __init__(self, module): + super(ScsiTargetFactsManager, self).__init__(module) + cluster_name = self.module.params.get('cluster_name') + self.esxi_hostname = self.module.params.get('esxi_hostname') + self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=self.esxi_hostname) + + def gather_scsi_device_facts(self): + """ + Function to gather facts about SCSI target devices + + """ + scsi_tgt_facts = {} + target_lun_uuid = {} + scsilun_canonical = {} + target_id = self.module.params['target_id'] + + for host in self.hosts: + # Associate the scsiLun key with the canonicalName (NAA) + for scsilun in host.config.storageDevice.scsiLun: + scsilun_canonical[scsilun.key] = scsilun.canonicalName + + # Associate target number with LUN uuid + for target in host.config.storageDevice.scsiTopology.adapter[0].target: + for lun in target.lun: + target_lun_uuid[target.target] = lun.scsiLun + + scsi_tgt_facts[host.name] = dict(scsilun_canonical=scsilun_canonical, + target_lun_uuid=target_lun_uuid) + + if target_id is not None and self.esxi_hostname is not None: + canonical = '' + temp_lun_data = scsi_tgt_facts[self.esxi_hostname]['target_lun_uuid'] + if self.esxi_hostname in scsi_tgt_facts and \ + target_id in temp_lun_data: + temp_scsi_data = scsi_tgt_facts[self.esxi_hostname]['scsilun_canonical'] + temp_target = temp_lun_data[target_id] + canonical = temp_scsi_data[temp_target] + self.module.exit_json(changed=False, canonical=canonical) + + self.module.exit_json(changed=False, scsi_tgt_facts=scsi_tgt_facts) def main(): - argument_spec = vmware_argument_spec() - argument_spec.update(dict(target_id=dict(required=True, type='int'))) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) + argument_spec.update( + dict( + target_id=dict(required=False, type='int'), + cluster_name=dict(type='str', required=False), + esxi_hostname=dict(type='str', required=False), + ) + ) - if not HAS_PYVMOMI: - module.fail_json(msg='pyvmomi is required for this module') + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=[ + ['cluster_name', 'esxi_hostname'], + ], + ) - content = connect_to_api(module) - host = find_hostsystem(content) - - target_lun_uuid = {} - scsilun_canonical = {} - - # Associate the scsiLun key with the canonicalName (NAA) - for scsilun in host.config.storageDevice.scsiLun: - scsilun_canonical[scsilun.key] = scsilun.canonicalName - - # Associate target number with LUN uuid - for target in host.config.storageDevice.scsiTopology.adapter[0].target: - for lun in target.lun: - target_lun_uuid[target.target] = lun.scsiLun - - module.exit_json(changed=False, canonical=scsilun_canonical[target_lun_uuid[module.params['target_id']]]) + scsi_tgt_manager = ScsiTargetFactsManager(module) + scsi_tgt_manager.gather_scsi_device_facts() if __name__ == '__main__': diff --git a/test/integration/targets/vmware_target_canonical_facts/aliases b/test/integration/targets/vmware_target_canonical_facts/aliases new file mode 100644 index 00000000000..6ee4e3d4f9f --- /dev/null +++ b/test/integration/targets/vmware_target_canonical_facts/aliases @@ -0,0 +1,3 @@ +posix/ci/cloud/group4/vcenter +cloud/vcenter + diff --git a/test/integration/targets/vmware_target_canonical_facts/tasks/main.yml b/test/integration/targets/vmware_target_canonical_facts/tasks/main.yml new file mode 100644 index 00000000000..3b152c83cfe --- /dev/null +++ b/test/integration/targets/vmware_target_canonical_facts/tasks/main.yml @@ -0,0 +1,90 @@ +# Test code for the vmware_target_canonical_facts module. +# Copyright: (c) 2018, Abhijeet Kasurde +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# TODO: vcsim does not support SCSI target releated operations + +#- name: make sure pyvmomi is installed +# pip: +# name: pyvmomi +# state: latest +# when: "{{ ansible_user_id == 'root' }}" + +#- name: store the vcenter container ip +# set_fact: +# vcsim: "{{ lookup('env', 'vcenter_host') }}" + +#- debug: var=vcsim + +#- name: Wait for Flask controller to come up online +# wait_for: +# host: "{{ vcsim }}" +# port: 5000 +# state: started + +#- name: kill vcsim +# uri: +# url: http://{{ vcsim }}:5000/killall + +#- name: start vcsim +# uri: +# url: http://{{ vcsim }}:5000/spawn?cluster=2 +# register: vcsim_instance + +#- debug: +# var: vcsim_instance + +#- name: Wait for vcsim server to come up online +# wait_for: +# host: "{{ vcsim }}" +# port: 443 +# state: started + +#- name: get a list of Cluster from vcsim +# uri: +# url: http://{{ vcsim }}:5000/govc_find?filter=CCR +# register: clusters + +#- name: get a cluster +# set_fact: +# ccr1: "{{ clusters.json[0] | basename }}" + +#- name: get a list of hosts from vcsim +# uri: +# url: http://{{ vcsim }}:5000/govc_find?filter=H +# register: hosts + +#- name: get a host +# set_fact: +# host1: "{{ hosts.json[0] | basename }}" + +#- debug: var=ccr1 +#- debug: var=host1 + +#- name: Gather target facts for all ESXi host from given cluster +# vmware_target_canonical_facts: +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance.json.username }}" +# password: "{{ vcsim_instance.json.password }}" +# validate_certs: False +# cluster_name: "{{ ccr1 }}" +# register: target_0001_results + +#- assert: +# that: +# - "not target_0001_results.changed" +# - "target_0001_results.scsi_tgt_facts is defined" + +#- name: Gather target facts for ESXi host +# vmware_target_canonical_facts: +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance.json.username }}" +# password: "{{ vcsim_instance.json.password }}" +# validate_certs: False +# esxi_hostname: "{{ host1 }}" +# register: target_0002_results + +#- assert: +# that: +# - "not target_0002_results.changed" +# - "target_0002_results.scsi_tgt_facts is defined"