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:
parent
b8ecb1671b
commit
3c12c6f482
2 changed files with 90 additions and 22 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- proxmox_disk - add ability to manipulate CD-ROM drive (https://github.com/ansible-collections/community.general/pull/7495).
|
|
@ -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()
|
# 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]
|
storage_name = storage_volume[0]
|
||||||
volume_name = storage_volume[1]
|
volume_name = storage_volume[1]
|
||||||
config_current = dict(
|
config_current = dict(
|
||||||
volume='%s:%s' % (storage_name, volume_name),
|
volume='%s:%s' % (storage_name, volume_name),
|
||||||
storage_name=storage_name,
|
storage_name=storage_name,
|
||||||
volume_name=volume_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=[
|
||||||
|
|
Loading…
Reference in a new issue