diff --git a/lib/ansible/modules/cloud/vmware/vmware_host_config_manager.py b/lib/ansible/modules/cloud/vmware/vmware_host_config_manager.py index 65d29035fd..e7c7c5082e 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_host_config_manager.py +++ b/lib/ansible/modules/cloud/vmware/vmware_host_config_manager.py @@ -40,8 +40,8 @@ options: - If C(cluster_name) is not given, this parameter is required. options: description: - - A dictionary of advance configuration parameter. - - Invalid configuration parameters are ignored. + - A dictionary of advance configuration parameters. + - Invalid options will cause module to error. default: {} extends_documentation_fragment: vmware.documentation ''' @@ -81,13 +81,14 @@ RETURN = r'''# ''' try: - from pyVmomi import vim, vmodl + from pyVmomi import vim, vmodl, VmomiSupport except ImportError: pass from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.vmware import vmware_argument_spec, PyVmomi from ansible.module_utils._text import to_native +from ansible.module_utils.six import integer_types, string_types class VmwareConfigManager(PyVmomi): @@ -98,18 +99,70 @@ class VmwareConfigManager(PyVmomi): self.options = self.params.get('options', dict()) 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): changed = False for host in self.hosts: option_manager = host.configManager.advancedOption host_facts = {} 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 = [] for option_key, option_value in self.options.items(): - if option_key in host_facts and option_value != host_facts[option_key]: - change_option_list.append(vim.option.OptionValue(key=option_key, value=option_value)) - changed = True + if option_key in host_facts: + # Make sure option_type is defined some values do not have + # 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: try: option_manager.UpdateOptions(changedValue=change_option_list)