summaryrefslogtreecommitdiff
path: root/lib/ansible/modules/cloud/ovirt/ovirt_disk.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/modules/cloud/ovirt/ovirt_disk.py')
-rw-r--r--lib/ansible/modules/cloud/ovirt/ovirt_disk.py838
1 files changed, 0 insertions, 838 deletions
diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_disk.py b/lib/ansible/modules/cloud/ovirt/ovirt_disk.py
deleted file mode 100644
index 6e6b0893be..0000000000
--- a/lib/ansible/modules/cloud/ovirt/ovirt_disk.py
+++ /dev/null
@@ -1,838 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2016 Red Hat, Inc.
-# 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': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: ovirt_disk
-short_description: "Module to manage Virtual Machine and floating disks in oVirt/RHV"
-version_added: "2.2"
-author: "Ondra Machacek (@machacekondra)"
-description:
- - "Module to manage Virtual Machine and floating disks in oVirt/RHV."
-options:
- id:
- description:
- - "ID of the disk to manage. Either C(id) or C(name) is required."
- name:
- description:
- - "Name of the disk to manage. Either C(id) or C(name)/C(alias) is required."
- aliases: ['alias']
- description:
- description:
- - "Description of the disk image to manage."
- version_added: "2.5"
- vm_name:
- description:
- - "Name of the Virtual Machine to manage. Either C(vm_id) or C(vm_name) is required if C(state) is I(attached) or I(detached)."
- vm_id:
- description:
- - "ID of the Virtual Machine to manage. Either C(vm_id) or C(vm_name) is required if C(state) is I(attached) or I(detached)."
- state:
- description:
- - "Should the Virtual Machine disk be present/absent/attached/detached/exported/imported."
- choices: ['present', 'absent', 'attached', 'detached', 'exported', 'imported']
- default: 'present'
- download_image_path:
- description:
- - "Path on a file system where disk should be downloaded."
- - "Note that you must have an valid oVirt/RHV engine CA in your system trust store
- or you must provide it in C(ca_file) parameter."
- - "Note that the disk is not downloaded when the file already exists,
- but you can forcibly download the disk when using C(force) I (true)."
- version_added: "2.3"
- upload_image_path:
- description:
- - "Path to disk image, which should be uploaded."
- - "Note that currently we support only compatibility version 0.10 of the qcow disk."
- - "Note that you must have an valid oVirt/RHV engine CA in your system trust store
- or you must provide it in C(ca_file) parameter."
- - "Note that there is no reliable way to achieve idempotency, so
- if you want to upload the disk even if the disk with C(id) or C(name) exists,
- then please use C(force) I(true). If you will use C(force) I(false), which
- is default, then the disk image won't be uploaded."
- version_added: "2.3"
- size:
- description:
- - "Size of the disk. Size should be specified using IEC standard units.
- For example 10GiB, 1024MiB, etc."
- - "Size can be only increased, not decreased."
- interface:
- description:
- - "Driver of the storage interface."
- - "It's required parameter when creating the new disk."
- choices: ['virtio', 'ide', 'virtio_scsi']
- format:
- description:
- - Specify format of the disk.
- - Note that this option isn't idempotent as it's not currently possible to change format of the disk via API.
- choices: ['raw', 'cow']
- content_type:
- description:
- - Specify if the disk is a data disk or ISO image or a one of a the Hosted Engine disk types
- - The Hosted Engine disk content types are available with Engine 4.3+ and Ansible 2.8
- choices: ['data', 'iso', 'hosted_engine', 'hosted_engine_sanlock', 'hosted_engine_metadata', 'hosted_engine_configuration']
- default: 'data'
- version_added: "2.8"
- sparse:
- required: False
- type: bool
- version_added: "2.5"
- description:
- - "I(True) if the disk should be sparse (also known as I(thin provision)).
- If the parameter is omitted, cow disks will be created as sparse and raw disks as I(preallocated)"
- - Note that this option isn't idempotent as it's not currently possible to change sparseness of the disk via API.
- storage_domain:
- description:
- - "Storage domain name where disk should be created."
- storage_domains:
- description:
- - "Storage domain names where disk should be copied."
- - "C(**IMPORTANT**)"
- - "There is no reliable way to achieve idempotency, so every time
- you specify this parameter the disks are copied, so please handle
- your playbook accordingly to not copy the disks all the time. This
- is valid only for VM and floating disks, template disks works
- as expected."
- version_added: "2.3"
- force:
- description:
- - "Please take a look at C(image_path) documentation to see the correct
- usage of this parameter."
- version_added: "2.3"
- type: bool
- profile:
- description:
- - "Disk profile name to be attached to disk. By default profile is chosen by oVirt/RHV engine."
- quota_id:
- description:
- - "Disk quota ID to be used for disk. By default quota is chosen by oVirt/RHV engine."
- version_added: "2.5"
- bootable:
- description:
- - "I(True) if the disk should be bootable. By default when disk is created it isn't bootable."
- type: bool
- default: 'no'
- shareable:
- description:
- - "I(True) if the disk should be shareable. By default when disk is created it isn't shareable."
- type: bool
- logical_unit:
- description:
- - "Dictionary which describes LUN to be directly attached to VM:"
- suboptions:
- address:
- description:
- - Address of the storage server. Used by iSCSI.
- port:
- description:
- - Port of the storage server. Used by iSCSI.
- target:
- description:
- - iSCSI target.
- lun_id:
- description:
- - LUN id.
- username:
- description:
- - CHAP Username to be used to access storage server. Used by iSCSI.
- password:
- description:
- - CHAP Password of the user to be used to access storage server. Used by iSCSI.
- storage_type:
- description:
- - Storage type either I(fcp) or I(iscsi).
- sparsify:
- description:
- - "I(True) if the disk should be sparsified."
- - "Sparsification frees space in the disk image that is not used by
- its filesystem. As a result, the image will occupy less space on
- the storage."
- - "Note that this parameter isn't idempotent, as it's not possible
- to check if the disk should be or should not be sparsified."
- version_added: "2.4"
- type: bool
- openstack_volume_type:
- description:
- - "Name of the openstack volume type. This is valid when working
- with cinder."
- version_added: "2.4"
- image_provider:
- description:
- - "When C(state) is I(exported) disk is exported to given Glance image provider."
- - "When C(state) is I(imported) disk is imported from given Glance image provider."
- - "C(**IMPORTANT**)"
- - "There is no reliable way to achieve idempotency, so every time
- you specify this parameter the disk is exported, so please handle
- your playbook accordingly to not export the disk all the time.
- This option is valid only for template disks."
- version_added: "2.4"
- host:
- description:
- - "When the hypervisor name is specified the newly created disk or
- an existing disk will refresh its information about the
- underlying storage( Disk size, Serial, Product ID, Vendor ID ...)
- The specified host will be used for gathering the storage
- related information. This option is only valid for passthrough
- disks. This option requires at least the logical_unit.id to be
- specified"
- version_added: "2.8"
- wipe_after_delete:
- description:
- - "If the disk's Wipe After Delete is enabled, then the disk is first wiped."
- type: bool
- activate:
- description:
- - I(True) if the disk should be activated.
- - When creating disk of virtual machine it is set to I(True).
- version_added: "2.8"
- type: bool
-extends_documentation_fragment: ovirt
-'''
-
-
-EXAMPLES = '''
-# Examples don't contain auth parameter for simplicity,
-# look at ovirt_auth module to see how to reuse authentication:
-
-# Create and attach new disk to VM
-- ovirt_disk:
- name: myvm_disk
- vm_name: rhel7
- size: 10GiB
- format: cow
- interface: virtio
- storage_domain: data
-
-# Attach logical unit to VM rhel7
-- ovirt_disk:
- vm_name: rhel7
- logical_unit:
- target: iqn.2016-08-09.brq.str-01:omachace
- id: 1IET_000d0001
- address: 10.34.63.204
- interface: virtio
-
-# Detach disk from VM
-- ovirt_disk:
- state: detached
- name: myvm_disk
- vm_name: rhel7
- size: 10GiB
- format: cow
- interface: virtio
-
-# Change Disk Name
-- ovirt_disk:
- id: 00000000-0000-0000-0000-000000000000
- storage_domain: data
- name: "new_disk_name"
- vm_name: rhel7
-
-# Upload local image to disk and attach it to vm:
-# Since Ansible 2.3
-- ovirt_disk:
- name: mydisk
- vm_name: myvm
- interface: virtio
- size: 10GiB
- format: cow
- image_path: /path/to/mydisk.qcow2
- storage_domain: data
-
-# Download disk to local file system:
-# Since Ansible 2.3
-- ovirt_disk:
- id: 7de90f31-222c-436c-a1ca-7e655bd5b60c
- download_image_path: /home/user/mydisk.qcow2
-
-# Export disk as image to Glance domain
-# Since Ansible 2.4
-- ovirt_disk:
- id: 7de90f31-222c-436c-a1ca-7e655bd5b60c
- image_provider: myglance
- state: exported
-
-# Defining a specific quota while creating a disk image:
-# Since Ansible 2.5
-- ovirt_quotas_facts:
- data_center: Default
- name: myquota
-- ovirt_disk:
- name: mydisk
- size: 10GiB
- storage_domain: data
- description: somedescriptionhere
- quota_id: "{{ ovirt_quotas[0]['id'] }}"
-
-# Upload an ISO image
-# Since Ansible 2.8
-- ovirt_disk:
- name: myiso
- upload_image_path: /path/to/iso/image
- storage_domain: data
- size: 4 GiB
- wait: true
- bootable: true
- format: raw
- content_type: iso
-
-# Add fiber chanel disk
-- name: Create disk
- ovirt_disk:
- name: fcp_disk
- host: my_host
- logical_unit:
- id: 3600a09803830447a4f244c4657597777
- storage_type: fcp
-'''
-
-
-RETURN = '''
-id:
- description: "ID of the managed disk"
- returned: "On success if disk is found."
- type: str
- sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
-disk:
- description: "Dictionary of all the disk attributes. Disk attributes can be found on your oVirt/RHV instance
- at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/disk."
- returned: "On success if disk is found and C(vm_id) or C(vm_name) wasn't passed."
- type: dict
-
-disk_attachment:
- description: "Dictionary of all the disk attachment attributes. Disk attachment attributes can be found
- on your oVirt/RHV instance at following url:
- http://ovirt.github.io/ovirt-engine-api-model/master/#types/disk_attachment."
- returned: "On success if disk is found and C(vm_id) or C(vm_name) was passed and VM was found."
- type: dict
-'''
-
-import os
-import time
-import traceback
-import ssl
-
-from ansible.module_utils.six.moves.http_client import HTTPSConnection, IncompleteRead
-from ansible.module_utils.six.moves.urllib.parse import urlparse
-try:
- import ovirtsdk4.types as otypes
-except ImportError:
- pass
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.ovirt import (
- BaseModule,
- check_sdk,
- check_params,
- create_connection,
- convert_to_bytes,
- equal,
- follow_link,
- get_id_by_name,
- ovirt_full_argument_spec,
- get_dict_of_struct,
- search_by_name,
- wait,
-)
-
-
-def _search_by_lun(disks_service, lun_id):
- """
- Find disk by LUN ID.
- """
- res = [
- disk for disk in disks_service.list(search='disk_type=lun') if (
- disk.lun_storage.id == lun_id
- )
- ]
- return res[0] if res else None
-
-
-def transfer(connection, module, direction, transfer_func):
- transfers_service = connection.system_service().image_transfers_service()
- transfer = transfers_service.add(
- otypes.ImageTransfer(
- image=otypes.Image(
- id=module.params['id'],
- ),
- direction=direction,
- )
- )
- transfer_service = transfers_service.image_transfer_service(transfer.id)
-
- try:
- # After adding a new transfer for the disk, the transfer's status will be INITIALIZING.
- # Wait until the init phase is over. The actual transfer can start when its status is "Transferring".
- while transfer.phase == otypes.ImageTransferPhase.INITIALIZING:
- time.sleep(module.params['poll_interval'])
- transfer = transfer_service.get()
-
- proxy_url = urlparse(transfer.proxy_url)
- context = ssl.create_default_context()
- auth = module.params['auth']
- if auth.get('insecure'):
- context.check_hostname = False
- context.verify_mode = ssl.CERT_NONE
- elif auth.get('ca_file'):
- context.load_verify_locations(cafile=auth.get('ca_file'))
-
- proxy_connection = HTTPSConnection(
- proxy_url.hostname,
- proxy_url.port,
- context=context,
- )
-
- transfer_func(
- transfer_service,
- proxy_connection,
- proxy_url,
- transfer.signed_ticket
- )
- return True
- finally:
- transfer_service.finalize()
- while transfer.phase in [
- otypes.ImageTransferPhase.TRANSFERRING,
- otypes.ImageTransferPhase.FINALIZING_SUCCESS,
- ]:
- time.sleep(module.params['poll_interval'])
- transfer = transfer_service.get()
- if transfer.phase in [
- otypes.ImageTransferPhase.UNKNOWN,
- otypes.ImageTransferPhase.FINISHED_FAILURE,
- otypes.ImageTransferPhase.FINALIZING_FAILURE,
- otypes.ImageTransferPhase.CANCELLED,
- ]:
- raise Exception(
- "Error occurred while uploading image. The transfer is in %s" % transfer.phase
- )
- if not module.params.get('logical_unit'):
- disks_service = connection.system_service().disks_service()
- wait(
- service=disks_service.service(module.params['id']),
- condition=lambda d: d.status == otypes.DiskStatus.OK,
- wait=module.params['wait'],
- timeout=module.params['timeout'],
- )
-
-
-def download_disk_image(connection, module):
- def _transfer(transfer_service, proxy_connection, proxy_url, transfer_ticket):
- BUF_SIZE = 128 * 1024
- transfer_headers = {
- 'Authorization': transfer_ticket,
- }
- proxy_connection.request(
- 'GET',
- proxy_url.path,
- headers=transfer_headers,
- )
- r = proxy_connection.getresponse()
- path = module.params["download_image_path"]
- image_size = int(r.getheader('Content-Length'))
- with open(path, "wb") as mydisk:
- pos = 0
- while pos < image_size:
- to_read = min(image_size - pos, BUF_SIZE)
- chunk = r.read(to_read)
- if not chunk:
- raise RuntimeError("Socket disconnected")
- mydisk.write(chunk)
- pos += len(chunk)
-
- return transfer(
- connection,
- module,
- otypes.ImageTransferDirection.DOWNLOAD,
- transfer_func=_transfer,
- )
-
-
-def upload_disk_image(connection, module):
- def _transfer(transfer_service, proxy_connection, proxy_url, transfer_ticket):
- BUF_SIZE = 128 * 1024
- path = module.params['upload_image_path']
-
- image_size = os.path.getsize(path)
- proxy_connection.putrequest("PUT", proxy_url.path)
- proxy_connection.putheader('Content-Length', "%d" % (image_size,))
- proxy_connection.endheaders()
- with open(path, "rb") as disk:
- pos = 0
- while pos < image_size:
- to_read = min(image_size - pos, BUF_SIZE)
- chunk = disk.read(to_read)
- if not chunk:
- transfer_service.pause()
- raise RuntimeError("Unexpected end of file at pos=%d" % pos)
- proxy_connection.send(chunk)
- pos += len(chunk)
-
- return transfer(
- connection,
- module,
- otypes.ImageTransferDirection.UPLOAD,
- transfer_func=_transfer,
- )
-
-
-class DisksModule(BaseModule):
-
- def build_entity(self):
- hosts_service = self._connection.system_service().hosts_service()
- logical_unit = self._module.params.get('logical_unit')
- disk = otypes.Disk(
- id=self._module.params.get('id'),
- name=self._module.params.get('name'),
- description=self._module.params.get('description'),
- format=otypes.DiskFormat(
- self._module.params.get('format')
- ) if self._module.params.get('format') else None,
- content_type=otypes.DiskContentType(
- self._module.params.get('content_type')
- ) if self._module.params.get('content_type') else None,
- sparse=self._module.params.get(
- 'sparse'
- ) if self._module.params.get(
- 'sparse'
- ) is not None else self._module.params.get('format') != 'raw',
- openstack_volume_type=otypes.OpenStackVolumeType(
- name=self.param('openstack_volume_type')
- ) if self.param('openstack_volume_type') else None,
- provisioned_size=convert_to_bytes(
- self._module.params.get('size')
- ),
- storage_domains=[
- otypes.StorageDomain(
- name=self._module.params.get('storage_domain'),
- ),
- ],
- quota=otypes.Quota(id=self._module.params.get('quota_id')) if self.param('quota_id') else None,
- shareable=self._module.params.get('shareable'),
- wipe_after_delete=self.param('wipe_after_delete'),
- lun_storage=otypes.HostStorage(
- host=otypes.Host(
- id=get_id_by_name(hosts_service, self._module.params.get('host'))
- ) if self.param('host') else None,
- type=otypes.StorageType(
- logical_unit.get('storage_type', 'iscsi')
- ),
- logical_units=[
- otypes.LogicalUnit(
- address=logical_unit.get('address'),
- port=logical_unit.get('port', 3260),
- target=logical_unit.get('target'),
- id=logical_unit.get('id'),
- username=logical_unit.get('username'),
- password=logical_unit.get('password'),
- )
- ],
- ) if logical_unit else None,
- )
- if hasattr(disk, 'initial_size') and self._module.params['upload_image_path']:
- disk.initial_size = convert_to_bytes(
- self._module.params.get('size')
- )
-
- return disk
-
- def update_storage_domains(self, disk_id):
- changed = False
- disk_service = self._service.service(disk_id)
- disk = disk_service.get()
- sds_service = self._connection.system_service().storage_domains_service()
-
- # We don't support move&copy for non file based storages:
- if disk.storage_type != otypes.DiskStorageType.IMAGE:
- return changed
-
- # Initiate move:
- if self._module.params['storage_domain']:
- new_disk_storage_id = get_id_by_name(sds_service, self._module.params['storage_domain'])
- changed = self.action(
- action='move',
- entity=disk,
- action_condition=lambda d: new_disk_storage_id != d.storage_domains[0].id,
- wait_condition=lambda d: d.status == otypes.DiskStatus.OK,
- storage_domain=otypes.StorageDomain(
- id=new_disk_storage_id,
- ),
- post_action=lambda _: time.sleep(self._module.params['poll_interval']),
- )['changed']
-
- if self._module.params['storage_domains']:
- for sd in self._module.params['storage_domains']:
- new_disk_storage = search_by_name(sds_service, sd)
- changed = changed or self.action(
- action='copy',
- entity=disk,
- action_condition=(
- lambda disk: new_disk_storage.id not in [sd.id for sd in disk.storage_domains]
- ),
- wait_condition=lambda disk: disk.status == otypes.DiskStatus.OK,
- storage_domain=otypes.StorageDomain(
- id=new_disk_storage.id,
- ),
- )['changed']
-
- return changed
-
- def _update_check(self, entity):
- return (
- equal(self._module.params.get('name'), entity.name) and
- equal(self._module.params.get('description'), entity.description) and
- equal(self.param('quota_id'), getattr(entity.quota, 'id', None)) and
- equal(convert_to_bytes(self._module.params.get('size')), entity.provisioned_size) and
- equal(self._module.params.get('shareable'), entity.shareable) and
- equal(self.param('wipe_after_delete'), entity.wipe_after_delete)
- )
-
-
-class DiskAttachmentsModule(DisksModule):
-
- def build_entity(self):
- return otypes.DiskAttachment(
- disk=super(DiskAttachmentsModule, self).build_entity(),
- interface=otypes.DiskInterface(
- self._module.params.get('interface')
- ) if self._module.params.get('interface') else None,
- bootable=self._module.params.get('bootable'),
- active=self.param('activate'),
- )
-
- def update_check(self, entity):
- return (
- super(DiskAttachmentsModule, self)._update_check(follow_link(self._connection, entity.disk)) and
- equal(self._module.params.get('interface'), str(entity.interface)) and
- equal(self._module.params.get('bootable'), entity.bootable) and
- equal(self.param('activate'), entity.active)
- )
-
-
-def searchable_attributes(module):
- """
- Return all searchable disk attributes passed to module.
- """
- attributes = {
- 'name': module.params.get('name'),
- 'Storage.name': module.params.get('storage_domain'),
- 'vm_names': module.params.get('vm_name'),
- }
- return dict((k, v) for k, v in attributes.items() if v is not None)
-
-
-def get_vm_service(connection, module):
- if module.params.get('vm_id') is not None or module.params.get('vm_name') is not None and module.params['state'] != 'absent':
- vms_service = connection.system_service().vms_service()
-
- # If `vm_id` isn't specified, find VM by name:
- vm_id = module.params['vm_id']
- if vm_id is None:
- vm_id = get_id_by_name(vms_service, module.params['vm_name'])
-
- if vm_id is None:
- module.fail_json(
- msg="VM don't exists, please create it first."
- )
-
- return vms_service.vm_service(vm_id)
-
-
-def main():
- argument_spec = ovirt_full_argument_spec(
- state=dict(
- choices=['present', 'absent', 'attached', 'detached', 'exported', 'imported'],
- default='present'
- ),
- id=dict(default=None),
- name=dict(default=None, aliases=['alias']),
- description=dict(default=None),
- vm_name=dict(default=None),
- vm_id=dict(default=None),
- size=dict(default=None),
- interface=dict(default=None,),
- storage_domain=dict(default=None),
- storage_domains=dict(default=None, type='list'),
- profile=dict(default=None),
- quota_id=dict(default=None),
- format=dict(default='cow', choices=['raw', 'cow']),
- content_type=dict(
- default='data',
- choices=['data', 'iso', 'hosted_engine', 'hosted_engine_sanlock', 'hosted_engine_metadata', 'hosted_engine_configuration']
- ),
- sparse=dict(default=None, type='bool'),
- bootable=dict(default=None, type='bool'),
- shareable=dict(default=None, type='bool'),
- logical_unit=dict(default=None, type='dict'),
- download_image_path=dict(default=None),
- upload_image_path=dict(default=None, aliases=['image_path']),
- force=dict(default=False, type='bool'),
- sparsify=dict(default=None, type='bool'),
- openstack_volume_type=dict(default=None),
- image_provider=dict(default=None),
- host=dict(default=None),
- wipe_after_delete=dict(type='bool', default=None),
- activate=dict(default=None, type='bool'),
- )
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True,
- )
-
- lun = module.params.get('logical_unit')
- host = module.params['host']
- # Fail when host is specified with the LUN id. Lun id is needed to identify
- # an existing disk if already available inthe environment.
- if (host and lun is None) or (host and lun.get("id") is None):
- module.fail_json(
- msg="Can not use parameter host ({0!s}) without "
- "specifying the logical_unit id".format(host)
- )
-
- check_sdk(module)
- check_params(module)
-
- try:
- disk = None
- state = module.params['state']
- auth = module.params.get('auth')
- connection = create_connection(auth)
- disks_service = connection.system_service().disks_service()
- disks_module = DisksModule(
- connection=connection,
- module=module,
- service=disks_service,
- )
-
- force_create = False
- vm_service = get_vm_service(connection, module)
- if lun:
- disk = _search_by_lun(disks_service, lun.get('id'))
- else:
- disk = disks_module.search_entity(search_params=searchable_attributes(module))
- if vm_service and disk:
- # If the VM don't exist in VMs disks, but still it's found it means it was found
- # for template with same name as VM, so we should force create the VM disk.
- force_create = disk.id not in [a.disk.id for a in vm_service.disk_attachments_service().list() if a.disk]
-
- ret = None
- # First take care of creating the VM, if needed:
- if state in ('present', 'detached', 'attached'):
- # Always activate disk when its being created
- if vm_service is not None and disk is None:
- module.params['activate'] = True
- ret = disks_module.create(
- entity=disk if not force_create else None,
- result_state=otypes.DiskStatus.OK if lun is None else None,
- fail_condition=lambda d: d.status == otypes.DiskStatus.ILLEGAL if lun is None else False,
- force_create=force_create,
- )
- is_new_disk = ret['changed']
- ret['changed'] = ret['changed'] or disks_module.update_storage_domains(ret['id'])
- # We need to pass ID to the module, so in case we want detach/attach disk
- # we have this ID specified to attach/detach method:
- module.params['id'] = ret['id']
-
- # Upload disk image in case it's new disk or force parameter is passed:
- if module.params['upload_image_path'] and (is_new_disk or module.params['force']):
- uploaded = upload_disk_image(connection, module)
- ret['changed'] = ret['changed'] or uploaded
- # Download disk image in case it's file don't exist or force parameter is passed:
- if (
- module.params['download_image_path'] and (not os.path.isfile(module.params['download_image_path']) or module.params['force'])
- ):
- downloaded = download_disk_image(connection, module)
- ret['changed'] = ret['changed'] or downloaded
-
- # Disk sparsify, only if disk is of image type:
- if not module.check_mode:
- disk = disks_service.disk_service(module.params['id']).get()
- if disk.storage_type == otypes.DiskStorageType.IMAGE:
- ret = disks_module.action(
- action='sparsify',
- action_condition=lambda d: module.params['sparsify'],
- wait_condition=lambda d: d.status == otypes.DiskStatus.OK,
- )
-
- # Export disk as image to glance domain
- elif state == 'exported':
- disk = disks_module.search_entity()
- if disk is None:
- module.fail_json(
- msg="Can not export given disk '%s', it doesn't exist" %
- module.params.get('name') or module.params.get('id')
- )
- if disk.storage_type == otypes.DiskStorageType.IMAGE:
- ret = disks_module.action(
- action='export',
- action_condition=lambda d: module.params['image_provider'],
- wait_condition=lambda d: d.status == otypes.DiskStatus.OK,
- storage_domain=otypes.StorageDomain(name=module.params['image_provider']),
- )
- elif state == 'imported':
- glance_service = connection.system_service().openstack_image_providers_service()
- image_provider = search_by_name(glance_service, module.params['image_provider'])
- images_service = glance_service.service(image_provider.id).images_service()
- entity_id = get_id_by_name(images_service, module.params['name'])
- images_service.service(entity_id).import_(
- storage_domain=otypes.StorageDomain(
- name=module.params['storage_domain']
- ) if module.params['storage_domain'] else None,
- disk=otypes.Disk(
- name=module.params['name']
- ),
- import_as_template=False,
- )
- # Wait for disk to appear in system:
- disk = disks_module.wait_for_import(
- condition=lambda t: t.status == otypes.DiskStatus.OK
- )
- ret = disks_module.create(result_state=otypes.DiskStatus.OK)
- elif state == 'absent':
- ret = disks_module.remove()
-
- # If VM was passed attach/detach disks to/from the VM:
- if vm_service:
- disk_attachments_service = vm_service.disk_attachments_service()
- disk_attachments_module = DiskAttachmentsModule(
- connection=connection,
- module=module,
- service=disk_attachments_service,
- changed=ret['changed'] if ret else False,
- )
-
- if state == 'present' or state == 'attached':
- ret = disk_attachments_module.create()
- if lun is None:
- wait(
- service=disk_attachments_service.service(ret['id']),
- condition=lambda d: follow_link(connection, d.disk).status == otypes.DiskStatus.OK,
- wait=module.params['wait'],
- timeout=module.params['timeout'],
- )
- elif state == 'detached':
- ret = disk_attachments_module.remove()
-
- # When the host parameter is specified and the disk is not being
- # removed, refresh the information about the LUN.
- if state != 'absent' and host:
- hosts_service = connection.system_service().hosts_service()
- host_id = get_id_by_name(hosts_service, host)
- disks_service.disk_service(disk.id).refresh_lun(otypes.Host(id=host_id))
-
- module.exit_json(**ret)
- except Exception as e:
- module.fail_json(msg=str(e), exception=traceback.format_exc())
- finally:
- connection.close(logout=auth.get('token') is None)
-
-
-if __name__ == "__main__":
- main()