From 034df49c56f03601aaf0049c71cc927c1efa6ac1 Mon Sep 17 00:00:00 2001 From: Mario Lenz <m@riolenz.de> Date: Sat, 16 Nov 2019 06:55:06 +0100 Subject: [PATCH] VMware: New module vmware_host_dns (#64458) * Restore module vmware_dns_config * Remove domainname and change_hostname_to * Changed version_added from 2.10 to '2.10' * Add setup_attach_host: true to test case * Add 'vcsim is not defined' block to integration tests * Change 'result' to 'dns_config_result' * Bugfix: Changing some static configurations while keeping others can crash the module * Implement changing DNS config from DHCP to static on a cluster * Update documentation for vmware_host_dns * vmware_host_dns integration tests: Always revert to original DNS configuration, even if a test fails * Deprecate vmware_dns_config --- .../fragments/64458-vmware_host_dns.yaml | 4 + .../rst/porting_guides/porting_guide_2.10.rst | 4 + ...re_dns_config.py => _vmware_dns_config.py} | 6 +- .../modules/cloud/vmware/vmware_host_dns.py | 470 ++++++++++++++++++ .../targets/vmware_host_dns/aliases | 3 + .../targets/vmware_host_dns/tasks/dhcp.yml | 303 +++++++++++ .../targets/vmware_host_dns/tasks/main.yml | 28 ++ .../targets/vmware_host_dns/tasks/static.yml | 215 ++++++++ 8 files changed, 1032 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/64458-vmware_host_dns.yaml rename lib/ansible/modules/cloud/vmware/{vmware_dns_config.py => _vmware_dns_config.py} (95%) create mode 100644 lib/ansible/modules/cloud/vmware/vmware_host_dns.py create mode 100644 test/integration/targets/vmware_host_dns/aliases create mode 100644 test/integration/targets/vmware_host_dns/tasks/dhcp.yml create mode 100644 test/integration/targets/vmware_host_dns/tasks/main.yml create mode 100644 test/integration/targets/vmware_host_dns/tasks/static.yml diff --git a/changelogs/fragments/64458-vmware_host_dns.yaml b/changelogs/fragments/64458-vmware_host_dns.yaml new file mode 100644 index 00000000000..45303c2ea54 --- /dev/null +++ b/changelogs/fragments/64458-vmware_host_dns.yaml @@ -0,0 +1,4 @@ +minor_changes: +- vmware_host_dns - New module replacing vmware_dns_config with increased functionality. +deprecated_features: +- vmware_dns_config - Deprecate in favour of new module vmware_host_dns. diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.10.rst b/docs/docsite/rst/porting_guides/porting_guide_2.10.rst index 7f8362e3646..8beb665f383 100644 --- a/docs/docsite/rst/porting_guides/porting_guide_2.10.rst +++ b/docs/docsite/rst/porting_guides/porting_guide_2.10.rst @@ -68,6 +68,10 @@ The following functionality will change in Ansible 2.14. Please update update yo * The :ref:`docker_container <docker_container_module>` module has a new option, ``container_default_behavior``, whose default value will change from ``compatibility`` to ``no_defaults``. Set to an explicit value to avoid deprecation warnings. +The following modules will be removed in Ansible 2.14. Please update your playbooks accordingly. + +* ``vmware_dns_config`` use :ref:`vmware_host_dns <vmware_host_dns_module>` instead. + Noteworthy module changes ------------------------- diff --git a/lib/ansible/modules/cloud/vmware/vmware_dns_config.py b/lib/ansible/modules/cloud/vmware/_vmware_dns_config.py similarity index 95% rename from lib/ansible/modules/cloud/vmware/vmware_dns_config.py rename to lib/ansible/modules/cloud/vmware/_vmware_dns_config.py index d86d5e527d7..45fe1e9b297 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_dns_config.py +++ b/lib/ansible/modules/cloud/vmware/_vmware_dns_config.py @@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], + 'status': ['deprecated'], 'supported_by': 'community'} DOCUMENTATION = ''' @@ -25,6 +25,10 @@ notes: requirements: - "python >= 2.6" - PyVmomi +deprecated: + removed_in: '2.14' + why: Will be replaced with new module vmware_host_dns. + alternative: Use M(vmware_host_dns) instead. options: change_hostname_to: description: diff --git a/lib/ansible/modules/cloud/vmware/vmware_host_dns.py b/lib/ansible/modules/cloud/vmware/vmware_host_dns.py new file mode 100644 index 00000000000..ffbb84f09dd --- /dev/null +++ b/lib/ansible/modules/cloud/vmware/vmware_host_dns.py @@ -0,0 +1,470 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2018, Christian Kotte <christian.kotte@gmx.de> +# +# 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_host_dns +short_description: Manage DNS configuration of an ESXi host system +description: +- This module can be used to configure DNS for the default TCP/IP stack on an ESXi host system. +version_added: '2.10' +author: +- Christian Kotte (@ckotte) +- Mario Lenz (@mariolenz) +notes: +- This module is a replacement for the module C(vmware_dns_config) +- Tested on vSphere 6.7 +requirements: +- python >= 2.6 +- PyVmomi +options: + type: + description: + - Type of IP assignment. Either C(dhcp) or C(static). + - A VMkernel adapter needs to be set to DHCP if C(type) is set to C(dhcp). + type: str + choices: [ 'dhcp', 'static' ] + required: true + device: + description: + - The VMkernel network adapter to obtain DNS settings from. + - Needs to get its IP through DHCP, a static network configuration combined with a dynamic DNS configuration doesn't work. + - The parameter is only required in case of C(type) is set to C(dhcp). + type: str + host_name: + description: + - The hostname to be used for the ESXi host. + - Cannot be used when configuring a complete cluster. + type: str + domain: + description: + - The domain name to be used for the the ESXi host. + type: str + dns_servers: + description: + - A list of DNS servers to be used. + - The order of the DNS servers is important as they are used consecutively in order. + type: list + search_domains: + description: + - A list of domains to be searched through by the resolver. + type: list + verbose: + description: + - Verbose output of the DNS server configuration change. + - Explains if an DNS server was added, removed, or if the DNS server sequence was changed. + type: bool + default: false + esxi_hostname: + description: + - Name of the host system to work with. + - This parameter is required if C(cluster_name) is not specified and you connect to a vCenter. + - Cannot be used when you connect directly to an ESXi host. + type: str + cluster_name: + description: + - Name of the cluster from which all host systems will be used. + - This parameter is required if C(esxi_hostname) is not specified and you connect to a vCenter. + - Cannot be used when you connect directly to an ESXi host. + type: str +extends_documentation_fragment: vmware.documentation +''' + +EXAMPLES = r''' +- name: Configure DNS for an ESXi host + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + esxi_hostname: '{{ esxi_hostname }}' + host_name: esx01 + domain: example.local + dns_servers: + - 192.168.1.10 + - 192.168.1.11 + search_domains: + - subdomain.example.local + - example.local + delegate_to: localhost + +- name: Configure DNS for all ESXi hosts of a cluster + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: '{{ cluster_name }}' + domain: example.local + dns_servers: + - 192.168.1.10 + - 192.168.1.11 + search_domains: + - subdomain.example.local + - example.local + delegate_to: localhost + +- name: Configure DNS via DHCP for an ESXi host + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + esxi_hostname: '{{ esxi_hostname }}' + type: dhcp + device: vmk0 + delegate_to: localhost +''' + +RETURN = r''' +dns_config_result: + description: metadata about host system's DNS configuration + returned: always + type: dict + sample: { + "esx01.example.local": { + "changed": true, + "dns_servers_changed": ["192.168.1.12", "192.168.1.13"], + "dns_servers": ["192.168.1.10", "192.168.1.11"], + "dns_servers_previous": ["192.168.1.10", "192.168.1.11", "192.168.1.12", "192.168.1.13"], + "domain": "example.local", + "host_name": "esx01", + "msg": "DNS servers and Search domains changed", + "search_domains_changed": ["subdomain.example.local"], + "search_domains": ["subdomain.example.local", "example.local"], + "search_domains_previous": ["example.local"], + }, + } +''' + +try: + from pyVmomi import vim, vmodl +except ImportError: + pass + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec +from ansible.module_utils._text import to_native + + +class VmwareHostDNS(PyVmomi): + """Class to manage DNS configuration of an ESXi host system""" + + def __init__(self, module): + super(VmwareHostDNS, self).__init__(module) + self.cluster_name = self.params.get('cluster_name') + self.esxi_host_name = self.params.get('esxi_hostname') + if self.is_vcenter(): + if not self.cluster_name and not self.esxi_host_name: + self.module.fail_json( + msg="You connected to a vCenter but didn't specify the cluster_name or esxi_hostname you want to configure." + ) + else: + if self.cluster_name: + self.module.warn( + "You connected directly to an ESXi host, cluster_name will be ignored." + ) + if self.esxi_host_name: + self.module.warn( + "You connected directly to an ESXi host, esxi_host_name will be ignored." + ) + self.hosts = self.get_all_host_objs(cluster_name=self.cluster_name, esxi_host_name=self.esxi_host_name) + if not self.hosts: + self.module.fail_json(msg="Failed to find host system(s).") + self.network_type = self.params.get('type') + self.vmkernel_device = self.params.get('device') + self.host_name = self.params.get('host_name') + self.domain = self.params.get('domain') + self.dns_servers = self.params.get('dns_servers') + self.search_domains = self.params.get('search_domains') + + def ensure(self): + """Function to manage DNS configuration of an ESXi host system""" + results = dict(changed=False, dns_config_result=dict()) + verbose = self.module.params.get('verbose', False) + host_change_list = [] + for host in self.hosts: + changed = False + changed_list = [] + results['dns_config_result'][host.name] = dict(changed='', msg='') + + host_netstack_config = host.config.network.netStackInstance + for instance in host_netstack_config: + if instance.key == 'defaultTcpipStack': + netstack_spec = vim.host.NetworkConfig.NetStackSpec() + netstack_spec.operation = 'edit' + netstack_spec.netStackInstance = vim.host.NetStackInstance() + netstack_spec.netStackInstance.key = 'defaultTcpipStack' + dns_config = vim.host.DnsConfig() + results['dns_config_result'][host.name]['dns_config'] = self.network_type + if self.network_type == 'static': + if instance.dnsConfig.dhcp: + results['dns_config_result'][host.name]['domain'] = self.domain + results['dns_config_result'][host.name]['dns_servers'] = self.dns_servers + results['dns_config_result'][host.name]['search_domains'] = self.search_domains + results['dns_config_result'][host.name]['dns_config_previous'] = 'DHCP' + changed = True + changed_list.append("DNS configuration") + dns_config.dhcp = False + dns_config.virtualNicDevice = None + if self.host_name: + dns_config.hostName = self.host_name + else: + dns_config.hostName = instance.dnsConfig.hostName + dns_config.domainName = self.domain + dns_config.address = self.dns_servers + dns_config.searchDomain = self.search_domains + else: + results['dns_config_result'][host.name]['host_name'] = self.host_name + # Check host name + if self.host_name: + if instance.dnsConfig.hostName != self.host_name: + results['dns_config_result'][host.name]['host_name_previous'] = instance.dnsConfig.hostName + changed = True + changed_list.append("Host name") + dns_config.hostName = self.host_name + else: + dns_config.hostName = instance.dnsConfig.hostName + + # Check domain + results['dns_config_result'][host.name]['domain'] = self.domain + if self.domain: + if instance.dnsConfig.domainName != self.domain: + results['dns_config_result'][host.name]['domain_previous'] = instance.dnsConfig.domainName + changed = True + changed_list.append("Domain") + dns_config.domainName = self.domain + else: + dns_config.domainName = instance.dnsConfig.domainName + + # Check DNS server(s) + results['dns_config_result'][host.name]['dns_servers'] = self.dns_servers + if self.dns_servers: + if instance.dnsConfig.address != self.dns_servers: + results['dns_config_result'][host.name]['dns_servers_previous'] = instance.dnsConfig.address + results['dns_config_result'][host.name]['dns_servers_changed'] = ( + self.get_differt_entries(instance.dnsConfig.address, self.dns_servers) + ) + changed = True + # build verbose message + if verbose: + dns_servers_verbose_message = self.build_changed_message( + instance.dnsConfig.address, + self.dns_servers + ) + else: + changed_list.append("DNS servers") + dns_config.address = self.dns_servers + else: + dns_config.address = instance.dnsConfig.address + + # Check search domain config + results['dns_config_result'][host.name]['search_domains'] = self.search_domains + if self.search_domains: + if instance.dnsConfig.searchDomain != self.search_domains: + results['dns_config_result'][host.name]['search_domains_previous'] = instance.dnsConfig.searchDomain + results['dns_config_result'][host.name]['search_domains_changed'] = ( + self.get_differt_entries(instance.dnsConfig.searchDomain, self.search_domains) + ) + changed = True + changed_list.append("Search domains") + dns_config.searchDomain = self.search_domains + else: + dns_config.searchDomain = instance.dnsConfig.searchDomain + elif self.network_type == 'dhcp' and not instance.dnsConfig.dhcp: + results['dns_config_result'][host.name]['device'] = self.vmkernel_device + results['dns_config_result'][host.name]['dns_config_previous'] = 'static' + changed = True + changed_list.append("DNS configuration") + dns_config.dhcp = True + dns_config.virtualNicDevice = self.vmkernel_device + netstack_spec.netStackInstance.dnsConfig = dns_config + config = vim.host.NetworkConfig() + config.netStackSpec = [netstack_spec] + + if changed: + if self.module.check_mode: + changed_suffix = ' would be changed' + else: + changed_suffix = ' changed' + if len(changed_list) > 2: + message = ', '.join(changed_list[:-1]) + ', and ' + str(changed_list[-1]) + elif len(changed_list) == 2: + message = ' and '.join(changed_list) + elif len(changed_list) == 1: + message = changed_list[0] + if verbose and dns_servers_verbose_message: + if changed_list: + message = message + changed_suffix + '. ' + dns_servers_verbose_message + '.' + else: + message = dns_servers_verbose_message + else: + message += changed_suffix + results['dns_config_result'][host.name]['changed'] = True + host_network_system = host.configManager.networkSystem + if not self.module.check_mode: + try: + host_network_system.UpdateNetworkConfig(config, 'modify') + except vim.fault.AlreadyExists: + self.module.fail_json( + msg="Network entity specified in the configuration already exist on host '%s'" % host.name + ) + except vim.fault.NotFound: + self.module.fail_json( + msg="Network entity specified in the configuration doesn't exist on host '%s'" % host.name + ) + except vim.fault.ResourceInUse: + self.module.fail_json(msg="Resource is in use on host '%s'" % host.name) + except vmodl.fault.InvalidArgument: + self.module.fail_json( + msg="An invalid parameter is passed in for one of the networking objects for host '%s'" % + host.name + ) + except vmodl.fault.NotSupported as not_supported: + self.module.fail_json( + msg="Operation isn't supported for the instance on '%s' : %s" % + (host.name, to_native(not_supported.msg)) + ) + except vim.fault.HostConfigFault as config_fault: + self.module.fail_json( + msg="Failed to configure TCP/IP stacks for host '%s' due to : %s" % + (host.name, to_native(config_fault.msg)) + ) + else: + results['dns_config_result'][host.name]['changed'] = False + message = 'All settings are already configured' + results['dns_config_result'][host.name]['msg'] = message + + host_change_list.append(changed) + + if any(host_change_list): + results['changed'] = True + self.module.exit_json(**results) + + def build_changed_message(self, dns_servers_configured, dns_servers_new): + """Build changed message""" + check_mode = 'would be ' if self.module.check_mode else '' + # get differences + add = self.get_not_in_list_one(dns_servers_new, dns_servers_configured) + remove = self.get_not_in_list_one(dns_servers_configured, dns_servers_new) + diff_servers = list(dns_servers_configured) + if add and remove: + for server in add: + diff_servers.append(server) + for server in remove: + diff_servers.remove(server) + if dns_servers_new != diff_servers: + message = ( + "DNS server %s %sadded and %s %sremoved and the server sequence %schanged as well" % + (self.array_to_string(add), check_mode, self.array_to_string(remove), check_mode, check_mode) + ) + else: + if dns_servers_new != dns_servers_configured: + message = ( + "DNS server %s %sreplaced with %s" % + (self.array_to_string(remove), check_mode, self.array_to_string(add)) + ) + else: + message = ( + "DNS server %s %sremoved and %s %sadded" % + (self.array_to_string(remove), check_mode, self.array_to_string(add), check_mode) + ) + elif add: + for server in add: + diff_servers.append(server) + if dns_servers_new != diff_servers: + message = ( + "DNS server %s %sadded and the server sequence %schanged as well" % + (self.array_to_string(add), check_mode, check_mode) + ) + else: + message = "DNS server %s %sadded" % (self.array_to_string(add), check_mode) + elif remove: + for server in remove: + diff_servers.remove(server) + if dns_servers_new != diff_servers: + message = ( + "DNS server %s %sremoved and the server sequence %schanged as well" % + (self.array_to_string(remove), check_mode, check_mode) + ) + else: + message = "DNS server %s %sremoved" % (self.array_to_string(remove), check_mode) + else: + message = "DNS server sequence %schanged" % check_mode + + return message + + @staticmethod + def get_not_in_list_one(list1, list2): + """Return entries that ore not in list one""" + return [x for x in list1 if x not in set(list2)] + + @staticmethod + def array_to_string(array): + """Return string from array""" + if len(array) > 2: + string = ( + ', '.join("'{0}'".format(element) for element in array[:-1]) + ', and ' + + "'{0}'".format(str(array[-1])) + ) + elif len(array) == 2: + string = ' and '.join("'{0}'".format(element) for element in array) + elif len(array) == 1: + string = "'{0}'".format(array[0]) + return string + + @staticmethod + def get_differt_entries(list1, list2): + """Return different entries of two lists""" + return [a for a in list1 + list2 if (a not in list1) or (a not in list2)] + + +def main(): + """Main""" + argument_spec = vmware_argument_spec() + argument_spec.update( + type=dict(required=True, type='str', choices=['dhcp', 'static']), + device=dict(type='str'), + host_name=dict(required=False, type='str'), + domain=dict(required=False, type='str'), + dns_servers=dict(required=False, type='list'), + search_domains=dict(required=False, type='list'), + esxi_hostname=dict(required=False, type='str'), + cluster_name=dict(required=False, type='str'), + verbose=dict(type='bool', default=False, required=False) + ) + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ['type', 'dhcp', ['device']], + ], + mutually_exclusive=[ + ['cluster_name', 'host_name'], + ['cluster_name', 'esxi_host_name'], + ['static', 'device'], + ['dhcp', 'host_name'], + ['dhcp', 'domain'], + ['dhcp', 'dns_servers'], + ['dhcp', 'search_domains'], + ], + supports_check_mode=True + ) + + dns = VmwareHostDNS(module) + dns.ensure() + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/vmware_host_dns/aliases b/test/integration/targets/vmware_host_dns/aliases new file mode 100644 index 00000000000..3eede2cbf01 --- /dev/null +++ b/test/integration/targets/vmware_host_dns/aliases @@ -0,0 +1,3 @@ +cloud/vcenter +shippable/vcenter/group1 +needs/target/prepare_vmware_tests diff --git a/test/integration/targets/vmware_host_dns/tasks/dhcp.yml b/test/integration/targets/vmware_host_dns/tasks/dhcp.yml new file mode 100644 index 00000000000..627580fca9c --- /dev/null +++ b/test/integration/targets/vmware_host_dns/tasks/dhcp.yml @@ -0,0 +1,303 @@ +- name: Tests when the hosts have a DHCP DNS config + block: + # Testcase 0001: Ensure DNS config directly on the host is idempotent for DHCP + - name: Ensure DHCP config is idempotent when done directly on the host + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'dhcp' + device: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['virtual_nic_device'] }}" + register: vmware_host_dns_result_0001 + + - name: Ensure DNS config wasn't changed + assert: + that: + - vmware_host_dns_result_0001 is not changed + + # Testcase 0002: Change DNS config directly on the host from DHCP to static + - name: Change DNS config from DHCP to static directly on the host + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['host_name'] }}" + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0002 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0002 is changed + + # Testcase 0003: Ensure DNS config directly on the host is idempotent for static + - name: Ensure static DNS config is idempotent when done directly on the host + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['host_name'] }}" + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0003 + + - name: Ensure DNS config wasn't changed + assert: + that: + - vmware_host_dns_result_0003 is not changed + + # Testcase 0004: Ensure changing the hostname directly on the host works + - name: Ensure changing the hostname directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0004 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0004 is changed + + # Testcase 0005: Ensure changing the domain directly on the host works + - name: Ensure changing the domain directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: new.domain + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0005 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0005 is changed + + # Testcase 0006: Ensure changing the DNS servers directly on the host works + - name: Ensure changing the domain directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0006 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0006 is changed + + # Testcase 0007: Ensure changing the search domain directly on the host works + - name: Ensure changing the domain directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: + - subdomain.example.local + - example.local + register: vmware_host_dns_result_0007 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0007 is changed + + # Testcase 0008: Change DNS config directly on the host from static to DHCP + - name: Change DNS config from static to DHCP directly on the host + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'dhcp' + device: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['virtual_nic_device'] }}" + register: vmware_host_dns_result_0008 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0008 is changed + + # Testcase 0009: Ensure DNS config on the cluster is idempotent for DHCP + - name: Ensure DHCP config is idempotent when done on the cluster + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'dhcp' + device: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['virtual_nic_device'] }}" + register: vmware_host_dns_result_0009 + + - name: Ensure DNS config wasn't changed + assert: + that: + - vmware_host_dns_result_0009 is not changed + + # Testcase 0010: Ensure changing DNS config on the cluster from DHCP to static works + - name: Ensure changing DNS config on the cluster from DHCP to static works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0010 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0010 is changed + + # Testcase 0011: Ensure DNS config on the cluster is idempotent for static + - name: Ensure static DNS config is idempotent when done on the cluster + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0011 + + - name: Ensure DNS config wasn't changed + assert: + that: + - vmware_host_dns_result_0011 is not changed + + # Testcase 0012: Ensure changing the domain on the cluster works + - name: Ensure changing the domain on the cluster works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: new.domain + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0012 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0012 is changed + + # Testcase 0013: Ensure changing the DNS servers on the cluster works + - name: Ensure changing the DNS servers on the cluster works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0013 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0013 is changed + + # Testcase 0014: Ensure changing the search domains on the cluster works + - name: Ensure changing the search domains on the cluster works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: + - subdomain.example.local + - example.local + register: vmware_host_dns_result_0014 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0014 is changed + + # Testcase 0015: Ensure changing DNS config on the cluster from static to DHCP works + - name: Ensure changing DNS config on the cluster from static to DHCP works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'dhcp' + device: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['virtual_nic_device'] }}" + register: vmware_host_dns_result_0015 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0015 is changed + + always: + # Revert to original DNS configuration + - name: Revert to original DNS configuration + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + esxi_hostname: "{{ item }}" + validate_certs: False + type: 'dhcp' + device: "{{ dns['results'][index]['hosts_dns_info'][esxi1]['virtual_nic_device'] }}" + loop: "{{ esxi_hosts }}" + loop_control: + index_var: index diff --git a/test/integration/targets/vmware_host_dns/tasks/main.yml b/test/integration/targets/vmware_host_dns/tasks/main.yml new file mode 100644 index 00000000000..2c247c515d6 --- /dev/null +++ b/test/integration/targets/vmware_host_dns/tasks/main.yml @@ -0,0 +1,28 @@ +# Test code for the vmware_host_dns module. +# Copyright: (c) 2019, Mario Lenz <m@riolenz.de> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# This tests assume that all ESXi hosts either have a static or a dynamic DNS +# configuration. They probably will fail if on host is 'static' and the other +# is 'dhcp' configured. +- when: vcsim is not defined + block: + - import_role: + name: prepare_vmware_tests + vars: + setup_attach_host: true + + - name: Gather DNS facts about ESXi Host + vmware_host_dns_info: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + esxi_hostname: "{{ item }}" + validate_certs: False + loop: "{{ esxi_hosts }}" + register: dns + + - include_tasks: dhcp.yml + when: dns['results'][0]['hosts_dns_info'][esxi1]['dhcp'] + - include_tasks: static.yml + when: not dns['results'][0]['hosts_dns_info'][esxi1]['dhcp'] diff --git a/test/integration/targets/vmware_host_dns/tasks/static.yml b/test/integration/targets/vmware_host_dns/tasks/static.yml new file mode 100644 index 00000000000..610dfe26f26 --- /dev/null +++ b/test/integration/targets/vmware_host_dns/tasks/static.yml @@ -0,0 +1,215 @@ +- name: Tests when the hosts have a static DNS config + block: + # Testcase 0001: Ensure DNS config directly on the host is idempotent for static + - name: Ensure static DNS config is idempotent when done directly on the host + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['host_name'] }}" + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0001 + + - name: Ensure DNS config wasn't changed + assert: + that: + - vmware_host_dns_result_0001 is not changed + + # Testcase 0002: Ensure changing the hostname directly on the host works + - name: Ensure changing the hostname directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0002 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0002 is changed + + # Testcase 0003: Ensure changing the domain directly on the host works + - name: Ensure changing the domain directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: new.domain + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0003 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0003 is changed + + # Testcase 0004: Ensure changing the DNS servers directly on the host works + - name: Ensure changing the domain directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0004 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0004 is changed + + # Testcase 0005: Ensure changing the search domain directly on the host works + - name: Ensure changing the domain directly on the host works + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: newname + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: + - subdomain.example.local + - example.local + register: vmware_host_dns_result_0005 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0005 is changed + + # Revert to original DNS configuration + - name: Revert to original DNS configuration + vmware_host_dns: + hostname: '{{ esxi1 }}' + username: '{{ esxi_user }}' + password: '{{ esxi_password }}' + validate_certs: False + type: 'static' + host_name: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['host_name'] }}" + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + + # Testcase 0006: Ensure DNS config on the cluster is idempotent for static + - name: Ensure static DNS config is idempotent when done on the cluster + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['domain_name'] }}" + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0006 + + - name: Ensure DNS config wasn't changed + assert: + that: + - vmware_host_dns_result_0006 is not changed + + # Testcase 0007: Ensure changing the domain on the cluster works + - name: Ensure changing the domain on the cluster works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: new.domain + dns_servers: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['ip_address'] }}" + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0007 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0007 is changed + + # Testcase 0008: Ensure changing the DNS servers on the cluster works + - name: Ensure changing the DNS servers on the cluster works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: "{{ dns['results'][0]['hosts_dns_info'][esxi1]['search_domain'] }}" + register: vmware_host_dns_result_0008 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0008 is changed + + # Testcase 0009: Ensure changing the search domains on the cluster works + - name: Ensure changing the search domains on the cluster works + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + cluster_name: "{{ ccr1 }}" + validate_certs: False + type: 'static' + domain: new.domain + dns_servers: + - 1.2.3.4 + - 5.6.7.8 + search_domains: + - subdomain.example.local + - example.local + register: vmware_host_dns_result_0009 + + - name: Ensure DNS config was changed + assert: + that: + - vmware_host_dns_result_0009 is changed + + always: + # Revert to original DNS configuration + - name: Revert to original DNS configuration + vmware_host_dns: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + esxi_hostname: "{{ item }}" + validate_certs: False + type: 'static' + host_name: "{{ dns['results'][index]['hosts_dns_info'][item]['host_name'] }}" + domain: "{{ dns['results'][index]['hosts_dns_info'][item]['domain_name'] }}" + dns_servers: "{{ dns['results'][index]['hosts_dns_info'][item]['ip_address'] }}" + search_domains: "{{ dns['results'][index]['hosts_dns_info'][item]['search_domain'] }}" + loop: "{{ esxi_hosts }}" + loop_control: + index_var: index