VMware: New module: vmware_tag (#37261)

This module is based on vSphere REST API. This module allows
user to manage various tags and their association with
categories. This fix also adds vCenter REST client library which can
be re-used for other REST based modules.

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
pull/38587/head
Abhijeet Kasurde 6 years ago committed by GitHub
parent a0b4462aea
commit d70b3b4661
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,6 +3,9 @@
# 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
import atexit
import os
import ssl

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Ansible Project
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
# 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
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
try:
from pyVim import connect
from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError:
HAS_PYVMOMI = False
try:
from vmware.vapi.lib.connect import get_requests_connector
from vmware.vapi.security.session import create_session_security_context
from vmware.vapi.security.user_password import create_user_password_security_context
from com.vmware.cis_client import Session
from com.vmware.vapi.std_client import DynamicID
HAS_VCLOUD = True
except ImportError:
HAS_VCLOUD = False
try:
from vmware.vapi.stdlib.client.factories import StubConfigurationFactory
HAS_VSPHERE = True
except ImportError:
HAS_VSPHERE = False
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import env_fallback
class VmwareRestClient(object):
def __init__(self, module):
"""
Constructor
"""
self.module = module
self.params = module.params
self.check_required_library()
self.connect = self.connect_to_rest()
def check_required_library(self):
"""
Function to check required libraries
"""
if not HAS_REQUESTS:
self.module.fail_json(msg="Unable to find 'requests' Python library which is required."
" Please install using 'pip install requests'")
if not HAS_PYVMOMI:
self.module.fail_json(msg="PyVmomi Python module required. Install using 'pip install PyVmomi'")
if not HAS_VSPHERE:
self.module.fail_json(msg="Unable to find 'vSphere Automation SDK' Python library which is required."
" Please refer this URL for installation steps"
" - https://code.vmware.com/web/sdk/65/vsphere-automation-python")
if not HAS_VCLOUD:
self.module.fail_json(msg="Unable to find 'vCloud Suite SDK' Python library which is required."
" Please refer this URL for installation steps"
" - https://code.vmware.com/web/sdk/60/vcloudsuite-python")
def connect_to_rest(self):
"""
Function to connect to server using username and password
"""
session = requests.Session()
session.verify = self.params.get('validate_certs')
username = self.params.get('username', None)
password = self.params.get('password', None)
if not all([self.params.get('hostname', None), username, password]):
self.module.fail_json(msg="Missing one of the following : hostname, username, password."
" Please read the documentation for more information.")
vcenter_url = "%(protocol)s://%(hostname)s/api" % self.params
# Get request connector
connector = get_requests_connector(session=session, url=vcenter_url)
# Create standard Configuration
stub_config = StubConfigurationFactory.new_std_configuration(connector)
# Use username and password in the security context to authenticate
security_context = create_user_password_security_context(username, password)
# Login
stub_config.connector.set_security_context(security_context)
# Create the stub for the session service and login by creating a session.
session_svc = Session(stub_config)
session_id = None
try:
session_id = session_svc.create()
except OSError as os_err:
self.module.fail_json(msg="Failed to login to %s: %s" % (self.params['hostname'],
to_native(os_err)))
if session_id is None:
self.module.fail_json(msg="Failed to create session using provided credentials."
" Please check hostname, username and password.")
# After successful authentication, store the session identifier in the security
# context of the stub and use that for all subsequent remote requests
session_security_context = create_session_security_context(session_id)
stub_config.connector.set_security_context(session_security_context)
if stub_config is None:
self.module.fail_json(msg="Failed to login to %(hostname)s" % self.params)
return stub_config
@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),
)

@ -0,0 +1,238 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Ansible Project
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
# 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_tag
short_description: Manage VMware tags
description:
- This module can be used to create / delete / update VMware tags.
- Tag Feature is introduced in vSphere 6 version, so module not supported in eariler versions of vSphere.
- All variables and VMware object names are case sensitive.
version_added: '2.6'
author:
- Abhijeet Kasurde (@akasurde)
notes:
- Tested on vSphere 6.5
requirements:
- python >= 2.6
- PyVmomi
- vSphere Automation SDK
- vCloud Suite SDK
options:
tag_name:
description:
- The name of tag to manage.
required: True
tag_description:
description:
- The tag description.
- This is required only if C(state) is set to C(present).
- This parameter is ignored, when C(state) is set to C(absent).
- Process of updating tag only allows description change.
required: False
default: ''
category_id:
description:
- The unique ID generated by vCenter should be used to.
- User can get this unique ID from facts module.
required: False
state:
description:
- The state of tag.
- If set to C(present) and tag does not exists, then tag is created.
- If set to C(present) and tag exists, then tag is updated.
- If set to C(absent) and tag exists, then tag is deleted.
- If set to C(absent) and tag does not exists, no action is taken.
required: False
default: 'present'
choices: [ 'present', 'absent' ]
extends_documentation_fragment: vmware_rest_client.documentation
'''
EXAMPLES = r'''
- name: Create a tag
vmware_tag:
hostname: 10.65.223.91
username: administrator@vsphere.local
password: Esxi@123$
validate_certs: False
category_id: 'urn:vmomi:InventoryServiceCategory:e785088d-6981-4b1c-9fb8-1100c3e1f742:GLOBAL'
tag_name: Sample_Tag_0002
tag_description: Sample Description
state: present
- name: Update tag description
vmware_tag:
hostname: 10.65.223.91
username: administrator@vsphere.local
password: Esxi@123$
validate_certs: False
tag_name: Sample_Tag_0002
tag_description: Some fancy description
state: present
- name: Delete tag
vmware_tag:
hostname: 10.65.223.91
username: administrator@vsphere.local
password: Esxi@123$
validate_certs: False
tag_name: Sample_Tag_0002
state: absent
'''
RETURN = r'''
results:
description: dictionary of tag metadata
returned: on success
type: dict
sample: {
"msg": "Tag 'Sample_Tag_0002' created.",
"tag_id": "urn:vmomi:InventoryServiceTag:bff91819-f529-43c9-80ca-1c9dfda09441:GLOBAL"
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.vmware_rest_client import VmwareRestClient
try:
from com.vmware.cis.tagging_client import Tag
except ImportError:
pass
class VmwareTag(VmwareRestClient):
def __init__(self, module):
super(VmwareTag, self).__init__(module)
self.tag_service = Tag(self.connect)
self.global_tags = dict()
self.tag_name = self.params.get('tag_name')
self.get_all_tags()
def ensure_state(self):
"""
Function to manage internal states of tags
"""
desired_state = self.params.get('state')
states = {
'present': {
'present': self.state_update_tag,
'absent': self.state_create_tag,
},
'absent': {
'present': self.state_delete_tag,
'absent': self.state_unchanged,
}
}
states[desired_state][self.check_tag_status()]()
def state_create_tag(self):
"""
Function to create tag
"""
tag_spec = self.tag_service.CreateSpec()
tag_spec.name = self.tag_name
tag_spec.description = self.params.get('tag_description')
category_id = self.params.get('category_id', None)
if category_id is None:
self.module.fail_json(msg="'category_id' is required parameter while creating tag.")
tag_spec.category_id = category_id
tag_id = self.tag_service.create(tag_spec)
if tag_id:
self.module.exit_json(changed=True,
results=dict(msg="Tag '%s' created." % tag_spec.name,
tag_id=tag_id))
self.module.exit_json(changed=False,
results=dict(msg="No tag created", tag_id=''))
def state_unchanged(self):
"""
Function to return unchanged state
"""
self.module.exit_json(changed=False)
def state_update_tag(self):
"""
Function to update tag
"""
changed = False
results = dict(msg="Tag %s is unchanged." % self.tag_name,
tag_id=self.global_tags[self.tag_name]['tag_id'])
tag_update_spec = self.tag_service.UpdateSpec()
tag_desc = self.global_tags[self.tag_name]['tag_description']
desired_tag_desc = self.params.get('tag_description')
if tag_desc != desired_tag_desc:
tag_update_spec.setDescription = desired_tag_desc
results['msg'] = 'Tag %s updated.' % self.tag_name
changed = True
self.module.exit_json(changed=changed, results=results)
def state_delete_tag(self):
"""
Function to delete tag
"""
tag_id = self.global_tags[self.tag_name]['tag_id']
self.tag_service.delete(tag_id=tag_id)
self.module.exit_json(changed=True,
results=dict(msg="Tag '%s' deleted." % self.tag_name,
tag_id=tag_id))
def check_tag_status(self):
"""
Function to check if tag exists or not
Returns: 'present' if tag found, else 'absent'
"""
if self.tag_name in self.global_tags:
return 'present'
else:
return 'absent'
def get_all_tags(self):
"""
Function to retrieve all tag information
"""
for tag in self.tag_service.list():
tag_obj = self.tag_service.get(tag)
self.global_tags[tag_obj.name] = dict(tag_description=tag_obj.description,
tag_used_by=tag_obj.used_by,
tag_category_id=tag_obj.category_id,
tag_id=tag_obj.id
)
def main():
argument_spec = VmwareRestClient.vmware_client_argument_spec()
argument_spec.update(
tag_name=dict(type='str', required=True),
tag_description=dict(type='str', default='', required=False),
category_id=dict(type='str', required=False),
state=dict(type='str', choices=['present', 'absent'], default='present', required=False),
)
module = AnsibleModule(argument_spec=argument_spec)
vmware_tag = VmwareTag(module)
vmware_tag.ensure_state()
if __name__ == '__main__':
main()

@ -0,0 +1,39 @@
# Copyright: (c) 2018, Ansible Project
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
class ModuleDocFragment(object):
# Parameters for VMware REST Client based modules
DOCUMENTATION = '''
options:
hostname:
description:
- The hostname or IP address of the vSphere vCenter server.
- If the value is not specified in the task, the value of environment variable C(VMWARE_HOST) will be used instead.
required: False
username:
description:
- The username of the vSphere vCenter server.
- If the value is not specified in the task, the value of environment variable C(VMWARE_USER) will be used instead.
aliases: ['user', 'admin']
password:
description:
- The password of the vSphere vCenter server.
- If the value is not specified in the task, the value of environment variable C(VMWARE_PASSWORD) will be used instead.
required: False
aliases: ['pass', 'pwd']
validate_certs:
description:
- Allows connection when SSL certificates are not valid. Set to C(false) when certificates are not trusted.
- If the value is not specified in the task, the value of environment variable C(VMWARE_VALIDATE_CERTS) will be used instead.
default: True
type: bool
required: False
protocol:
description:
- The connection to protocol.
choices: ['https', 'http']
default: 'https'
required: False
'''
Loading…
Cancel
Save