VMware: Handle user unauthorization in tagging scenarios (#58405)

Handle unauthorization scenarios in VMware tagging APIs.

Fixes: #58326

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
This commit is contained in:
Abhijeet Kasurde 2019-06-28 07:59:54 +05:30 committed by GitHub
parent 242f160747
commit e2d159c40c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 18 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- Handle user unauthorization errors in VMware REST API code for tagging (https://github.com/ansible/ansible/issues/58326).

View file

@ -29,6 +29,7 @@ VSPHERE_IMP_ERR = None
try: try:
from com.vmware.vapi.std_client import DynamicID from com.vmware.vapi.std_client import DynamicID
from vmware.vapi.vsphere.client import create_vsphere_client from vmware.vapi.vsphere.client import create_vsphere_client
from com.vmware.vapi.std.errors_client import Unauthorized
HAS_VSPHERE = True HAS_VSPHERE = True
except ImportError: except ImportError:
VSPHERE_IMP_ERR = traceback.format_exc() VSPHERE_IMP_ERR = traceback.format_exc()
@ -49,6 +50,22 @@ class VmwareRestClient(object):
self.check_required_library() self.check_required_library()
self.api_client = self.connect_to_vsphere_client() 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): def check_required_library(self):
""" """
Check required libraries Check required libraries

View file

@ -119,6 +119,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.vmware_rest_client import VmwareRestClient from ansible.module_utils.vmware_rest_client import VmwareRestClient
try: try:
from com.vmware.cis.tagging_client import CategoryModel from com.vmware.cis.tagging_client import CategoryModel
from com.vmware.vapi.std.errors_client import Error
except ImportError: except ImportError:
pass pass
@ -159,7 +160,11 @@ class VmwareCategory(VmwareRestClient):
category_spec.associable_types = set() category_spec.associable_types = set()
try:
category_id = self.category_service.create(category_spec) category_id = self.category_service.create(category_spec)
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
if category_id: if category_id:
self.module.exit_json(changed=True, self.module.exit_json(changed=True,
category_results=dict(msg="Category '%s' created." % category_spec.name, category_results=dict(msg="Category '%s' created." % category_spec.name,
@ -199,8 +204,11 @@ class VmwareCategory(VmwareRestClient):
change_list.append(True) change_list.append(True)
if any(change_list): if any(change_list):
try:
self.category_service.update(category_id, category_update_spec) self.category_service.update(category_id, category_update_spec)
changed = True changed = True
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
self.module.exit_json(changed=changed, self.module.exit_json(changed=changed,
category_results=results) category_results=results)
@ -208,7 +216,10 @@ class VmwareCategory(VmwareRestClient):
def state_delete_category(self): def state_delete_category(self):
"""Delete category.""" """Delete category."""
category_id = self.global_categories[self.category_name]['category_id'] category_id = self.global_categories[self.category_name]['category_id']
try:
self.category_service.delete(category_id=category_id) self.category_service.delete(category_id=category_id)
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
self.module.exit_json(changed=True, self.module.exit_json(changed=True,
category_results=dict(msg="Category '%s' deleted." % self.category_name, category_results=dict(msg="Category '%s' deleted." % self.category_name,
category_id=category_id)) category_id=category_id))

View file

@ -107,6 +107,10 @@ results:
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.vmware_rest_client import VmwareRestClient from ansible.module_utils.vmware_rest_client import VmwareRestClient
try:
from com.vmware.vapi.std.errors_client import Error
except ImportError:
pass
class VmwareTag(VmwareRestClient): class VmwareTag(VmwareRestClient):
@ -160,13 +164,18 @@ class VmwareTag(VmwareRestClient):
self.module.fail_json(msg="Unable to find category specified using 'category_id' - %s" % category_id) self.module.fail_json(msg="Unable to find category specified using 'category_id' - %s" % category_id)
tag_spec.category_id = category_id tag_spec.category_id = category_id
tag_id = ''
try:
tag_id = self.tag_service.create(tag_spec) tag_id = self.tag_service.create(tag_spec)
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
if tag_id: if tag_id:
self.module.exit_json(changed=True, self.module.exit_json(changed=True,
results=dict(msg="Tag '%s' created." % tag_spec.name, results=dict(msg="Tag '%s' created." % tag_spec.name,
tag_id=tag_id)) tag_id=tag_id))
self.module.exit_json(changed=False, self.module.exit_json(changed=False,
results=dict(msg="No tag created", tag_id='')) results=dict(msg="No tag created", tag_id=tag_id))
def state_unchanged(self): def state_unchanged(self):
""" """
@ -189,7 +198,11 @@ class VmwareTag(VmwareRestClient):
desired_tag_desc = self.params.get('tag_description') desired_tag_desc = self.params.get('tag_description')
if tag_desc != desired_tag_desc: if tag_desc != desired_tag_desc:
tag_update_spec.description = desired_tag_desc tag_update_spec.description = desired_tag_desc
try:
self.tag_service.update(tag_id, tag_update_spec) self.tag_service.update(tag_id, tag_update_spec)
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
results['msg'] = 'Tag %s updated.' % self.tag_name results['msg'] = 'Tag %s updated.' % self.tag_name
changed = True changed = True
@ -201,7 +214,10 @@ class VmwareTag(VmwareRestClient):
""" """
tag_id = self.global_tags[self.tag_name]['tag_id'] tag_id = self.global_tags[self.tag_name]['tag_id']
try:
self.tag_service.delete(tag_id=tag_id) self.tag_service.delete(tag_id=tag_id)
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
self.module.exit_json(changed=True, self.module.exit_json(changed=True,
results=dict(msg="Tag '%s' deleted." % self.tag_name, results=dict(msg="Tag '%s' deleted." % self.tag_name,
tag_id=tag_id)) tag_id=tag_id))

View file

@ -137,6 +137,7 @@ from ansible.module_utils.vmware_rest_client import VmwareRestClient
from ansible.module_utils.vmware import (PyVmomi, find_dvs_by_name, find_dvspg_by_name) from ansible.module_utils.vmware import (PyVmomi, find_dvs_by_name, find_dvspg_by_name)
try: try:
from com.vmware.vapi.std_client import DynamicID from com.vmware.vapi.std_client import DynamicID
from com.vmware.vapi.std.errors_client import Error
except ImportError: except ImportError:
pass pass
@ -239,20 +240,31 @@ class VmwareTagManager(VmwareRestClient):
if action in ('add', 'present'): if action in ('add', 'present'):
if tag_obj not in available_tag_obj: if tag_obj not in available_tag_obj:
# Tag is not already applied # Tag is not already applied
try:
self.tag_association_svc.attach(tag_id=tag_obj.id, object_id=self.dynamic_managed_object) self.tag_association_svc.attach(tag_id=tag_obj.id, object_id=self.dynamic_managed_object)
changed = True changed = True
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
elif action == 'set': elif action == 'set':
# Remove all tags first # Remove all tags first
try:
if not removed_tags_for_set: if not removed_tags_for_set:
for av_tag in available_tag_obj: for av_tag in available_tag_obj:
self.tag_association_svc.detach(tag_id=av_tag.id, object_id=self.dynamic_managed_object) self.tag_association_svc.detach(tag_id=av_tag.id, object_id=self.dynamic_managed_object)
removed_tags_for_set = True removed_tags_for_set = True
self.tag_association_svc.attach(tag_id=tag_obj.id, object_id=self.dynamic_managed_object) self.tag_association_svc.attach(tag_id=tag_obj.id, object_id=self.dynamic_managed_object)
changed = True changed = True
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
elif action in ('remove', 'absent'): elif action in ('remove', 'absent'):
if tag_obj in available_tag_obj: if tag_obj in available_tag_obj:
try:
self.tag_association_svc.detach(tag_id=tag_obj.id, object_id=self.dynamic_managed_object) self.tag_association_svc.detach(tag_id=tag_obj.id, object_id=self.dynamic_managed_object)
changed = True changed = True
except Error as error:
self.module.fail_json(msg="%s" % self.get_error_message(error))
results['tag_status']['current_tags'] = [tag.name for tag in self.get_tags_for_object(self.tag_service, results['tag_status']['current_tags'] = [tag.name for tag in self.get_tags_for_object(self.tag_service,
self.tag_association_svc, self.tag_association_svc,