diff --git a/changelogs/fragments/54111-cs_volume-add-extract-upload.yml b/changelogs/fragments/54111-cs_volume-add-extract-upload.yml new file mode 100644 index 0000000000..b68864ead9 --- /dev/null +++ b/changelogs/fragments/54111-cs_volume-add-extract-upload.yml @@ -0,0 +1,2 @@ +minor_changes: + - cs_volume - add volumes extraction and upload features. diff --git a/lib/ansible/modules/cloud/cloudstack/cs_volume.py b/lib/ansible/modules/cloud/cloudstack/cs_volume.py index c566a1c8d9..5a3d15a1a0 100644 --- a/lib/ansible/modules/cloud/cloudstack/cs_volume.py +++ b/lib/ansible/modules/cloud/cloudstack/cs_volume.py @@ -3,21 +3,7 @@ # # (c) 2015, Jefferson Girão # (c) 2015, René Moser -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['stableinterface'], @@ -29,120 +15,173 @@ DOCUMENTATION = ''' module: cs_volume short_description: Manages volumes on Apache CloudStack based clouds. description: - - Create, destroy, attach, detach volumes. -version_added: "2.1" + - Create, destroy, attach, detach, extract or upload volumes. +version_added: '2.1' author: - - "Jefferson Girão (@jeffersongirao)" - - "René Moser (@resmo)" + - Jefferson Girão (@jeffersongirao) + - René Moser (@resmo) options: name: description: - Name of the volume. - - C(name) can only contain ASCII letters. + - I(name) can only contain ASCII letters. + type: str required: true account: description: - Account the volume is related to. + type: str custom_id: description: - Custom id to the resource. - Allowed to Root Admins only. + type: str disk_offering: description: - Name of the disk offering to be used. - - Required one of C(disk_offering), C(snapshot) if volume is not already C(state=present). + - Required one of I(disk_offering), I(snapshot) if volume is not already I(state=present). + type: str display_volume: description: - Whether to display the volume to the end user or not. - Allowed to Root Admins only. - default: true + default: yes type: bool domain: description: - Name of the domain the volume to be deployed in. + type: str max_iops: description: - Max iops + type: int min_iops: description: - Min iops + type: int project: description: - Name of the project the volume to be deployed in. + type: str size: description: - Size of disk in GB + type: int snapshot: description: - The snapshot name for the disk volume. - - Required one of C(disk_offering), C(snapshot) if volume is not already C(state=present). + - Required one of I(disk_offering), I(snapshot) if volume is not already I(state=present). + type: str force: description: - Force removal of volume even it is attached to a VM. - - Considered on C(state=absent) only. - default: false + - Considered on I(state=absent) only. + default: no type: bool shrink_ok: description: - Whether to allow to shrink the volume. - default: false + default: no type: bool vm: description: - Name of the virtual machine to attach the volume to. + type: str zone: description: - Name of the zone in which the volume should be deployed. - If not set, default zone is used. + type: str state: description: - State of the volume. + - The choices C(extracted) and C(uploaded) were added in version 2.8. + type: str default: present - choices: [ present, absent, attached, detached ] + choices: [ present, absent, attached, detached, extracted, uploaded ] poll_async: description: - Poll async jobs until job has finished. - default: true + default: yes type: bool tags: description: - - List of tags. Tags are a list of dictionaries having keys C(key) and C(value). - - "To delete all tags, set a empty list e.g. C(tags: [])." - aliases: [ 'tag' ] - version_added: "2.4" + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + aliases: [ tag ] + version_added: '2.4' + url: + description: + - URL to which the volume would be extracted on I(state=extracted) + - or the URL where to download the volume on I(state=uploaded). + - Only considered if I(state) is C(extracted) or C(uploaded). + type: str + version_added: '2.8' + mode: + description: + - Mode for the volume extraction. + - Only considered if I(state=extracted). + type: str + choices: [ http_download, ftp_upload ] + default: http_download + version_added: '2.8' + format: + description: + - The format for the volume. + - Only considered if I(state=uploaded). + type: str + choices: [ QCOW2, RAW, VHD, VHDX, OVA ] + version_added: '2.8' extends_documentation_fragment: cloudstack ''' EXAMPLES = ''' - name: create volume within project and zone with specified storage options - local_action: - module: cs_volume + cs_volume: name: web-vm-1-volume project: Integration zone: ch-zrh-ix-01 disk_offering: PerfPlus Storage size: 20 + delegate_to: localhost - name: create/attach volume to instance - local_action: - module: cs_volume + cs_volume: name: web-vm-1-volume disk_offering: PerfPlus Storage size: 20 vm: web-vm-1 state: attached + delegate_to: localhost - name: detach volume - local_action: - module: cs_volume + cs_volume: name: web-vm-1-volume state: detached + delegate_to: localhost - name: remove volume - local_action: - module: cs_volume + cs_volume: name: web-vm-1-volume state: absent + delegate_to: localhost + +# New in version 2.8 +- name: Extract DATA volume to make it downloadable + cs_volume: + state: extracted + name: web-vm-1-volume + register: data_vol_out + delegate_to: localhost + +- name: Create new volume by downloading source volume + cs_volume: + state: uploaded + name: web-vm-1-volume-2 + format: VHD + url: "{{ data_vol_out.url }}" + delegate_to: localhost ''' RETURN = ''' @@ -199,7 +238,7 @@ type: size: description: Size of disk volume. returned: success - type: str + type: int sample: 20 vm: description: Name of the vm the volume is attached to (not returned when detached) @@ -214,8 +253,14 @@ state: device_id: description: Id of the device on user vm the volume is attached to (not returned when detached) returned: success - type: str + type: int sample: 1 +url: + description: The url of the uploaded volume or the download url depending extraction mode. + returned: success when I(state=extracted) + type: str + sample: http://1.12.3.4/userdata/387e2c7c-7c42-4ecc-b4ed-84e8367a1965.vhd + version_added: '2.8' ''' from ansible.module_utils.basic import AnsibleModule @@ -237,6 +282,7 @@ class AnsibleCloudStackVolume(AnsibleCloudStack): 'deviceid': 'device_id', 'type': 'type', 'size': 'size', + 'url': 'url', } self.volume = None @@ -251,6 +297,10 @@ class AnsibleCloudStackVolume(AnsibleCloudStack): 'type': 'DATADISK', 'fetch_list': True, } + # Do not filter on DATADISK when state=extracted + if self.module.params.get('state') == 'extracted': + del args['type'] + volumes = self.query_api('listVolumes', **args) if volumes: volume_name = self.module.params.get('name') @@ -304,8 +354,6 @@ class AnsibleCloudStackVolume(AnsibleCloudStack): } if not self.module.check_mode: res = self.query_api('createVolume', **args) - if 'errortext' in res: - self.module.fail_json(msg="Failed: '%s'" % res['errortext']) poll_async = self.module.params.get('poll_async') if poll_async: volume = self.poll_job(res, 'volume') @@ -398,6 +446,56 @@ class AnsibleCloudStackVolume(AnsibleCloudStack): return volume + def extract_volume(self): + volume = self.get_volume() + if not volume: + self.module.fail_json(msg="Failed: volume not found") + + args = { + 'id': volume['id'], + 'url': self.module.params.get('url'), + 'mode': self.module.params.get('mode').upper(), + 'zoneid': self.get_zone(key='id') + } + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('extractVolume', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + self.volume = volume + + return volume + + def upload_volume(self): + volume = self.get_volume() + if not volume: + disk_offering_id = self.get_disk_offering(key='id') + + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'format': self.module.params.get('format'), + 'url': self.module.params.get('url'), + 'diskofferingid': disk_offering_id, + } + if not self.module.check_mode: + res = self.query_api('uploadVolume', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + if volume: + volume = self.ensure_tags(resource=volume, resource_type='Volume') + self.volume = volume + + return volume + def main(): argument_spec = cs_argument_spec() @@ -414,13 +512,23 @@ def main(): custom_id=dict(), force=dict(type='bool', default=False), shrink_ok=dict(type='bool', default=False), - state=dict(choices=['present', 'absent', 'attached', 'detached'], default='present'), + state=dict(default='present', choices=[ + 'present', + 'absent', + 'attached', + 'detached', + 'extracted', + 'uploaded', + ]), zone=dict(), domain=dict(), account=dict(), project=dict(), poll_async=dict(type='bool', default=True), tags=dict(type='list', aliases=['tag']), + url=dict(), + mode=dict(choices=['http_download', 'ftp_upload'], default='http_download'), + format=dict(choices=['QCOW2', 'RAW', 'VHD', 'VHDX', 'OVA']), )) module = AnsibleModule( @@ -429,6 +537,9 @@ def main(): mutually_exclusive=( ['snapshot', 'disk_offering'], ), + required_if=[ + ('state', 'uploaded', ['url', 'format']), + ], supports_check_mode=True ) @@ -442,6 +553,10 @@ def main(): volume = acs_vol.attached_volume() elif state in ['detached']: volume = acs_vol.detached_volume() + elif state == 'extracted': + volume = acs_vol.extract_volume() + elif state == 'uploaded': + volume = acs_vol.upload_volume() else: volume = acs_vol.present_volume() diff --git a/test/integration/targets/cs_volume/defaults/main.yml b/test/integration/targets/cs_volume/defaults/main.yml index 1b97cfeb41..f1074cf166 100644 --- a/test/integration/targets/cs_volume/defaults/main.yml +++ b/test/integration/targets/cs_volume/defaults/main.yml @@ -1,6 +1,8 @@ --- test_cs_instance_1: "{{ cs_resource_prefix }}-vm1" test_cs_instance_2: "{{ cs_resource_prefix }}-vm2" +test_cs_instance_3: "{{ cs_resource_prefix }}-vm3" test_cs_instance_template: "{{ cs_common_template }}" test_cs_instance_offering_1: Small Instance test_cs_disk_offering_1: Custom +test_cs_volume_to_upload: http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-xen.vhd.bz2 diff --git a/test/integration/targets/cs_volume/tasks/common.yml b/test/integration/targets/cs_volume/tasks/common.yml new file mode 100644 index 0000000000..615ed45c2e --- /dev/null +++ b/test/integration/targets/cs_volume/tasks/common.yml @@ -0,0 +1,296 @@ +--- +- name: setup + cs_volume: name={{ cs_resource_prefix }}_vol state=absent + register: vol +- name: verify setup + assert: + that: + - vol is successful + +- name: setup instance 1 + cs_instance: + name: "{{ test_cs_instance_1 }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + register: instance +- name: verify create instance + assert: + that: + - instance is successful + +- name: setup instance 2 + cs_instance: + name: "{{ test_cs_instance_2 }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + register: instance +- name: verify create instance + assert: + that: + - instance is successful + +- name: test fail if missing name + action: cs_volume + register: vol + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - vol is failed + - "vol.msg == 'missing required arguments: name'" + +- name: test create volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 20 + register: vol + check_mode: true +- name: verify results test create volume in check mode + assert: + that: + - vol is changed + +- name: test create volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 20 + register: vol +- name: verify results test create volume + assert: + that: + - vol is changed + - vol.size == 20 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test create volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 20 + register: vol +- name: verify results test create volume idempotence + assert: + that: + - vol is not changed + - vol.size == 20 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test shrink volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 10 + shrink_ok: yes + register: vol + check_mode: true +- name: verify results test create volume in check mode + assert: + that: + - vol is changed + - vol.size == 20 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test shrink volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 10 + shrink_ok: yes + register: vol +- name: verify results test create volume + assert: + that: + - vol is changed + - vol.size == 10 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test shrink volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 10 + shrink_ok: yes + register: vol +- name: verify results test create volume + assert: + that: + - vol is not changed + - vol.size == 10 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test attach volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + vm: "{{ test_cs_instance_1 }}" + state: attached + register: vol + check_mode: true +- name: verify results test attach volume in check mode + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is not defined + +- name: test attach volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + vm: "{{ test_cs_instance_1 }}" + state: attached + register: vol +- name: verify results test attach volume + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_1 }}" + - vol.attached is defined + +- name: test attach volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + vm: "{{ test_cs_instance_1 }}" + state: attached + register: vol +- name: verify results test attach volume idempotence + assert: + that: + - vol is not changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_1 }}" + - vol.attached is defined + +- name: test attach attached volume to another vm in check mdoe + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + vm: "{{ test_cs_instance_2 }}" + state: attached + register: vol + check_mode: true +- name: verify results test attach attached volume to another vm in check mode + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_1 }}" + - vol.attached is defined + +- name: test attach attached volume to another vm + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + vm: "{{ test_cs_instance_2 }}" + state: attached + register: vol +- name: verify results test attach attached volume to another vm + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_2 }}" + - vol.attached is defined + +- name: test attach attached volume to another vm idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + vm: "{{ test_cs_instance_2 }}" + state: attached + register: vol +- name: verify results test attach attached volume to another vm idempotence + assert: + that: + - vol is not changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_2 }}" + - vol.attached is defined + +- name: test detach volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + state: detached + register: vol + check_mode: true +- name: verify results test detach volume in check mdoe + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is defined + +- name: test detach volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + state: detached + register: vol +- name: verify results test detach volume + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is undefined + +- name: test detach volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + state: detached + register: vol +- name: verify results test detach volume idempotence + assert: + that: + - vol is not changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is undefined + +- name: test delete volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + state: absent + register: vol + check_mode: true +- name: verify results test create volume in check mode + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test delete volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + state: absent + register: vol +- name: verify results test create volume + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test delete volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + state: absent + register: vol +- name: verify results test delete volume idempotence + assert: + that: + - vol is not changed + +- name: cleanup instance 1 + cs_instance: + name: "{{ test_cs_instance_1 }}" + state: absent + register: instance +- name: verify create instance + assert: + that: + - instance is successful + +- name: cleanup instance 2 + cs_instance: + name: "{{ test_cs_instance_2 }}" + state: absent + register: instance +- name: verify create instance + assert: + that: + - instance is successful diff --git a/test/integration/targets/cs_volume/tasks/extract_upload.yml b/test/integration/targets/cs_volume/tasks/extract_upload.yml new file mode 100644 index 0000000000..74b6daef77 --- /dev/null +++ b/test/integration/targets/cs_volume/tasks/extract_upload.yml @@ -0,0 +1,150 @@ +--- +- name: setup + cs_volume: + zone: "{{ cs_common_zone_adv }}" + name: "{{ cs_resource_prefix }}_upload" + state: absent + register: uploaded_vol +- name: verify setup + assert: + that: + - uploaded_vol is successful + +- name: setup instance + cs_instance: + zone: "{{ cs_common_zone_adv }}" + name: "{{ test_cs_instance_3 }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + register: instance +- name: verify setup instance + assert: + that: + - instance is successful + +- name: setup stop instance + cs_instance: + zone: "{{ cs_common_zone_adv }}" + name: "{{ test_cs_instance_3 }}" + state: stopped + register: instance +- name: verify stop instance + assert: + that: + - instance is successful + - instance.state == 'Stopped' + +- name: setup get instance facts + cs_instance_facts: + name: "{{ test_cs_instance_3 }}" + register: instance +- name: verify setup get instance facts + assert: + that: + - instance is successful + +- name: test extract volume in check mode + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: extracted + name: "{{ instance.volumes[0].name }}" + check_mode: yes + register: extracted_vol +- name: verify test extract volume in check mode + assert: + that: + - extracted_vol is successful + - extracted_vol is changed + - extracted_vol.state == "Ready" + - extracted_vol.name == "{{ instance.volumes[0].name }}" + - extracted_vol.url is not defined + +- name: test extract volume + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: extracted + name: "{{ instance.volumes[0].name }}" + register: extracted_vol +- name: verify test extract volume + assert: + that: + - extracted_vol is successful + - extracted_vol is changed + - extracted_vol.state == "DOWNLOAD_URL_CREATED" + - extracted_vol.name == "{{ instance.volumes[0].name }}" + - extracted_vol.url is defined + +- name: test upload volume with missing param + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + url: "{{ test_cs_volume_to_upload }}" + ignore_errors: yes + register: uploaded_vol +- name: verify upload volume with missing param + assert: + that: + - uploaded_vol is failed + - uploaded_vol is not changed + - 'uploaded_vol.msg == "state is uploaded but all of the following are missing: format"' + +- name: test upload volume in check mode + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + format: VHD + url: "{{ test_cs_volume_to_upload }}" + check_mode: yes + register: uploaded_vol +- name: verify upload volume in check mode + assert: + that: + - uploaded_vol is successful + - uploaded_vol is changed + - uploaded_vol.name is not defined + +- name: test upload volume + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + format: VHD + url: "{{ test_cs_volume_to_upload }}" + register: uploaded_vol +- name: verify upload volume + assert: + that: + - uploaded_vol is successful + - uploaded_vol is changed + - uploaded_vol.name == "{{ cs_resource_prefix }}_upload" + - uploaded_vol.state == "Uploaded" + +- name: test upload volume idempotence + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + format: VHD + url: "{{ test_cs_volume_to_upload }}" + register: uploaded_vol +- name: verify upload volume idempotence + assert: + that: + - uploaded_vol is successful + - uploaded_vol is not changed + - uploaded_vol.name == "{{ cs_resource_prefix }}_upload" + - uploaded_vol.state == "Uploaded" + +- name: delete volume + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: absent + name: "{{ cs_resource_prefix }}_upload" + register: uploaded_vol +- name: verify delete volume + assert: + that: + - uploaded_vol is successful + - uploaded_vol is changed diff --git a/test/integration/targets/cs_volume/tasks/main.yml b/test/integration/targets/cs_volume/tasks/main.yml index 615ed45c2e..3b863beb95 100644 --- a/test/integration/targets/cs_volume/tasks/main.yml +++ b/test/integration/targets/cs_volume/tasks/main.yml @@ -1,296 +1,3 @@ --- -- name: setup - cs_volume: name={{ cs_resource_prefix }}_vol state=absent - register: vol -- name: verify setup - assert: - that: - - vol is successful - -- name: setup instance 1 - cs_instance: - name: "{{ test_cs_instance_1 }}" - template: "{{ test_cs_instance_template }}" - service_offering: "{{ test_cs_instance_offering_1 }}" - register: instance -- name: verify create instance - assert: - that: - - instance is successful - -- name: setup instance 2 - cs_instance: - name: "{{ test_cs_instance_2 }}" - template: "{{ test_cs_instance_template }}" - service_offering: "{{ test_cs_instance_offering_1 }}" - register: instance -- name: verify create instance - assert: - that: - - instance is successful - -- name: test fail if missing name - action: cs_volume - register: vol - ignore_errors: true -- name: verify results of fail if missing name - assert: - that: - - vol is failed - - "vol.msg == 'missing required arguments: name'" - -- name: test create volume in check mode - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - disk_offering: "{{ test_cs_disk_offering_1 }}" - size: 20 - register: vol - check_mode: true -- name: verify results test create volume in check mode - assert: - that: - - vol is changed - -- name: test create volume - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - disk_offering: "{{ test_cs_disk_offering_1 }}" - size: 20 - register: vol -- name: verify results test create volume - assert: - that: - - vol is changed - - vol.size == 20 * 1024 ** 3 - - vol.name == "{{ cs_resource_prefix }}_vol" - -- name: test create volume idempotence - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - disk_offering: "{{ test_cs_disk_offering_1 }}" - size: 20 - register: vol -- name: verify results test create volume idempotence - assert: - that: - - vol is not changed - - vol.size == 20 * 1024 ** 3 - - vol.name == "{{ cs_resource_prefix }}_vol" - -- name: test shrink volume in check mode - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - disk_offering: "{{ test_cs_disk_offering_1 }}" - size: 10 - shrink_ok: yes - register: vol - check_mode: true -- name: verify results test create volume in check mode - assert: - that: - - vol is changed - - vol.size == 20 * 1024 ** 3 - - vol.name == "{{ cs_resource_prefix }}_vol" - -- name: test shrink volume - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - disk_offering: "{{ test_cs_disk_offering_1 }}" - size: 10 - shrink_ok: yes - register: vol -- name: verify results test create volume - assert: - that: - - vol is changed - - vol.size == 10 * 1024 ** 3 - - vol.name == "{{ cs_resource_prefix }}_vol" - -- name: test shrink volume idempotence - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - disk_offering: "{{ test_cs_disk_offering_1 }}" - size: 10 - shrink_ok: yes - register: vol -- name: verify results test create volume - assert: - that: - - vol is not changed - - vol.size == 10 * 1024 ** 3 - - vol.name == "{{ cs_resource_prefix }}_vol" - -- name: test attach volume in check mode - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - vm: "{{ test_cs_instance_1 }}" - state: attached - register: vol - check_mode: true -- name: verify results test attach volume in check mode - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.attached is not defined - -- name: test attach volume - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - vm: "{{ test_cs_instance_1 }}" - state: attached - register: vol -- name: verify results test attach volume - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.vm == "{{ test_cs_instance_1 }}" - - vol.attached is defined - -- name: test attach volume idempotence - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - vm: "{{ test_cs_instance_1 }}" - state: attached - register: vol -- name: verify results test attach volume idempotence - assert: - that: - - vol is not changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.vm == "{{ test_cs_instance_1 }}" - - vol.attached is defined - -- name: test attach attached volume to another vm in check mdoe - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - vm: "{{ test_cs_instance_2 }}" - state: attached - register: vol - check_mode: true -- name: verify results test attach attached volume to another vm in check mode - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.vm == "{{ test_cs_instance_1 }}" - - vol.attached is defined - -- name: test attach attached volume to another vm - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - vm: "{{ test_cs_instance_2 }}" - state: attached - register: vol -- name: verify results test attach attached volume to another vm - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.vm == "{{ test_cs_instance_2 }}" - - vol.attached is defined - -- name: test attach attached volume to another vm idempotence - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - vm: "{{ test_cs_instance_2 }}" - state: attached - register: vol -- name: verify results test attach attached volume to another vm idempotence - assert: - that: - - vol is not changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.vm == "{{ test_cs_instance_2 }}" - - vol.attached is defined - -- name: test detach volume in check mode - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - state: detached - register: vol - check_mode: true -- name: verify results test detach volume in check mdoe - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.attached is defined - -- name: test detach volume - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - state: detached - register: vol -- name: verify results test detach volume - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.attached is undefined - -- name: test detach volume idempotence - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - state: detached - register: vol -- name: verify results test detach volume idempotence - assert: - that: - - vol is not changed - - vol.name == "{{ cs_resource_prefix }}_vol" - - vol.attached is undefined - -- name: test delete volume in check mode - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - state: absent - register: vol - check_mode: true -- name: verify results test create volume in check mode - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - -- name: test delete volume - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - state: absent - register: vol -- name: verify results test create volume - assert: - that: - - vol is changed - - vol.name == "{{ cs_resource_prefix }}_vol" - -- name: test delete volume idempotence - cs_volume: - name: "{{ cs_resource_prefix }}_vol" - state: absent - register: vol -- name: verify results test delete volume idempotence - assert: - that: - - vol is not changed - -- name: cleanup instance 1 - cs_instance: - name: "{{ test_cs_instance_1 }}" - state: absent - register: instance -- name: verify create instance - assert: - that: - - instance is successful - -- name: cleanup instance 2 - cs_instance: - name: "{{ test_cs_instance_2 }}" - state: absent - register: instance -- name: verify create instance - assert: - that: - - instance is successful +- include_tasks: common.yml +- include_tasks: extract_upload.yml