Created
March 20, 2020 07:20
-
-
Save Akasurde/a103484d3785f00d7bb7fa60a88dc9c2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# -*- coding: utf-8 -*- | |
# Copyright: (c) 2020, Abhijeet Kasurde <[email protected]> | |
# Copyright: (c) 2020, 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' | |
} | |
DOCUMENTATION = r''' | |
--- | |
module: vmware_datacenter_info | |
short_description: Gather information about VMware vSphere Datacenters | |
description: | |
- This module can be used to gather information VMware vSphere Datacenters. | |
author: | |
- Abhijeet Kasurde (@Akasurde) | |
notes: | |
- Tested on vSphere 6.5 | |
requirements: | |
- "python >= 2.7" | |
- PyVmomi | |
options: | |
datacenter: | |
description: | |
- The name of the datacenter to gather information for. | |
- If not provided, will gather information about all datacenters from the VMware infra. | |
type: str | |
aliases: ['datacenter_name'] | |
schema: | |
description: | |
- Specify the output schema desired. | |
- The 'summary' output schema is the legacy output from the module. | |
- The 'vsphere' output schema is the vSphere API class definition which requires pyvmomi>6.7.1. | |
choices: ['summary', 'vsphere'] | |
default: 'summary' | |
type: str | |
properties: | |
description: | |
- Specify the properties to retrieve. | |
- If not specified, all properties are retrieved (deeply). | |
- Results are returned in a structure identical to the vSphere API. | |
- 'Example:' | |
- ' properties: [' | |
- ' "overallStatus"' | |
- ' ]' | |
- Only valid when C(schema) is C(vsphere). | |
type: list | |
elements: str | |
show_tag: | |
description: | |
- Tags related to Datacenter are shown if set to C(True). | |
default: False | |
type: bool | |
extends_documentation_fragment: | |
- community.vmware.vmware.documentation | |
''' | |
EXAMPLES = r''' | |
- name: Gather information about all datacenters | |
vmware_datacenter_info: | |
hostname: '{{ vcenter_hostname }}' | |
username: '{{ vcenter_username }}' | |
password: '{{ vcenter_password }}' | |
delegate_to: localhost | |
- name: Gather information about a particular datacenter | |
vmware_datacenter_info: | |
hostname: '{{ vcenter_hostname }}' | |
username: '{{ vcenter_username }}' | |
password: '{{ vcenter_password }}' | |
datacenter: '{{ datacenter_name }}' | |
delegate_to: localhost | |
- name: Gather information about a particular datacenter | |
vmware_datacenter_info: | |
hostname: '{{ vcenter_hostname }}' | |
username: '{{ vcenter_username }}' | |
password: '{{ vcenter_password }}' | |
datacenter: '{{ datacenter_name }}' | |
show_tag: True | |
delegate_to: localhost | |
- name: Gather vSphere schema information | |
vmware_datacenter_info: | |
hostname: '{{ vcenter_hostname }}' | |
username: '{{ vcenter_username }}' | |
password: '{{ vcenter_password }}' | |
datacenter: '{{ datacenter_name }}' | |
schema: vsphere | |
properties: | |
- configStatus | |
- overallStatus | |
''' | |
RETURN = r""" | |
datacenter_info: | |
description: Information about datacenter | |
returned: always | |
type: list | |
sample: | |
[ | |
{ | |
"configStatus": "gray", | |
"moid": "datacenter-2", | |
"name": "Asia-Datacenter1" | |
} | |
] | |
""" | |
try: | |
from pyVmomi import vim | |
except ImportError: | |
pass | |
from ansible.module_utils.basic import AnsibleModule | |
from ansible.module_utils._text import to_native | |
from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec | |
from ansible.module_utils.vmware_rest_client import VmwareRestClient | |
class VmwareDatacenterInfo(PyVmomi): | |
def __init__(self, module): | |
super(VmwareDatacenterInfo, self).__init__(module) | |
if self.params.get('show_tag'): | |
self.vmware_client = VmwareRestClient(self.module) | |
def get_datacenter_info(self): | |
self.datacenter_name = self.params.get('datacenter') | |
results = dict( | |
changed=False, | |
datacenter_info=[], | |
) | |
datacenter_objs = self.get_managed_objects_properties(vim_type=vim.Datacenter, properties=['name']) | |
dcs = [] | |
for dc_obj in datacenter_objs: | |
if len(dc_obj.propSet) == 1: | |
if self.datacenter_name is not None: | |
if dc_obj.propSet[0].val == to_native(self.datacenter_name): | |
dcs.append(dc_obj.obj) | |
continue | |
else: | |
dcs.append(dc_obj.obj) | |
for obj in dcs: | |
if obj is None: | |
continue | |
temp_dc = dict( | |
name=obj.name, | |
moid=obj._moId, | |
) | |
if self.module.params['schema'] == 'summary': | |
temp_dc.update( | |
dict( | |
config_status=obj.configStatus, | |
overall_status=obj.overallStatus, | |
) | |
) | |
else: | |
temp_dc.update(self.to_json(obj, self.params.get('properties'))) | |
if self.params.get('show_tag'): | |
temp_dc.update({ | |
'tags': self.vmware_client.get_tags_for_datacenter(datacenter_mid=obj._moId) | |
}) | |
results['datacenter_info'].append(temp_dc) | |
self.module.exit_json(**results) | |
def main(): | |
argument_spec = vmware_argument_spec() | |
argument_spec.update( | |
dict( | |
datacenter=dict(type='str', aliases=['datacenter_name']), | |
schema=dict(type='str', choices=['summary', 'vsphere'], default='summary'), | |
properties=dict(type='list', elements='str'), | |
show_tag=dict(type='bool', default=False), | |
) | |
) | |
module = AnsibleModule( | |
argument_spec=argument_spec, | |
supports_check_mode=True | |
) | |
vmware_datacenter_mgr = VmwareDatacenterInfo(module) | |
vmware_datacenter_mgr.get_datacenter_info() | |
if __name__ == '__main__': | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# Copyright: (c) 2018, Ansible Project | |
# Copyright: (c) 2018, Abhijeet Kasurde <[email protected]> | |
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) | |
from __future__ import absolute_import, division, print_function | |
__metaclass__ = type | |
import traceback | |
REQUESTS_IMP_ERR = None | |
try: | |
import requests | |
HAS_REQUESTS = True | |
except ImportError: | |
REQUESTS_IMP_ERR = traceback.format_exc() | |
HAS_REQUESTS = False | |
PYVMOMI_IMP_ERR = None | |
try: | |
from pyVim import connect | |
from pyVmomi import vim, vmodl | |
HAS_PYVMOMI = True | |
except ImportError: | |
PYVMOMI_IMP_ERR = traceback.format_exc() | |
HAS_PYVMOMI = False | |
VSPHERE_IMP_ERR = None | |
try: | |
from com.vmware.vapi.std_client import DynamicID | |
from vmware.vapi.vsphere.client import create_vsphere_client | |
from com.vmware.vapi.std.errors_client import Unauthorized | |
from com.vmware.content.library_client import Item | |
from com.vmware.vcenter_client import (Folder, | |
Datacenter, | |
ResourcePool, | |
Datastore, | |
Cluster, | |
Host) | |
HAS_VSPHERE = True | |
except ImportError: | |
VSPHERE_IMP_ERR = traceback.format_exc() | |
HAS_VSPHERE = False | |
from ansible.module_utils.basic import env_fallback, missing_required_lib | |
class VmwareRestClient(object): | |
def __init__(self, module): | |
""" | |
Constructor | |
""" | |
self.module = module | |
self.params = module.params | |
self.check_required_library() | |
self.api_client = self.connect_to_vsphere_client() | |
# Helper function | |
def get_error_message(self, error): | |
""" | |
Helper function to show human readable error messages. | |
""" | |
err_msg = [] | |
if not error.messages: | |
if isinstance(error, Unauthorized): | |
return "Authorization required." | |
return "Generic error occurred." | |
for err in error.messages: | |
err_msg.append(err.default_message % err.args) | |
return " ,".join(err_msg) | |
def check_required_library(self): | |
""" | |
Check required libraries | |
""" | |
if not HAS_REQUESTS: | |
self.module.fail_json(msg=missing_required_lib('requests'), | |
exception=REQUESTS_IMP_ERR) | |
if not HAS_PYVMOMI: | |
self.module.fail_json(msg=missing_required_lib('PyVmomi'), | |
exception=PYVMOMI_IMP_ERR) | |
if not HAS_VSPHERE: | |
self.module.fail_json( | |
msg=missing_required_lib('vSphere Automation SDK', | |
url='https://code.vmware.com/web/sdk/65/vsphere-automation-python'), | |
exception=VSPHERE_IMP_ERR) | |
@staticmethod | |
def vmware_client_argument_spec(): | |
return dict( | |
hostname=dict(type='str', | |
fallback=(env_fallback, ['VMWARE_HOST'])), | |
username=dict(type='str', | |
fallback=(env_fallback, ['VMWARE_USER']), | |
aliases=['user', 'admin']), | |
password=dict(type='str', | |
fallback=(env_fallback, ['VMWARE_PASSWORD']), | |
aliases=['pass', 'pwd'], | |
no_log=True), | |
protocol=dict(type='str', | |
default='https', | |
choices=['https', 'http']), | |
validate_certs=dict(type='bool', | |
fallback=(env_fallback, ['VMWARE_VALIDATE_CERTS']), | |
default=True), | |
) | |
def connect_to_vsphere_client(self): | |
""" | |
Connect to vSphere API Client with Username and Password | |
""" | |
username = self.params.get('username') | |
password = self.params.get('password') | |
hostname = self.params.get('hostname') | |
session = requests.Session() | |
session.verify = self.params.get('validate_certs') | |
if not all([hostname, username, password]): | |
self.module.fail_json(msg="Missing one of the following : hostname, username, password." | |
" Please read the documentation for more information.") | |
client = create_vsphere_client( | |
server=hostname, | |
username=username, | |
password=password, | |
session=session) | |
if client is None: | |
self.module.fail_json(msg="Failed to login to %s" % hostname) | |
return client | |
def get_tags_for_object(self, tag_service=None, tag_assoc_svc=None, dobj=None): | |
""" | |
Return list of tag objects associated with an object | |
Args: | |
dobj: Dynamic object | |
tag_service: Tag service object | |
tag_assoc_svc: Tag Association object | |
Returns: List of tag objects associated with the given object | |
""" | |
# This method returns list of tag objects only, | |
# Please use get_tags_for_dynamic_obj for more object details | |
tags = [] | |
if not dobj: | |
return tags | |
if not tag_service: | |
tag_service = self.api_client.tagging.Tag | |
if not tag_assoc_svc: | |
tag_assoc_svc = self.api_client.tagging.TagAssociation | |
tag_ids = tag_assoc_svc.list_attached_tags(dobj) | |
for tag_id in tag_ids: | |
tags.append(tag_service.get(tag_id)) | |
return tags | |
def get_tags_for_dynamic_obj(self, mid=None, type=None): | |
""" | |
Return list of tag object details associated with object | |
Args: | |
mid: Dynamic object for specified object | |
type: Type of DynamicID to lookup | |
Returns: List of tag object details associated with the given object | |
""" | |
tags = [] | |
if mid is None: | |
return tags | |
dynamic_managed_object = DynamicID(type=type, id=mid) | |
temp_tags_model = self.get_tags_for_object(dobj=dynamic_managed_object) | |
category_service = self.api_client.tagging.Category | |
for tag_obj in temp_tags_model: | |
tags.append({ | |
'id': tag_obj.id, | |
'category_name': category_service.get(tag_obj.category_id).name, | |
'name': tag_obj.name, | |
'description': tag_obj.description, | |
'category_id': tag_obj.category_id, | |
}) | |
return tags | |
def get_tags_for_datacenter(self, datacenter_mid=None): | |
return self.get_tags_for_dynamic_obj(mid=datacenter_mid, type='Datacenter') | |
def get_tags_for_cluster(self, cluster_mid=None): | |
""" | |
Return list of tag object associated with cluster | |
Args: | |
cluster_mid: Dynamic object for cluster | |
Returns: List of tag object associated with the given cluster | |
""" | |
return self.get_tags_for_dynamic_obj(mid=cluster_mid, type='ClusterComputeResource') | |
def get_tags_for_hostsystem(self, hostsystem_mid=None): | |
""" | |
Return list of tag object associated with host system | |
Args: | |
hostsystem_mid: Dynamic object for host system | |
Returns: List of tag object associated with the given host system | |
""" | |
return self.get_tags_for_dynamic_obj(mid=hostsystem_mid, type='HostSystem') | |
def get_tags_for_vm(self, vm_mid=None): | |
""" | |
Return list of tag object associated with virtual machine | |
Args: | |
vm_mid: Dynamic object for virtual machine | |
Returns: List of tag object associated with the given virtual machine | |
""" | |
return self.get_tags_for_dynamic_obj(mid=vm_mid, type='VirtualMachine') | |
def get_vm_tags(self, tag_service=None, tag_association_svc=None, vm_mid=None): | |
""" | |
Return list of tag name associated with virtual machine | |
Args: | |
tag_service: Tag service object | |
tag_association_svc: Tag association object | |
vm_mid: Dynamic object for virtual machine | |
Returns: List of tag names associated with the given virtual machine | |
""" | |
# This API returns just names of tags | |
# Please use get_tags_for_vm for more tag object details | |
tags = [] | |
if vm_mid is None: | |
return tags | |
dynamic_managed_object = DynamicID(type='VirtualMachine', id=vm_mid) | |
temp_tags_model = self.get_tags_for_object(tag_service, tag_association_svc, dynamic_managed_object) | |
for tag_obj in temp_tags_model: | |
tags.append(tag_obj.name) | |
return tags | |
def get_library_item_by_name(self, name): | |
""" | |
Returns the identifier of the library item with the given name. | |
Args: | |
name (str): The name of item to look for | |
Returns: | |
str: The item ID or None if the item is not found | |
""" | |
find_spec = Item.FindSpec(name=name) | |
item_ids = self.api_client.content.library.Item.find(find_spec) | |
item_id = item_ids[0] if item_ids else None | |
return item_id | |
def get_datacenter_by_name(self, datacenter_name): | |
""" | |
Returns the identifier of a datacenter | |
Note: The method assumes only one datacenter with the mentioned name. | |
""" | |
filter_spec = Datacenter.FilterSpec(names=set([datacenter_name])) | |
datacenter_summaries = self.api_client.vcenter.Datacenter.list(filter_spec) | |
datacenter = datacenter_summaries[0].datacenter if len(datacenter_summaries) > 0 else None | |
return datacenter | |
def get_folder_by_name(self, datacenter_name, folder_name): | |
""" | |
Returns the identifier of a folder | |
with the mentioned names. | |
""" | |
datacenter = self.get_datacenter_by_name(datacenter_name) | |
if not datacenter: | |
return None | |
filter_spec = Folder.FilterSpec(type=Folder.Type.VIRTUAL_MACHINE, | |
names=set([folder_name]), | |
datacenters=set([datacenter])) | |
folder_summaries = self.api_client.vcenter.Folder.list(filter_spec) | |
folder = folder_summaries[0].folder if len(folder_summaries) > 0 else None | |
return folder | |
def get_resource_pool_by_name(self, datacenter_name, resourcepool_name): | |
""" | |
Returns the identifier of a resource pool | |
with the mentioned names. | |
""" | |
datacenter = self.get_datacenter_by_name(datacenter_name) | |
if not datacenter: | |
return None | |
names = set([resourcepool_name]) if resourcepool_name else None | |
filter_spec = ResourcePool.FilterSpec(datacenters=set([datacenter]), | |
names=names) | |
resource_pool_summaries = self.api_client.vcenter.ResourcePool.list(filter_spec) | |
resource_pool = resource_pool_summaries[0].resource_pool if len(resource_pool_summaries) > 0 else None | |
return resource_pool | |
def get_datastore_by_name(self, datacenter_name, datastore_name): | |
""" | |
Returns the identifier of a datastore | |
with the mentioned names. | |
""" | |
datacenter = self.get_datacenter_by_name(datacenter_name) | |
if not datacenter: | |
return None | |
names = set([datastore_name]) if datastore_name else None | |
filter_spec = Datastore.FilterSpec(datacenters=set([datacenter]), | |
names=names) | |
datastore_summaries = self.api_client.vcenter.Datastore.list(filter_spec) | |
datastore = datastore_summaries[0].datastore if len(datastore_summaries) > 0 else None | |
return datastore | |
def get_cluster_by_name(self, datacenter_name, cluster_name): | |
""" | |
Returns the identifier of a cluster | |
with the mentioned names. | |
""" | |
datacenter = self.get_datacenter_by_name(datacenter_name) | |
if not datacenter: | |
return None | |
names = set([cluster_name]) if cluster_name else None | |
filter_spec = Cluster.FilterSpec(datacenters=set([datacenter]), | |
names=names) | |
cluster_summaries = self.api_client.vcenter.Cluster.list(filter_spec) | |
cluster = cluster_summaries[0].cluster if len(cluster_summaries) > 0 else None | |
return cluster | |
def get_host_by_name(self, datacenter_name, host_name): | |
""" | |
Returns the identifier of a Host | |
with the mentioned names. | |
""" | |
datacenter = self.get_datacenter_by_name(datacenter_name) | |
if not datacenter: | |
return None | |
names = set([host_name]) if host_name else None | |
filter_spec = Host.FilterSpec(datacenters=set([datacenter]), | |
names=names) | |
host_summaries = self.api_client.vcenter.Host.list(filter_spec) | |
host = host_summaries[0].host if len(host_summaries) > 0 else None | |
return host | |
@staticmethod | |
def search_svc_object_by_name(service, svc_obj_name=None): | |
""" | |
Return service object by name | |
Args: | |
service: Service object | |
svc_obj_name: Name of service object to find | |
Returns: Service object if found else None | |
""" | |
if not svc_obj_name: | |
return None | |
for svc_object in service.list(): | |
svc_obj = service.get(svc_object) | |
if svc_obj.name == svc_obj_name: | |
return svc_obj | |
return None |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment