Fix vmware host config for all vmware OptionTypes (#41343)

* Fix vmware host config for all vmware OptionTypes

Setting some options and option types failed with invalid value errors being return from vmware, this resolves all known ways that issue can occur.

* Add logic for integer inputs as string

For example - "UserVars.ESXiShellInteractiveTimeOut": "20"

Fixes #40180
Fixes #41212
This commit is contained in:
Justin 2018-06-18 08:27:37 -06:00 committed by Abhijeet Kasurde
parent d52ea9518d
commit 6bd7d71cc1

View file

@ -40,8 +40,8 @@ options:
- If C(cluster_name) is not given, this parameter is required. - If C(cluster_name) is not given, this parameter is required.
options: options:
description: description:
- A dictionary of advance configuration parameter. - A dictionary of advance configuration parameters.
- Invalid configuration parameters are ignored. - Invalid options will cause module to error.
default: {} default: {}
extends_documentation_fragment: vmware.documentation extends_documentation_fragment: vmware.documentation
''' '''
@ -81,13 +81,14 @@ RETURN = r'''#
''' '''
try: try:
from pyVmomi import vim, vmodl from pyVmomi import vim, vmodl, VmomiSupport
except ImportError: except ImportError:
pass pass
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.vmware import vmware_argument_spec, PyVmomi from ansible.module_utils.vmware import vmware_argument_spec, PyVmomi
from ansible.module_utils._text import to_native from ansible.module_utils._text import to_native
from ansible.module_utils.six import integer_types, string_types
class VmwareConfigManager(PyVmomi): class VmwareConfigManager(PyVmomi):
@ -98,18 +99,70 @@ class VmwareConfigManager(PyVmomi):
self.options = self.params.get('options', dict()) self.options = self.params.get('options', dict())
self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_host_name) self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_host_name)
@staticmethod
def is_integer(value, type_of='int'):
try:
VmomiSupport.vmodlTypes[type_of](value)
return True
except (TypeError, ValueError):
return False
@staticmethod
def is_boolean(value):
if str(value).lower() in ['true', 'on', 'yes', 'false', 'off', 'no']:
return True
return False
@staticmethod
def is_truthy(value):
if str(value).lower() in ['true', 'on', 'yes']:
return True
return False
def set_host_configuration_facts(self): def set_host_configuration_facts(self):
changed = False changed = False
for host in self.hosts: for host in self.hosts:
option_manager = host.configManager.advancedOption option_manager = host.configManager.advancedOption
host_facts = {} host_facts = {}
for option in option_manager.QueryOptions(): for option in option_manager.QueryOptions():
host_facts[option.key] = option.value host_facts[option.key] = dict(value=option.value)
for s_option in option_manager.supportedOption:
host_facts[s_option.key].update(
option_type=s_option.optionType,
)
change_option_list = [] change_option_list = []
for option_key, option_value in self.options.items(): for option_key, option_value in self.options.items():
if option_key in host_facts and option_value != host_facts[option_key]: if option_key in host_facts:
change_option_list.append(vim.option.OptionValue(key=option_key, value=option_value)) # Make sure option_type is defined some values do not have
changed = True # it defined and appear to be read only.
if 'option_type' in host_facts[option_key]:
# We handle all supported types here so we can give meaningful errors.
option_type = host_facts[option_key]['option_type']
if self.is_boolean(option_value) and isinstance(option_type, vim.option.BoolOption):
option_value = self.is_truthy(option_value)
elif (isinstance(option_value, integer_types) or self.is_integer(option_value))\
and isinstance(option_type, vim.option.IntOption):
option_value = VmomiSupport.vmodlTypes['int'](option_value)
elif (isinstance(option_value, integer_types) or self.is_integer(option_value, 'long'))\
and isinstance(option_type, vim.option.LongOption):
option_value = VmomiSupport.vmodlTypes['long'](option_value)
elif isinstance(option_value, float) and isinstance(option_type, vim.option.FloatOption):
pass
elif isinstance(option_value, string_types) and isinstance(option_type, (vim.option.StringOption, vim.option.ChoiceOption)):
pass
else:
self.module.fail_json(msg="Provided value is of type %s."
" Option %s expects: %s" % (type(option_value), option_key, type(option_type)))
else:
self.module.fail_json(msg="Cannot change read only option %s to %s." % (option_key, option_value))
if option_value != host_facts[option_key]['value']:
change_option_list.append(vim.option.OptionValue(key=option_key, value=option_value))
changed = True
else: # Don't silently drop unknown options. This prevents typos from falling through the cracks.
self.module.fail_json(msg="Unknown option %s" % option_key)
if changed: if changed:
try: try:
option_manager.UpdateOptions(changedValue=change_option_list) option_manager.UpdateOptions(changedValue=change_option_list)