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

Allow Proxmox Snapshot Restoring (#4377)

* Allow restoring of snapshots

* Fix formatting

* Add documentation for new feature

* Revert unrelated reformatting

* Add documentation for snapshot change

* Remove redundant multiple call to status API

* Remove unneccesary indent

* Add documentation for timeout fix

* Update changelog fragment to reflect real changes

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

* Update changelog fragment to reflect real changes

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

* Add Tests for Snapshot rollback

* Update tests/unit/plugins/modules/cloud/misc/test_proxmox_snap.py

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

* Update changelogs/fragments/4377-allow-proxmox-snapshot-restoring.yml

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

* Update plugins/modules/cloud/misc/proxmox_snap.py

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

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
Timon Michel 2022-04-25 06:39:15 +02:00 committed by GitHub
parent c8c2636676
commit dbad1e0f11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 10 deletions

View file

@ -0,0 +1,3 @@
minor_changes:
- proxmox_snap - add restore snapshot option (https://github.com/ansible-collections/community.general/pull/4377).
- proxmox_snap - fixed timeout value to correctly reflect time in seconds. The timeout was off by one second (https://github.com/ansible-collections/community.general/pull/4377).

View file

@ -13,7 +13,7 @@ module: proxmox_snap
short_description: Snapshot management of instances in Proxmox VE cluster short_description: Snapshot management of instances in Proxmox VE cluster
version_added: 2.0.0 version_added: 2.0.0
description: description:
- Allows you to create/delete snapshots from instances in Proxmox VE cluster. - Allows you to create/delete/restore snapshots from instances in Proxmox VE cluster.
- Supports both KVM and LXC, OpenVZ has not been tested, as it is no longer supported on Proxmox VE. - Supports both KVM and LXC, OpenVZ has not been tested, as it is no longer supported on Proxmox VE.
options: options:
hostname: hostname:
@ -28,7 +28,8 @@ options:
state: state:
description: description:
- Indicate desired state of the instance snapshot. - Indicate desired state of the instance snapshot.
choices: ['present', 'absent'] - The C(rollback) value was added in community.general 4.8.0.
choices: ['present', 'absent', 'rollback']
default: present default: present
type: str type: str
force: force:
@ -53,7 +54,7 @@ options:
type: int type: int
snapname: snapname:
description: description:
- Name of the snapshot that has to be created. - Name of the snapshot that has to be created/deleted/restored.
default: 'ansible_snap' default: 'ansible_snap'
type: str type: str
@ -84,6 +85,15 @@ EXAMPLES = r'''
vmid: 100 vmid: 100
state: absent state: absent
snapname: pre-updates snapname: pre-updates
- name: Rollback container snapshot
community.general.proxmox_snap:
api_user: root@pam
api_password: 1q2w3e
api_host: node1
vmid: 100
state: rollback
snapname: pre-updates
''' '''
RETURN = r'''#''' RETURN = r'''#'''
@ -109,15 +119,15 @@ class ProxmoxSnapAnsible(ProxmoxAnsible):
else: else:
taskid = self.snapshot(vm, vmid).post(snapname=snapname, description=description, vmstate=int(vmstate)) taskid = self.snapshot(vm, vmid).post(snapname=snapname, description=description, vmstate=int(vmstate))
while timeout: while timeout:
if (self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['status'] == 'stopped' and status_data = self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()
self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['exitstatus'] == 'OK'): if status_data['status'] == 'stopped' and status_data['exitstatus'] == 'OK':
return True return True
timeout -= 1
if timeout == 0: if timeout == 0:
self.module.fail_json(msg='Reached timeout while waiting for creating VM snapshot. Last line in task before timeout: %s' % self.module.fail_json(msg='Reached timeout while waiting for creating VM snapshot. Last line in task before timeout: %s' %
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1]) self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
time.sleep(1) time.sleep(1)
timeout -= 1
return False return False
def snapshot_remove(self, vm, vmid, timeout, snapname, force): def snapshot_remove(self, vm, vmid, timeout, snapname, force):
@ -126,15 +136,32 @@ class ProxmoxSnapAnsible(ProxmoxAnsible):
taskid = self.snapshot(vm, vmid).delete(snapname, force=int(force)) taskid = self.snapshot(vm, vmid).delete(snapname, force=int(force))
while timeout: while timeout:
if (self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['status'] == 'stopped' and status_data = self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()
self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['exitstatus'] == 'OK'): if status_data['status'] == 'stopped' and status_data['exitstatus'] == 'OK':
return True return True
timeout -= 1
if timeout == 0: if timeout == 0:
self.module.fail_json(msg='Reached timeout while waiting for removing VM snapshot. Last line in task before timeout: %s' % self.module.fail_json(msg='Reached timeout while waiting for removing VM snapshot. Last line in task before timeout: %s' %
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1]) self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
time.sleep(1) time.sleep(1)
timeout -= 1
return False
def snapshot_rollback(self, vm, vmid, timeout, snapname):
if self.module.check_mode:
return True
taskid = self.snapshot(vm, vmid)(snapname).post("rollback")
while timeout:
status_data = self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()
if status_data['status'] == 'stopped' and status_data['exitstatus'] == 'OK':
return True
if timeout == 0:
self.module.fail_json(msg='Reached timeout while waiting for rolling back VM snapshot. Last line in task before timeout: %s' %
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
time.sleep(1)
timeout -= 1
return False return False
@ -144,7 +171,7 @@ def main():
vmid=dict(required=False), vmid=dict(required=False),
hostname=dict(), hostname=dict(),
timeout=dict(type='int', default=30), timeout=dict(type='int', default=30),
state=dict(default='present', choices=['present', 'absent']), state=dict(default='present', choices=['present', 'absent', 'rollback']),
description=dict(type='str'), description=dict(type='str'),
snapname=dict(type='str', default='ansible_snap'), snapname=dict(type='str', default='ansible_snap'),
force=dict(type='bool', default='no'), force=dict(type='bool', default='no'),
@ -211,6 +238,25 @@ def main():
except Exception as e: except Exception as e:
module.fail_json(msg="Removing snapshot %s of VM %s failed with exception: %s" % (snapname, vmid, to_native(e))) module.fail_json(msg="Removing snapshot %s of VM %s failed with exception: %s" % (snapname, vmid, to_native(e)))
elif state == 'rollback':
try:
snap_exist = False
for i in proxmox.snapshot(vm, vmid).get():
if i['name'] == snapname:
snap_exist = True
continue
if not snap_exist:
module.exit_json(changed=False, msg="Snapshot %s does not exist" % snapname)
if proxmox.snapshot_rollback(vm, vmid, timeout, snapname):
if module.check_mode:
module.exit_json(changed=True, msg="Snapshot %s would be rolled back" % snapname)
else:
module.exit_json(changed=True, msg="Snapshot %s rolled back" % snapname)
except Exception as e:
module.fail_json(msg="Rollback of snapshot %s of VM %s failed with exception: %s" % (snapname, vmid, to_native(e)))
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -91,3 +91,26 @@ def test_remove_snapshot_check_mode(connect_mock, capfd, mocker):
out, err = capfd.readouterr() out, err = capfd.readouterr()
assert not err assert not err
assert not json.loads(out)['changed'] assert not json.loads(out)['changed']
@patch('ansible_collections.community.general.plugins.module_utils.proxmox.ProxmoxAnsible._connect')
def test_rollback_snapshot_check_mode(connect_mock, capfd, mocker):
set_module_args({"hostname": "test-lxc",
"api_user": "root@pam",
"api_password": "secret",
"api_host": "127.0.0.1",
"state": "rollback",
"snapname": "test",
"timeout": "1",
"force": True,
"_ansible_check_mode": True})
proxmox_utils.HAS_PROXMOXER = True
connect_mock.side_effect = lambda: fake_api(mocker)
with pytest.raises(SystemExit) as results:
proxmox_snap.main()
out, err = capfd.readouterr()
assert not err
output = json.loads(out)
assert not output['changed']
assert output['msg'] == "Snapshot test does not exist"