diff --git a/changelogs/fragments/7143-proxmox-template.yml b/changelogs/fragments/7143-proxmox-template.yml new file mode 100644 index 0000000000..89d44594d3 --- /dev/null +++ b/changelogs/fragments/7143-proxmox-template.yml @@ -0,0 +1,3 @@ +minor_changes: + - proxmox - adds ``template`` value to the ``state`` parameter, allowing conversion of container to a template (https://github.com/ansible-collections/community.general/pull/7143). + - proxmox_kvm - adds ``template`` value to the ``state`` parameter, allowing conversion of a VM to a template (https://github.com/ansible-collections/community.general/pull/7143). diff --git a/plugins/modules/proxmox.py b/plugins/modules/proxmox.py index 7a0df1422b..7f84a30fcd 100644 --- a/plugins/modules/proxmox.py +++ b/plugins/modules/proxmox.py @@ -144,8 +144,9 @@ options: state: description: - Indicate desired state of the instance + - V(template) was added in community.general 8.1.0. type: str - choices: ['present', 'started', 'absent', 'stopped', 'restarted'] + choices: ['present', 'started', 'absent', 'stopped', 'restarted', 'template'] default: present pubkey: description: @@ -419,6 +420,23 @@ EXAMPLES = r''' api_host: node1 state: restarted +- name: Convert container to template + community.general.proxmox: + vmid: 100 + api_user: root@pam + api_password: 1q2w3e + api_host: node1 + state: template + +- name: Convert container to template (stop container if running) + community.general.proxmox: + vmid: 100 + api_user: root@pam + api_password: 1q2w3e + api_host: node1 + state: template + force: true + - name: Remove container community.general.proxmox: vmid: 100 @@ -581,6 +599,13 @@ class ProxmoxLxcAnsible(ProxmoxAnsible): time.sleep(1) return False + def convert_to_template(self, vm, vmid, timeout, force): + if getattr(self.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'running' and force: + self.stop_instance(vm, vmid, timeout, force) + # not sure why, but templating a container doesn't return a taskid + getattr(self.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).template.post() + return True + def umount_instance(self, vm, vmid, timeout): taskid = getattr(self.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.umount.post() while timeout: @@ -621,7 +646,7 @@ def main(): timeout=dict(type='int', default=30), force=dict(type='bool', default=False), purge=dict(type='bool', default=False), - state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted']), + state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'template']), pubkey=dict(type='str'), unprivileged=dict(type='bool', default=True), description=dict(type='str'), @@ -791,6 +816,15 @@ def main(): except Exception as e: module.fail_json(vmid=vmid, msg="stopping of VM %s failed with exception: %s" % (vmid, e)) + elif state == 'template': + try: + vm = proxmox.get_vm(vmid) + + proxmox.convert_to_template(vm, vmid, timeout, force=module.params['force']) + module.exit_json(changed=True, msg="VM %s is converted to template" % vmid) + except Exception as e: + module.fail_json(vmid=vmid, msg="conversion of VM %s to template failed with exception: %s" % (vmid, e)) + elif state == 'restarted': try: vm = proxmox.get_vm(vmid) diff --git a/plugins/modules/proxmox_kvm.py b/plugins/modules/proxmox_kvm.py index d3c06b9adf..1422a7c63d 100644 --- a/plugins/modules/proxmox_kvm.py +++ b/plugins/modules/proxmox_kvm.py @@ -453,8 +453,9 @@ options: description: - Indicates desired state of the instance. - If V(current), the current state of the VM will be fetched. You can access it with C(results.status) + - V(template) was added in community.general 8.1.0. type: str - choices: ['present', 'started', 'absent', 'stopped', 'restarted', 'current'] + choices: ['present', 'started', 'absent', 'stopped', 'restarted', 'current', 'template'] default: present storage: description: @@ -792,6 +793,25 @@ EXAMPLES = ''' node: sabrewulf state: restarted +- name: Convert VM to template + community.general.proxmox_kvm: + api_user: root@pam + api_password: secret + api_host: helldorado + name: spynal + node: sabrewulf + state: template + +- name: Convert VM to template (stop VM if running) + community.general.proxmox_kvm: + api_user: root@pam + api_password: secret + api_host: helldorado + name: spynal + node: sabrewulf + state: template + force: true + - name: Remove VM community.general.proxmox_kvm: api_user: root@pam @@ -1135,6 +1155,19 @@ class ProxmoxKvmAnsible(ProxmoxAnsible): self.module.fail_json(vmid=vmid, msg="restarting of VM %s failed with exception: %s" % (vmid, e)) return False + def convert_to_template(self, vm, timeout, force): + vmid = vm['vmid'] + try: + proxmox_node = self.proxmox_api.nodes(vm['node']) + if proxmox_node.qemu(vmid).status.current.get()['status'] == 'running' and force: + self.stop_instance(vm, vmid, timeout, force) + # not sure why, but templating a container doesn't return a taskid + proxmox_node.qemu(vmid).template.post() + return True + except Exception as e: + self.module.fail_json(vmid=vmid, msg="conversion of VM %s to template failed with exception: %s" % (vmid, e)) + return False + def migrate_vm(self, vm, target_node): vmid = vm['vmid'] proxmox_node = self.proxmox_api.nodes(vm['node']) @@ -1222,7 +1255,7 @@ def main(): sshkeys=dict(type='str', no_log=False), startdate=dict(type='str'), startup=dict(), - state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'current']), + state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'current', 'template']), storage=dict(type='str'), tablet=dict(type='bool'), tags=dict(type='list', elements='str'), @@ -1492,11 +1525,24 @@ def main(): if vm['status'] == 'stopped': module.exit_json(changed=False, vmid=vmid, msg="VM %s is already stopped" % vmid, **status) - if proxmox.stop_vm(vm, force=module.params['force'], timeout=module.params['timeout']): - module.exit_json(changed=True, vmid=vmid, msg="VM %s is shutting down" % vmid, **status) + proxmox.stop_vm(vm, force=module.params['force'], timeout=module.params['timeout']) + module.exit_json(changed=True, vmid=vmid, msg="VM %s is shutting down" % vmid, **status) except Exception as e: module.fail_json(vmid=vmid, msg="stopping of VM %s failed with exception: %s" % (vmid, e), **status) + elif state == 'template': + if not vmid: + module.fail_json(msg='VM with name = %s does not exist in cluster' % name) + + status = {} + try: + vm = proxmox.get_vm(vmid) + + if proxmox.convert_to_template(vm, force=module.params['force'], timeout=module.params['timeout']): + module.exit_json(changed=True, vmid=vmid, msg="VM %s is converting to template" % vmid, **status) + except Exception as e: + module.fail_json(vmid=vmid, msg="conversion of VM %s to template failed with exception: %s" % (vmid, e), **status) + elif state == 'restarted': if not vmid: module.fail_json(msg='VM with name = %s does not exist in cluster' % name)