From 02e7c5a19f1e864d0c86b04a424bdea51fd5cb25 Mon Sep 17 00:00:00 2001 From: Mario Lenz Date: Mon, 2 Dec 2019 21:02:50 +0100 Subject: [PATCH] vmware_datastore_cluster: Added SDRS configuration (#65193) --- ...vmware_datastore_cluster-configure-dns.yml | 2 + .../cloud/vmware/vmware_datastore_cluster.py | 112 ++++++++++- .../vmware_datastore_cluster/tasks/main.yml | 190 +++++++++++------- 3 files changed, 223 insertions(+), 81 deletions(-) create mode 100644 changelogs/fragments/65154-vmware_datastore_cluster-configure-dns.yml diff --git a/changelogs/fragments/65154-vmware_datastore_cluster-configure-dns.yml b/changelogs/fragments/65154-vmware_datastore_cluster-configure-dns.yml new file mode 100644 index 0000000000..40e155a465 --- /dev/null +++ b/changelogs/fragments/65154-vmware_datastore_cluster-configure-dns.yml @@ -0,0 +1,2 @@ +minor_changes: +- vmware_datastore_cluster - Added basic SDRS configuration (https://github.com/ansible/ansible/issues/65154). diff --git a/lib/ansible/modules/cloud/vmware/vmware_datastore_cluster.py b/lib/ansible/modules/cloud/vmware/vmware_datastore_cluster.py index f5e65b6201..af2969af03 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_datastore_cluster.py +++ b/lib/ansible/modules/cloud/vmware/vmware_datastore_cluster.py @@ -67,17 +67,54 @@ options: required: False version_added: '2.9' type: str + enable_sdrs: + description: + - Whether or not storage DRS is enabled. + default: False + type: bool + required: False + version_added: '2.10' + automation_level: + description: + - Run SDRS automated or manually. + choices: [ automated, manual ] + default: manual + type: str + required: False + version_added: '2.10' + keep_vmdks_together: + description: + - Specifies whether or not each VM in this datastore cluster should have its virtual disks on the same datastore by default. + default: True + type: bool + required: False + version_added: '2.10' + loadbalance_interval: + description: + - Specify the interval in minutes that storage DRS runs to load balance among datastores. + default: 480 + type: int + required: False + version_added: '2.10' + enable_io_loadbalance: + description: + - Whether or not storage DRS takes into account storage I/O workload when making load balancing and initial placement recommendations. + default: False + type: bool + required: False + version_added: '2.10' extends_documentation_fragment: vmware.documentation ''' EXAMPLES = ''' -- name: Create datastore cluster +- name: Create datastore cluster and enable SDRS vmware_datastore_cluster: hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' password: '{{ vcenter_password }}' datacenter_name: '{{ datacenter_name }}' datastore_cluster_name: '{{ datastore_cluster_name }}' + enable_sdrs: True state: present delegate_to: localhost @@ -110,6 +147,11 @@ result: sample: "Datastore cluster 'DSC2' created successfully." """ +try: + from pyVmomi import vim +except ImportError: + pass + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec, wait_for_task from ansible.module_utils._text import to_native @@ -141,10 +183,55 @@ class VMwareDatastoreClusterManager(PyVmomi): """ results = dict(changed=False, result='') state = self.module.params.get('state') + enable_sdrs = self.params.get('enable_sdrs') + automation_level = self.params.get('automation_level') + keep_vmdks_together = self.params.get('keep_vmdks_together') + enable_io_loadbalance = self.params.get('enable_io_loadbalance') + loadbalance_interval = self.params.get('loadbalance_interval') if self.datastore_cluster_obj: if state == 'present': results['result'] = "Datastore cluster '%s' already available." % self.datastore_cluster_name + sdrs_spec = vim.storageDrs.ConfigSpec() + sdrs_spec.podConfigSpec = None + if enable_sdrs != self.datastore_cluster_obj.podStorageDrsEntry.storageDrsConfig.podConfig.enabled: + if not sdrs_spec.podConfigSpec: + sdrs_spec.podConfigSpec = vim.storageDrs.PodConfigSpec() + sdrs_spec.podConfigSpec.enabled = enable_sdrs + results['result'] = results['result'] + " Changed SDRS to '%s'." % enable_sdrs + if automation_level != self.datastore_cluster_obj.podStorageDrsEntry.storageDrsConfig.podConfig.defaultVmBehavior: + if not sdrs_spec.podConfigSpec: + sdrs_spec.podConfigSpec = vim.storageDrs.PodConfigSpec() + sdrs_spec.podConfigSpec.defaultVmBehavior = automation_level + results['result'] = results['result'] + " Changed automation level to '%s'." % automation_level + if keep_vmdks_together != self.datastore_cluster_obj.podStorageDrsEntry.storageDrsConfig.podConfig.defaultIntraVmAffinity: + if not sdrs_spec.podConfigSpec: + sdrs_spec.podConfigSpec = vim.storageDrs.PodConfigSpec() + sdrs_spec.podConfigSpec.defaultIntraVmAffinity = keep_vmdks_together + results['result'] = results['result'] + " Changed VMDK affinity to '%s'." % keep_vmdks_together + if enable_io_loadbalance != self.datastore_cluster_obj.podStorageDrsEntry.storageDrsConfig.podConfig.ioLoadBalanceEnabled: + if not sdrs_spec.podConfigSpec: + sdrs_spec.podConfigSpec = vim.storageDrs.PodConfigSpec() + sdrs_spec.podConfigSpec.ioLoadBalanceEnabled = enable_io_loadbalance + results['result'] = results['result'] + " Changed I/O workload balancing to '%s'." % enable_io_loadbalance + if loadbalance_interval != self.datastore_cluster_obj.podStorageDrsEntry.storageDrsConfig.podConfig.loadBalanceInterval: + if not sdrs_spec.podConfigSpec: + sdrs_spec.podConfigSpec = vim.storageDrs.PodConfigSpec() + sdrs_spec.podConfigSpec.loadBalanceInterval = loadbalance_interval + results['result'] = results['result'] + " Changed load balance interval to '%s' minutes." % loadbalance_interval + if sdrs_spec.podConfigSpec: + if not self.module.check_mode: + try: + task = self.content.storageResourceManager.ConfigureStorageDrsForPod_Task(pod=self.datastore_cluster_obj, + spec=sdrs_spec, modify=True) + changed, result = wait_for_task(task) + except Exception as generic_exc: + self.module.fail_json(msg="Failed to configure datastore cluster" + " '%s' due to %s" % (self.datastore_cluster_name, + to_native(generic_exc))) + else: + changed = True + results['changed'] = changed elif state == 'absent': # Delete datastore cluster if not self.module.check_mode: @@ -162,11 +249,25 @@ class VMwareDatastoreClusterManager(PyVmomi): # Create datastore cluster if not self.module.check_mode: try: - self.folder_obj.CreateStoragePod(name=self.datastore_cluster_name) + self.datastore_cluster_obj = self.folder_obj.CreateStoragePod(name=self.datastore_cluster_name) except Exception as generic_exc: self.module.fail_json(msg="Failed to create datastore cluster" " '%s' due to %s" % (self.datastore_cluster_name, to_native(generic_exc))) + try: + sdrs_spec = vim.storageDrs.ConfigSpec() + sdrs_spec.podConfigSpec = vim.storageDrs.PodConfigSpec() + sdrs_spec.podConfigSpec.enabled = enable_sdrs + sdrs_spec.podConfigSpec.defaultVmBehavior = automation_level + sdrs_spec.podConfigSpec.defaultIntraVmAffinity = keep_vmdks_together + sdrs_spec.podConfigSpec.ioLoadBalanceEnabled = enable_io_loadbalance + sdrs_spec.podConfigSpec.loadBalanceInterval = loadbalance_interval + task = self.content.storageResourceManager.ConfigureStorageDrsForPod_Task(pod=self.datastore_cluster_obj, spec=sdrs_spec, modify=True) + changed, result = wait_for_task(task) + except Exception as generic_exc: + self.module.fail_json(msg="Failed to configure datastore cluster" + " '%s' due to %s" % (self.datastore_cluster_name, + to_native(generic_exc))) results['changed'] = True results['result'] = "Datastore cluster '%s' created successfully." % self.datastore_cluster_name elif state == 'absent': @@ -181,7 +282,12 @@ def main(): datacenter_name=dict(type='str', required=False, aliases=['datacenter']), datastore_cluster_name=dict(type='str', required=True), state=dict(default='present', choices=['present', 'absent'], type='str'), - folder=dict(type='str', required=False) + folder=dict(type='str', required=False), + enable_sdrs=dict(type='bool', default=False, required=False), + keep_vmdks_together=dict(type='bool', default=True, required=False), + automation_level=dict(type='str', choices=['automated', 'manual'], default='manual'), + enable_io_loadbalance=dict(type='bool', default=False, required=False), + loadbalance_interval=dict(type='int', default=480, required=False) ) ) module = AnsibleModule( diff --git a/test/integration/targets/vmware_datastore_cluster/tasks/main.yml b/test/integration/targets/vmware_datastore_cluster/tasks/main.yml index 272eb2cbfe..f679172feb 100644 --- a/test/integration/targets/vmware_datastore_cluster/tasks/main.yml +++ b/test/integration/targets/vmware_datastore_cluster/tasks/main.yml @@ -2,86 +2,120 @@ # Copyright: (c) 2018, Abhijeet Kasurde # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -- import_role: - name: prepare_vmware_tests - -- name: Add a datastore cluster to datacenter (check-mode) - vmware_datastore_cluster: &add_datastore_cluster - hostname: '{{ vcenter_hostname }}' - username: '{{ vcenter_username }}' - password: '{{ vcenter_password }}' - validate_certs: no - datacenter_name: "{{ dc1 }}" - datastore_cluster_name: DSC1 - state: present - check_mode: yes - register: add_dsc_check - -- assert: - that: - - add_dsc_check.changed - -- name: Add a datastore cluster to datacenter - vmware_datastore_cluster: *add_datastore_cluster - register: add_dsc - -- assert: - that: - - add_dsc.changed - -- name: Add a datastore cluster to datacenter again - vmware_datastore_cluster: *add_datastore_cluster - register: add_dsc - -- assert: - that: - - not add_dsc.changed - -- name: Create a VM folder on given Datacenter - vcenter_folder: - hostname: '{{ vcenter_hostname }}' - username: '{{ vcenter_username }}' - password: '{{ vcenter_password }}' - datacenter: '{{ dc1 }}' - folder_name: 'my_datastore_folder' - folder_type: datastore - state: present - validate_certs: no - register: my_datastore_folder - -- name: Add a datastore cluster using folder - vmware_datastore_cluster: - hostname: '{{ vcenter_hostname }}' - username: '{{ vcenter_username }}' - password: '{{ vcenter_password }}' - validate_certs: no - folder: "{{ my_datastore_folder.result.path }}" - datastore_cluster_name: DSC2 - state: present - register: add_dsc_folder_check - -- assert: - that: - - add_dsc_folder_check.changed - -- name: Delete a datastore cluster to datacenter (check-mode) - vmware_datastore_cluster: &delete_datastore_cluster - hostname: '{{ vcenter_hostname }}' - username: '{{ vcenter_username }}' - password: '{{ vcenter_password }}' - validate_certs: no - datacenter_name: "{{ dc1 }}" - datastore_cluster_name: DSC1 - state: absent - check_mode: yes - register: delete_dsc_check - -- assert: - that: - - delete_dsc_check.changed - - when: vcsim is not defined block: + - import_role: + name: prepare_vmware_tests + + - name: Add a datastore cluster to datacenter (check-mode) + vmware_datastore_cluster: &add_datastore_cluster + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + validate_certs: no + datacenter_name: "{{ dc1 }}" + datastore_cluster_name: DSC1 + enable_sdrs: False + state: present + check_mode: yes + register: add_dsc_check + + - assert: + that: + - add_dsc_check.changed + + - name: Add a datastore cluster to datacenter + vmware_datastore_cluster: *add_datastore_cluster + register: add_dsc + + - assert: + that: + - add_dsc.changed + + - name: Add a datastore cluster to datacenter again + vmware_datastore_cluster: *add_datastore_cluster + register: add_dsc + + - assert: + that: + - not add_dsc.changed + + - name: Enable SDRS on a datastore cluster (check-mode) + vmware_datastore_cluster: &enable_sdrs + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + validate_certs: no + datacenter_name: "{{ dc1 }}" + datastore_cluster_name: DSC1 + enable_sdrs: True + state: present + check_mode: yes + register: enable_sdrs_check + + - assert: + that: + - enable_sdrs_check.changed + + - name: Enable SDRS on a datastore cluster + vmware_datastore_cluster: *enable_sdrs + register: enable_sdrs + + - assert: + that: + - enable_sdrs.changed + + - name: Enable SDRS on a datastore cluster again + vmware_datastore_cluster: *enable_sdrs + register: enable_sdrs_again + + - assert: + that: + - not enable_sdrs_again.changed + + - name: Create a datastore folder on given Datacenter + vcenter_folder: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + datacenter: '{{ dc1 }}' + folder_name: 'my_datastore_folder' + folder_type: datastore + state: present + validate_certs: no + register: my_datastore_folder + + - name: Add a datastore cluster using folder + vmware_datastore_cluster: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + validate_certs: no + folder: "{{ my_datastore_folder.result.path }}" + datastore_cluster_name: DSC2 + state: present + register: add_dsc_folder_check + + - assert: + that: + - add_dsc_folder_check.changed + + - name: Delete a datastore cluster to datacenter (check-mode) + vmware_datastore_cluster: &delete_datastore_cluster + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + validate_certs: no + datacenter_name: "{{ dc1 }}" + datastore_cluster_name: DSC1 + state: absent + check_mode: yes + register: delete_dsc_check + + - assert: + that: + - delete_dsc_check.changed + - name: Delete a datastore cluster to datacenter vmware_datastore_cluster: *delete_datastore_cluster register: delete_dsc_check