1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

[proxmox_disk]: Add ability to manipulate CD-ROM drive (#7495)

* add: ability to manipulate CD-ROM drive

Added ability to manipulate CD-ROM drive:
create, mount, umount, use physical drive.

* Add changelog fragment

* Relax cdrom option requirement

* Formatting values

Co-authored-by: Felix Fontein <felix@fontein.de>

* YAML fix

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
castorsky 2023-11-19 12:31:05 +03:00 committed by GitHub
parent b8ecb1671b
commit 3c12c6f482
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 22 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- proxmox_disk - add ability to manipulate CD-ROM drive (https://github.com/ansible-collections/community.general/pull/7495).

View file

@ -256,6 +256,16 @@ options:
- The drive's media type. - The drive's media type.
type: str type: str
choices: ['cdrom', 'disk'] choices: ['cdrom', 'disk']
iso_image:
description:
- The ISO image to be mounted on the specified in O(disk) CD-ROM.
- O(media=cdrom) needs to be specified for this option to work.
- "Image string format:"
- V(<STORAGE>:iso/<ISO_NAME>) to mount ISO.
- V(cdrom) to use physical CD/DVD drive.
- V(none) to unmount image from existent CD-ROM or create empty CD-ROM drive.
type: str
version_added: 8.1.0
queues: queues:
description: description:
- Number of queues (SCSI only). - Number of queues (SCSI only).
@ -412,6 +422,18 @@ EXAMPLES = '''
vmid: 101 vmid: 101
disk: scsi4 disk: scsi4
state: absent state: absent
- name: Mount ISO image on CD-ROM (create drive if missing)
community.general.proxmox_disk:
api_host: node1
api_user: root@pam
api_token_id: token1
api_token_secret: some-token-data
vmid: 101
disk: ide2
media: cdrom
iso_image: local:iso/favorite_distro_amd64.iso
state: present
''' '''
RETURN = ''' RETURN = '''
@ -435,17 +457,41 @@ from time import sleep
def disk_conf_str_to_dict(config_string): def disk_conf_str_to_dict(config_string):
"""
Transform Proxmox configuration string for disk element into dictionary which has
volume option parsed in '{ storage }:{ volume }' format and other options parsed
in '{ option }={ value }' format. This dictionary will be compared afterward with
attributes that user passed to this module in playbook.\n
config_string examples:
- local-lvm:vm-100-disk-0,ssd=1,discard=on,size=25G
- local:iso/new-vm-ignition.iso,media=cdrom,size=70k
- none,media=cdrom
:param config_string: Retrieved from Proxmox API configuration string
:return: Dictionary with volume option divided into parts ('volume_name', 'storage_name', 'volume') \n
and other options as key:value.
"""
config = config_string.split(',') config = config_string.split(',')
storage_volume = config.pop(0).split(':')
config.sort()
storage_name = storage_volume[0]
volume_name = storage_volume[1]
config_current = dict(
volume='%s:%s' % (storage_name, volume_name),
storage_name=storage_name,
volume_name=volume_name
)
# When empty CD-ROM drive present, the volume part of config string is "none".
storage_volume = config.pop(0)
if storage_volume in ["none", "cdrom"]:
config_current = dict(
volume=storage_volume,
storage_name=None,
volume_name=None,
size=None,
)
else:
storage_volume = storage_volume.split(':')
storage_name = storage_volume[0]
volume_name = storage_volume[1]
config_current = dict(
volume='%s:%s' % (storage_name, volume_name),
storage_name=storage_name,
volume_name=volume_name,
)
config.sort()
for option in config: for option in config:
k, v = option.split('=') k, v = option.split('=')
config_current[k] = v config_current[k] = v
@ -497,13 +543,19 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
if (create == 'regular' and disk not in vm_config) or (create == 'forced'): if (create == 'regular' and disk not in vm_config) or (create == 'forced'):
# CREATE # CREATE
attributes = self.get_create_attributes() playbook_config = self.get_create_attributes()
import_string = attributes.pop('import_from', None) import_string = playbook_config.pop('import_from', None)
iso_image = self.module.params.get('iso_image', None)
if import_string: if import_string:
# When 'import_from' option is present in task options.
config_str = "%s:%s,import-from=%s" % (self.module.params["storage"], "0", import_string) config_str = "%s:%s,import-from=%s" % (self.module.params["storage"], "0", import_string)
timeout_str = "Reached timeout while importing VM disk. Last line in task before timeout: %s" timeout_str = "Reached timeout while importing VM disk. Last line in task before timeout: %s"
ok_str = "Disk %s imported into VM %s" ok_str = "Disk %s imported into VM %s"
elif iso_image is not None:
# disk=<busN>, media=cdrom, iso_image=<ISO_NAME>
config_str = iso_image
ok_str = "CD-ROM was created on %s bus in VM %s"
else: else:
config_str = self.module.params["storage"] config_str = self.module.params["storage"]
if self.module.params.get("media") != "cdrom": if self.module.params.get("media") != "cdrom":
@ -511,29 +563,41 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
ok_str = "Disk %s created in VM %s" ok_str = "Disk %s created in VM %s"
timeout_str = "Reached timeout while creating VM disk. Last line in task before timeout: %s" timeout_str = "Reached timeout while creating VM disk. Last line in task before timeout: %s"
for k, v in attributes.items(): for k, v in playbook_config.items():
config_str += ',%s=%s' % (k, v) config_str += ',%s=%s' % (k, v)
disk_config_to_apply = {self.module.params["disk"]: config_str} disk_config_to_apply = {self.module.params["disk"]: config_str}
if create in ['disabled', 'regular'] and disk in vm_config: if create in ['disabled', 'regular'] and disk in vm_config:
# UPDATE # UPDATE
disk_config = disk_conf_str_to_dict(vm_config[disk])
config_str = disk_config["volume"]
ok_str = "Disk %s updated in VM %s" ok_str = "Disk %s updated in VM %s"
attributes = self.get_create_attributes() iso_image = self.module.params.get('iso_image', None)
# 'import_from' fails on disk updates
attributes.pop('import_from', None)
for k, v in attributes.items(): proxmox_config = disk_conf_str_to_dict(vm_config[disk])
# 'import_from' fails on disk updates
playbook_config = self.get_create_attributes()
playbook_config.pop('import_from', None)
# Begin composing configuration string
if iso_image is not None:
config_str = iso_image
else:
config_str = proxmox_config["volume"]
# Append all mandatory fields from playbook_config
for k, v in playbook_config.items():
config_str += ',%s=%s' % (k, v) config_str += ',%s=%s' % (k, v)
# Now compare old and new config to detect if changes are needed # Append to playbook_config fields which are constants for disk images
for option in ['size', 'storage_name', 'volume', 'volume_name']: for option in ['size', 'storage_name', 'volume', 'volume_name']:
attributes.update({option: disk_config[option]}) playbook_config.update({option: proxmox_config[option]})
# CD-ROM is special disk device and its disk image is subject to change
if iso_image is not None:
playbook_config['volume'] = iso_image
# Values in params are numbers, but strings are needed to compare with disk_config # Values in params are numbers, but strings are needed to compare with disk_config
attributes = dict((k, str(v)) for k, v in attributes.items()) playbook_config = dict((k, str(v)) for k, v in playbook_config.items())
if disk_config == attributes:
# Now compare old and new config to detect if changes are needed
if proxmox_config == playbook_config:
return False, "Disk %s is up to date in VM %s" % (disk, vmid) return False, "Disk %s is up to date in VM %s" % (disk, vmid)
disk_config_to_apply = {self.module.params["disk"]: config_str} disk_config_to_apply = {self.module.params["disk"]: config_str}
@ -602,6 +666,7 @@ def main():
iops_wr_max=dict(type='int'), iops_wr_max=dict(type='int'),
iops_wr_max_length=dict(type='int'), iops_wr_max_length=dict(type='int'),
iothread=dict(type='bool'), iothread=dict(type='bool'),
iso_image=dict(type='str'),
mbps=dict(type='float'), mbps=dict(type='float'),
mbps_max=dict(type='float'), mbps_max=dict(type='float'),
mbps_rd=dict(type='float'), mbps_rd=dict(type='float'),
@ -666,6 +731,7 @@ def main():
'iops_max_length': 'iops_max', 'iops_max_length': 'iops_max',
'iops_rd_max_length': 'iops_rd_max', 'iops_rd_max_length': 'iops_rd_max',
'iops_wr_max_length': 'iops_wr_max', 'iops_wr_max_length': 'iops_wr_max',
'iso_image': 'media',
}, },
supports_check_mode=False, supports_check_mode=False,
mutually_exclusive=[ mutually_exclusive=[