mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
* 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>
(cherry picked from commit dbad1e0f11
)
Co-authored-by: Timon Michel <ich.bin@ein.dev>
This commit is contained in:
parent
759e82d403
commit
868a6303be
3 changed files with 82 additions and 10 deletions
|
@ -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).
|
|
@ -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__':
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue