summaryrefslogtreecommitdiffstats
path: root/ansible_collections/openstack/cloud/plugins/modules/image.py
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/openstack/cloud/plugins/modules/image.py')
-rw-r--r--ansible_collections/openstack/cloud/plugins/modules/image.py681
1 files changed, 470 insertions, 211 deletions
diff --git a/ansible_collections/openstack/cloud/plugins/modules/image.py b/ansible_collections/openstack/cloud/plugins/modules/image.py
index fae13a2e5..48527de16 100644
--- a/ansible_collections/openstack/cloud/plugins/modules/image.py
+++ b/ansible_collections/openstack/cloud/plugins/modules/image.py
@@ -1,125 +1,135 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2013, Benno Joy <benno@ansible.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-# TODO(mordred): we need to support "location"(v1) and "locations"(v2)
-
-DOCUMENTATION = '''
----
+DOCUMENTATION = r'''
module: image
-short_description: Add/Delete images from OpenStack Cloud
+short_description: Manage images of OpenStack image (Glance) service.
author: OpenStack Ansible SIG
description:
- - Add or Remove images from the OpenStack Image Repository
+ - Create or delete images in OpenStack image (Glance) service.
options:
- name:
- description:
- - The name of the image when uploading - or the name/ID of the image if deleting
- required: true
- type: str
- id:
- description:
- - The ID of the image when uploading an image
- type: str
- checksum:
- description:
- - The checksum of the image
- type: str
- disk_format:
- description:
- - The format of the disk that is getting uploaded
- default: qcow2
- choices: ['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso', 'vhdx', 'ploop']
- type: str
- container_format:
- description:
- - The format of the container
- default: bare
- choices: ['ami', 'aki', 'ari', 'bare', 'ovf', 'ova', 'docker']
- type: str
- project:
- description:
- - The name or ID of the project owning the image
- type: str
- aliases: ['owner']
- project_domain:
- description:
- - The domain the project owning the image belongs to
- - May be used to identify a unique project when providing a name to the project argument and multiple projects with such name exist
- type: str
- min_disk:
- description:
- - The minimum disk space (in GB) required to boot this image
- type: int
- min_ram:
- description:
- - The minimum ram (in MB) required to boot this image
- type: int
- is_public:
- description:
- - Whether the image can be accessed publicly. Note that publicizing an image requires admin role by default.
- type: bool
- default: false
- protected:
- description:
- - Prevent image from being deleted
- type: bool
- default: false
- filename:
- description:
- - The path to the file which has to be uploaded
- type: str
- ramdisk:
- description:
- - The name of an existing ramdisk image that will be associated with this image
- type: str
- kernel:
- description:
- - The name of an existing kernel image that will be associated with this image
- type: str
- properties:
- description:
- - Additional properties to be associated with this image
- default: {}
- type: dict
- state:
- description:
- - Should the resource be present or absent.
- choices: [present, absent]
- default: present
- type: str
- tags:
- description:
- - List of tags to be applied to the image
- default: []
- type: list
- elements: str
- volume:
- description:
- - ID of a volume to create an image from.
- - The volume must be in AVAILABLE state.
- type: str
-requirements:
- - "python >= 3.6"
- - "openstacksdk"
-
+ checksum:
+ description:
+ - The checksum of the image.
+ type: str
+ container_format:
+ description:
+ - The format of the container.
+ - This image attribute cannot be changed.
+ - Examples are C(ami), C(aki), C(ari), C(bare), C(ovf), C(ova) or
+ C(docker).
+ default: bare
+ type: str
+ disk_format:
+ description:
+ - The format of the disk that is getting uploaded.
+ - This image attribute cannot be changed.
+ - Examples are C(ami), C(ari), C(aki), C(vhd), C(vmdk), C(raw),
+ C(qcow2), C(vdi), c(iso), C(vhdx) or C(ploop).
+ default: qcow2
+ type: str
+ filename:
+ description:
+ - The path to the file which has to be uploaded.
+ - This image attribute cannot be changed.
+ type: str
+ id:
+ description:
+ - The ID of the image when uploading an image.
+ - This image attribute cannot be changed.
+ type: str
+ is_protected:
+ description:
+ - Prevent image from being deleted.
+ aliases: ['protected']
+ type: bool
+ is_public:
+ description:
+ - Whether the image can be accessed publicly.
+ - Setting I(is_public) to C(true) requires admin role by default.
+ - I(is_public) has been deprecated. Use I(visibility) instead of
+ I(is_public).
+ type: bool
+ default: false
+ kernel:
+ description:
+ - The name of an existing kernel image that will be associated with this
+ image.
+ type: str
+ min_disk:
+ description:
+ - The minimum disk space (in GB) required to boot this image.
+ type: int
+ min_ram:
+ description:
+ - The minimum ram (in MB) required to boot this image.
+ type: int
+ name:
+ description:
+ - The name of the image when uploading - or the name/ID of the image if
+ deleting.
+ - If provided with the id, it can be used to change the name of existing
+ image.
+ required: true
+ type: str
+ owner:
+ description:
+ - The name or ID of the project owning the image.
+ type: str
+ aliases: ['project']
+ owner_domain:
+ description:
+ - The name or id of the domain the project owning the image belongs to.
+ - May be used to identify a unique project when providing a name to the
+ project argument and multiple projects with such name exist.
+ type: str
+ aliases: ['project_domain']
+ properties:
+ description:
+ - Additional properties to be associated with this image.
+ default: {}
+ type: dict
+ ramdisk:
+ description:
+ - The name of an existing ramdisk image that will be associated with this
+ image.
+ type: str
+ state:
+ description:
+ - Should the resource be present or absent.
+ choices: [present, absent]
+ default: present
+ type: str
+ tags:
+ description:
+ - List of tags to be applied to the image.
+ default: []
+ type: list
+ elements: str
+ visibility:
+ description:
+ - The image visibility.
+ type: str
+ choices: [public, private, shared, community]
+ volume:
+ description:
+ - ID of a volume to create an image from.
+ - The volume must be in AVAILABLE state.
+ - I(volume) has been deprecated. Use module M(openstack.cloud.volume)
+ instead.
+ type: str
extends_documentation_fragment:
-- openstack.cloud.openstack
+ - openstack.cloud.openstack
'''
-EXAMPLES = '''
-# Upload an image from a local file named cirros-0.3.0-x86_64-disk.img
-- openstack.cloud.image:
- auth:
- auth_url: https://identity.example.com
- username: admin
- password: passme
- project_name: admin
- openstack.cloud.identity_user_domain_name: Default
- openstack.cloud.project_domain_name: Default
+EXAMPLES = r'''
+- name: Upload an image from a local file named cirros-0.3.0-x86_64-disk.img
+ openstack.cloud.image:
+ cloud: devstack-admin
name: cirros
container_format: bare
disk_format: qcow2
@@ -132,33 +142,229 @@ EXAMPLES = '''
properties:
cpu_arch: x86_64
distro: ubuntu
+'''
-# Create image from volume attached to an instance
-- name: create volume snapshot
- openstack.cloud.volume_snapshot:
- auth:
- "{{ auth }}"
- display_name: myvol_snapshot
- volume: myvol
- force: yes
- register: myvol_snapshot
-
-- name: create volume from snapshot
- openstack.cloud.volume:
- auth:
- "{{ auth }}"
- size: "{{ myvol_snapshot.snapshot.size }}"
- snapshot_id: "{{ myvol_snapshot.snapshot.id }}"
- display_name: myvol_snapshot_volume
- wait: yes
- register: myvol_snapshot_volume
-
-- name: create image from volume snapshot
- openstack.cloud.image:
- auth:
- "{{ auth }}"
- volume: "{{ myvol_snapshot_volume.volume.id }}"
- name: myvol_image
+RETURN = r'''
+image:
+ description: Dictionary describing the Glance image.
+ returned: On success when I(state) is C(present).
+ type: dict
+ contains:
+ id:
+ description: Unique UUID.
+ type: str
+ name:
+ description: Name given to the image.
+ type: str
+ status:
+ description: Image status.
+ type: str
+ architecture:
+ description: The CPU architecture that must be supported by
+ the hypervisor.
+ type: str
+ created_at:
+ description: Image created at timestamp.
+ type: str
+ container_format:
+ description: Container format of the image.
+ type: str
+ direct_url:
+ description: URL to access the image file kept in external store.
+ type: str
+ min_ram:
+ description: Min amount of RAM required for this image.
+ type: int
+ disk_format:
+ description: Disk format of the image.
+ type: str
+ file:
+ description: The URL for the virtual machine image file.
+ type: str
+ has_auto_disk_config:
+ description: If root partition on disk is automatically resized
+ before the instance boots.
+ type: bool
+ hash_algo:
+ description: The algorithm used to compute a secure hash of the
+ image data.
+ type: str
+ hash_value:
+ description: The hexdigest of the secure hash of the image data
+ computed using the algorithm whose name is the value of the
+ os_hash_algo property.
+ type: str
+ hw_cpu_cores:
+ description: Used to pin the virtual CPUs (vCPUs) of instances to
+ the host's physical CPU cores (pCPUs).
+ type: str
+ hw_cpu_policy:
+ description: The hexdigest of the secure hash of the image data.
+ type: str
+ hw_cpu_sockets:
+ description: Preferred number of sockets to expose to the guest.
+ type: str
+ hw_cpu_thread_policy:
+ description: Defines how hardware CPU threads in a simultaneous
+ multithreading-based (SMT) architecture be used.
+ type: str
+ hw_cpu_threads:
+ description: The preferred number of threads to expose to the guest.
+ type: str
+ hw_disk_bus:
+ description: Specifies the type of disk controller to attach disk
+ devices to.
+ type: str
+ hw_machine_type:
+ description: Enables booting an ARM system using the
+ specified machine type.
+ type: str
+ hw_qemu_guest_agent:
+ description: "A string boolean, which if 'true', QEMU guest agent
+ will be exposed to the instance."
+ type: str
+ hw_rng_model:
+ description: "Adds a random-number generator device to the image's
+ instances."
+ type: str
+ hw_scsi_model:
+ description: Enables the use of VirtIO SCSI (virtio-scsi) to
+ provide block device access for compute instances.
+ type: str
+ hw_video_model:
+ description: The video image driver used.
+ type: str
+ hw_video_ram:
+ description: Maximum RAM for the video image.
+ type: str
+ hw_vif_model:
+ description: Specifies the model of virtual network interface device to
+ use.
+ type: str
+ hw_watchdog_action:
+ description: Enables a virtual hardware watchdog device that
+ carries out the specified action if the server hangs.
+ type: str
+ hypervisor_type:
+ description: The hypervisor type.
+ type: str
+ instance_type_rxtx_factor:
+ description: Optional property allows created servers to have a
+ different bandwidth cap than that defined in the network
+ they are attached to.
+ type: str
+ instance_uuid:
+ description: For snapshot images, this is the UUID of the server
+ used to create this image.
+ type: str
+ is_hidden:
+ description: Controls whether an image is displayed in the default
+ image-list response
+ type: bool
+ is_hw_boot_menu_enabled:
+ description: Enables the BIOS bootmenu.
+ type: bool
+ is_hw_vif_multiqueue_enabled:
+ description: Enables the virtio-net multiqueue feature.
+ type: bool
+ kernel_id:
+ description: The ID of an image stored in the Image service that
+ should be used as the kernel when booting an AMI-style
+ image.
+ type: str
+ locations:
+ description: A list of URLs to access the image file in external store.
+ type: str
+ metadata:
+ description: The location metadata.
+ type: str
+ needs_config_drive:
+ description: Specifies whether the image needs a config drive.
+ type: bool
+ needs_secure_boot:
+ description: Whether Secure Boot is needed.
+ type: bool
+ os_admin_user:
+ description: The operating system admin username.
+ type: str
+ os_command_line:
+ description: The kernel command line to be used by libvirt driver.
+ type: str
+ os_distro:
+ description: The common name of the operating system distribution
+ in lowercase.
+ type: str
+ os_require_quiesce:
+ description: If true, require quiesce on snapshot via
+ QEMU guest agent.
+ type: str
+ os_shutdown_timeout:
+ description: Time for graceful shutdown.
+ type: str
+ os_type:
+ description: The operating system installed on the image.
+ type: str
+ os_version:
+ description: The operating system version as specified by
+ the distributor.
+ type: str
+ owner_id:
+ description: The ID of the owner, or project, of the image.
+ type: str
+ ramdisk_id:
+ description: The ID of image stored in the Image service that should
+ be used as the ramdisk when booting an AMI-style image.
+ type: str
+ schema:
+ description: URL for the schema describing a virtual machine image.
+ type: str
+ store:
+ description: Glance will attempt to store the disk image data in the
+ backing store indicated by the value of the header.
+ type: str
+ updated_at:
+ description: Image updated at timestamp.
+ type: str
+ url:
+ description: URL to access the image file kept in external store.
+ type: str
+ virtual_size:
+ description: The virtual size of the image.
+ type: str
+ vm_mode:
+ description: The virtual machine mode.
+ type: str
+ vmware_adaptertype:
+ description: The virtual SCSI or IDE controller used by the
+ hypervisor.
+ type: str
+ vmware_ostype:
+ description: Operating system installed in the image.
+ type: str
+ filters:
+ description: Additional properties associated with the image.
+ type: dict
+ min_disk:
+ description: Min amount of disk space required for this image.
+ type: int
+ is_protected:
+ description: Image protected flag.
+ type: bool
+ checksum:
+ description: Checksum for the image.
+ type: str
+ owner:
+ description: Owner for the image.
+ type: str
+ visibility:
+ description: Indicates who has access to the image.
+ type: str
+ size:
+ description: Size of the image.
+ type: int
+ tags:
+ description: List of tags assigned to the image
+ type: list
'''
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
@@ -166,99 +372,152 @@ from ansible_collections.openstack.cloud.plugins.module_utils.openstack import O
class ImageModule(OpenStackModule):
- deprecated_names = ('os_image', 'openstack.cloud.os_image')
-
argument_spec = dict(
- name=dict(required=True, type='str'),
- id=dict(type='str'),
- checksum=dict(type='str'),
- disk_format=dict(default='qcow2',
- choices=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso', 'vhdx', 'ploop']),
- container_format=dict(default='bare', choices=['ami', 'aki', 'ari', 'bare', 'ovf', 'ova', 'docker']),
- project=dict(type='str', aliases=['owner']),
- project_domain=dict(type='str'),
- min_disk=dict(type='int', default=0),
- min_ram=dict(type='int', default=0),
+ checksum=dict(),
+ container_format=dict(default='bare'),
+ disk_format=dict(default='qcow2'),
+ filename=dict(),
+ id=dict(),
+ is_protected=dict(type='bool', aliases=['protected']),
is_public=dict(type='bool', default=False),
- protected=dict(type='bool', default=False),
- filename=dict(type='str'),
- ramdisk=dict(type='str'),
- kernel=dict(type='str'),
+ kernel=dict(),
+ min_disk=dict(type='int'),
+ min_ram=dict(type='int'),
+ name=dict(required=True),
+ owner=dict(aliases=['project']),
+ owner_domain=dict(aliases=['project_domain']),
properties=dict(type='dict', default={}),
- volume=dict(type='str'),
- tags=dict(type='list', default=[], elements='str'),
+ ramdisk=dict(),
state=dict(default='present', choices=['absent', 'present']),
+ tags=dict(type='list', default=[], elements='str'),
+ visibility=dict(choices=['public', 'private', 'shared', 'community']),
+ volume=dict(),
)
module_kwargs = dict(
- mutually_exclusive=[['filename', 'volume']],
+ mutually_exclusive=[
+ ('filename', 'volume'),
+ ('visibility', 'is_public'),
+ ],
)
- def run(self):
+ # resource attributes obtainable directly from params
+ attr_params = ('id', 'name', 'filename', 'disk_format',
+ 'container_format', 'wait', 'timeout', 'is_public',
+ 'is_protected', 'min_disk', 'min_ram', 'volume', 'tags')
+
+ def _resolve_visibility(self):
+ """resolve a visibility value to be compatible with older versions"""
+ if self.params['visibility']:
+ return self.params['visibility']
+ if self.params['is_public'] is not None:
+ return 'public' if self.params['is_public'] else 'private'
+ return None
+
+ def _build_params(self, owner):
+ params = {attr: self.params[attr] for attr in self.attr_params}
+ if owner:
+ params['owner_id'] = owner.id
+ params['visibility'] = self._resolve_visibility()
+ params = {k: v for k, v in params.items() if v is not None}
+ return params
+
+ def _return_value(self, image_name_or_id):
+ image = self.conn.image.find_image(image_name_or_id)
+ if image:
+ image = image.to_dict(computed=False)
+ return image
+
+ def _build_update(self, image):
+ update_payload = {'visibility': self._resolve_visibility()}
+
+ for k in ('is_protected', 'min_disk', 'min_ram'):
+ update_payload[k] = self.params[k]
+
+ for k in ('kernel', 'ramdisk'):
+ if not self.params[k]:
+ continue
+ k_id = '{0}_id'.format(k)
+ k_image = self.conn.image.find_image(
+ name_or_id=self.params[k], ignore_missing=False)
+ update_payload[k_id] = k_image.id
+ update_payload = {k: v for k, v in update_payload.items()
+ if v is not None and image[k] != v}
+
+ for p, v in self.params['properties'].items():
+ if p not in image or image[p] != v:
+ update_payload[p] = v
+
+ if (self.params['tags']
+ and set(image['tags']) != set(self.params['tags'])):
+ update_payload['tags'] = self.params['tags']
+
+ # If both name and id are defined,then we might change the name
+ if self.params['id'] and \
+ self.params['name'] and \
+ self.params['name'] != image['name']:
+ update_payload['name'] = self.params['name']
+
+ return update_payload
+
+ def run(self):
changed = False
- if self.params['id']:
- image = self.conn.get_image(name_or_id=self.params['id'])
- elif self.params['checksum']:
- image = self.conn.get_image(name_or_id=self.params['name'], filters={'checksum': self.params['checksum']})
- else:
- image = self.conn.get_image(name_or_id=self.params['name'])
+ image_name_or_id = self.params['id'] or self.params['name']
+ owner_name_or_id = self.params['owner']
+ owner_domain_name_or_id = self.params['owner_domain']
+ owner_filters = {}
+ if owner_domain_name_or_id:
+ owner_domain = self.conn.identity.find_domain(
+ owner_domain_name_or_id)
+ if owner_domain:
+ owner_filters['domain_id'] = owner_domain.id
+ else:
+ # else user may not be able to enumerate domains
+ owner_filters['domain_id'] = owner_domain_name_or_id
+
+ owner = None
+ if owner_name_or_id:
+ owner = self.conn.identity.find_project(
+ owner_name_or_id, ignore_missing=False, **owner_filters)
+ image = None
+ if image_name_or_id:
+ image = self.conn.get_image(
+ image_name_or_id,
+ filters={k: self.params[k]
+ for k in ['checksum'] if self.params[k] is not None})
+
+ changed = False
if self.params['state'] == 'present':
+ attrs = self._build_params(owner)
if not image:
- kwargs = {}
- if self.params['id'] is not None:
- kwargs['id'] = self.params['id']
- if self.params['project']:
- project_domain = {'id': None}
- if self.params['project_domain']:
- project_domain = self.conn.get_domain(name_or_id=self.params['project_domain'])
- if not project_domain or project_domain['id'] is None:
- self.fail(msg='Project domain %s could not be found' % self.params['project_domain'])
- project = self.conn.get_project(name_or_id=self.params['project'], domain_id=project_domain['id'])
- if not project:
- self.fail(msg='Project %s could not be found' % self.params['project'])
- kwargs['owner'] = project['id']
- image = self.conn.create_image(
- name=self.params['name'],
- filename=self.params['filename'],
- disk_format=self.params['disk_format'],
- container_format=self.params['container_format'],
- wait=self.params['wait'],
- timeout=self.params['timeout'],
- is_public=self.params['is_public'],
- protected=self.params['protected'],
- min_disk=self.params['min_disk'],
- min_ram=self.params['min_ram'],
- volume=self.params['volume'],
- tags=self.params['tags'],
- **kwargs
- )
+ # self.conn.image.create_image() cannot be used because it does
+ # not provide self.conn.create_image()'s volume parameter [0].
+ # [0] https://opendev.org/openstack/openstacksdk/src/commit/
+ # a41d04ea197439c2f134ce3554995693933a46ac/openstack/cloud/_image.py#L306
+ image = self.conn.create_image(**attrs)
changed = True
if not self.params['wait']:
- self.exit(changed=changed, image=image, id=image.id)
-
- self.conn.update_image_properties(
- image=image,
- kernel=self.params['kernel'],
- ramdisk=self.params['ramdisk'],
- protected=self.params['protected'],
- **self.params['properties'])
- if self.params['tags']:
- self.conn.image.update_image(image.id, tags=self.params['tags'])
- image = self.conn.get_image(name_or_id=image.id)
- self.exit(changed=changed, image=image, id=image.id)
-
- elif self.params['state'] == 'absent':
- if not image:
- changed = False
- else:
- self.conn.delete_image(
- name_or_id=self.params['name'],
- wait=self.params['wait'],
- timeout=self.params['timeout'])
+ self.exit_json(changed=changed,
+ image=self._return_value(image.id))
+
+ update_payload = self._build_update(image)
+
+ if update_payload:
+ self.conn.image.update_image(image.id, **update_payload)
changed = True
- self.exit(changed=changed)
+
+ self.exit_json(changed=changed, image=self._return_value(image.id))
+
+ elif self.params['state'] == 'absent' and image is not None:
+ # self.conn.image.delete_image() does not offer a wait parameter
+ self.conn.delete_image(
+ name_or_id=image['id'],
+ wait=self.params['wait'],
+ timeout=self.params['timeout'])
+ changed = True
+ self.exit_json(changed=changed)
def main():