diff --git a/changelogs/fragments/1847_vmware_guest_snapshot.yml b/changelogs/fragments/1847_vmware_guest_snapshot.yml new file mode 100644 index 000000000..ffae31cd2 --- /dev/null +++ b/changelogs/fragments/1847_vmware_guest_snapshot.yml @@ -0,0 +1,2 @@ +minor_changes: + - add new snapshot_id option to the vmware_guest_snapshot module(https://github.com/ansible-collections/community.vmware/pull/1847). diff --git a/docs/community.vmware.vmware_guest_snapshot_module.rst b/docs/community.vmware.vmware_guest_snapshot_module.rst index f6dceb2de..74f3b2ce3 100644 --- a/docs/community.vmware.vmware_guest_snapshot_module.rst +++ b/docs/community.vmware.vmware_guest_snapshot_module.rst @@ -322,6 +322,23 @@ Parameters
If set to true and state is set to absent, then entire snapshot subtree is set for removal.
+ + +
+ snapshot_id + +
+ integer +
+
added in 3.10.0
+ + + + +
Sets the snapshot id to manage.
+
This param is available when state is absent.
+ +
@@ -335,7 +352,7 @@ Parameters
Sets the snapshot name to manage.
-
This param is required only if state is not remove_all
+
This param or snapshot_id is required only if state is not remove_all
@@ -545,6 +562,18 @@ Examples snapshot_name: snap1 delegate_to: localhost + - name: Remove a snapshot with a snapshot id + community.vmware.vmware_guest_snapshot: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + datacenter: "{{ datacenter_name }}" + folder: "/{{ datacenter_name }}/vm/" + name: "{{ guest_name }}" + snapshot_id: 10 + state: absent + delegate_to: localhost + - name: Rename a snapshot community.vmware.vmware_guest_snapshot: hostname: "{{ vcenter_hostname }}" diff --git a/plugins/modules/vmware_guest_snapshot.py b/plugins/modules/vmware_guest_snapshot.py index 6e33d2b95..ed108d69f 100644 --- a/plugins/modules/vmware_guest_snapshot.py +++ b/plugins/modules/vmware_guest_snapshot.py @@ -84,8 +84,14 @@ snapshot_name: description: - Sets the snapshot name to manage. - - This param is required only if state is not C(remove_all) + - This param or C(snapshot_id) is required only if state is not C(remove_all) type: str + snapshot_id: + description: + - Sets the snapshot id to manage. + - This param is available when state is C(absent). + type: int + version_added: 3.10.0 description: description: - Define an arbitrary description to attach to snapshot. @@ -214,6 +220,18 @@ snapshot_name: snap1 delegate_to: localhost + - name: Remove a snapshot with a snapshot id + community.vmware.vmware_guest_snapshot: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + datacenter: "{{ datacenter_name }}" + folder: "/{{ datacenter_name }}/vm/" + name: "{{ guest_name }}" + snapshot_id: 10 + state: absent + delegate_to: localhost + - name: Rename a snapshot community.vmware.vmware_guest_snapshot: hostname: "{{ vcenter_hostname }}" @@ -293,6 +311,16 @@ def get_snapshots_by_name_recursively(self, snapshots, snapname): snap_obj = snap_obj + self.get_snapshots_by_name_recursively(snapshot.childSnapshotList, snapname) return snap_obj + def get_snapshots_by_id_recursively(self, snapshots, snapid): + snap_obj = [] + for snapshot in snapshots: + if snapshot.id == snapid: + snap_obj.append(snapshot) + else: + snap_obj = snap_obj + self.get_snapshots_by_id_recursively(snapshot.childSnapshotList, snapid) + + return snap_obj + def snapshot_vm(self, vm): memory_dump = False quiesce = False @@ -357,8 +385,13 @@ def remove_or_revert_snapshot(self, vm): self.module.exit_json(msg="virtual machine - %s doesn't have any" " snapshots to remove." % vm_name) - snap_obj = self.get_snapshots_by_name_recursively(vm.snapshot.rootSnapshotList, - self.module.params["snapshot_name"]) + if self.module.params["snapshot_name"]: + snap_obj = self.get_snapshots_by_name_recursively(vm.snapshot.rootSnapshotList, + self.module.params["snapshot_name"]) + elif self.module.params["snapshot_id"]: + snap_obj = self.get_snapshots_by_id_recursively(vm.snapshot.rootSnapshotList, + self.module.params["snapshot_id"]) + task = None if len(snap_obj) == 1: snap_obj = snap_obj[0].snapshot @@ -414,6 +447,7 @@ def main(): folder=dict(type='str'), datacenter=dict(required=True, type='str'), snapshot_name=dict(type='str'), + snapshot_id=dict(type='int'), description=dict(type='str', default=''), quiesce=dict(type='bool', default=False), memory_dump=dict(type='bool', default=False), @@ -429,6 +463,9 @@ def main(): required_one_of=[ ['name', 'uuid', 'moid'] ], + mutually_exclusive=[ + ['snapshot_name', 'snapshot_id'] + ] ) if module.params['folder']: @@ -444,7 +481,7 @@ def main(): vm_id = (module.params.get('uuid') or module.params.get('name') or module.params.get('moid')) module.fail_json(msg="Unable to manage snapshots for non-existing VM %s" % vm_id) - if not module.params['snapshot_name'] and module.params['state'] != 'remove_all': + if not (module.params['snapshot_name'] or module.params['snapshot_id']) and module.params['state'] != 'remove_all': module.fail_json(msg="snapshot_name param is required when state is '%(state)s'" % module.params) result = pyv.apply_snapshot_op(vm) diff --git a/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml b/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml index 622a69c70..4eeb11cf5 100644 --- a/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml +++ b/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml @@ -7,7 +7,7 @@ # Test0001: Try to delete the non-existent snapshot - name: 0001 - Delete non-existent snapshot - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -20,7 +20,7 @@ # Test0002: Create two snapshots - name: 0002 - Create snapshot - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -37,7 +37,7 @@ # Test0003: Reanme a to c - name: 0003 - Rename snapshot - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -51,7 +51,7 @@ # Test0004: Create snap_a again - name: 0004 - Re-create snapshot a - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -65,7 +65,7 @@ # Test0005: Change description of snap_c - name: 0005 - Change description of snap_c - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -79,7 +79,7 @@ # Test0006: Delete snap_b with child remove - name: 0006 - Delete snap_b with child remove - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -93,7 +93,7 @@ # Test0007: Delete all snapshots - name: 0007 - Delete all snapshots - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -105,7 +105,7 @@ # Test0008: Create snap_a again and revert to it - name: 0008 - Re-create snapshot a - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -118,7 +118,7 @@ description: "snap named a" - name: 0008 - Revert to snap_a - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -131,7 +131,7 @@ # Test0009: Create snap_a and check in result - name: 0009 - create snapshot a - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -144,16 +144,16 @@ description: "snap named a" register: snapshot_details -- debug: var=snapshot_details +- ansible.builtin.debug: var=snapshot_details - name: Check if snapshot details available or not - assert: + ansible.builtin.assert: that: - "snapshot_details['msg'] == 'Snapshot named [snap_a] already exists and is current.'" # Test0011: Failure sceanrios - when name and UUID is not specified - name: 0011 - name and UUID is missing - vmware_guest_snapshot: + community.vmware.vmware_guest_snapshot: validate_certs: false hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' @@ -166,7 +166,84 @@ ignore_errors: true - name: Check if error is shown - assert: + ansible.builtin.assert: that: - "'one of the following is required: name, uuid' in snapshot_failure_details['msg']" - "snapshot_failure_details.changed == false" + +# Test0010 : Test for revert and remove a snapshot to specify snapshot_id +- name: 0012 - Create snapshot + community.vmware.vmware_guest_snapshot: + validate_certs: false + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + datacenter: "{{ dc1 }}" + name: "{{ virtual_machines[0].name }}" + folder: "{{ virtual_machines[0].folder }}" + state: present + snapshot_name: "snap_{{item}}" + description: "snap named {{item}}" + with_items: + - b + - c + register: snapshot_creation_result0012 + +- name: Create the snapshot_ids variable + ansible.builtin.set_fact: + snapshot_ids: >- + {{ snapshot_ids | default([]) + + [({ + 'name': item.snapshot_results.current_snapshot.name, + 'snapshot_id': item.snapshot_results.current_snapshot.id + })] + }} + loop: "{{ snapshot_creation_result0012.results }}" + +- name: 0013 - Revert to snap_b with snapshot_id + community.vmware.vmware_guest_snapshot: + validate_certs: false + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + datacenter: "{{ dc1 }}" + name: "{{ virtual_machines[0].name }}" + folder: "{{ virtual_machines[0].folder }}" + state: revert + snapshot_id: "{{ item.snapshot_id }}" + loop: "{{ snapshot_ids }}" + when: + - item.name == "snap_b" + register: revert_snapshot_with_id_result + +- name: Make sure whether reverted with snapshot_id + ansible.builtin.assert: + that: + - item.changed is sameas true + loop: "{{ revert_snapshot_with_id_result.results }}" + when: + - item.item.name == "snap_b" + +- name: 0014 - Remove snap_b with snapshot_id + community.vmware.vmware_guest_snapshot: + validate_certs: false + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + datacenter: "{{ dc1 }}" + name: "{{ virtual_machines[0].name }}" + folder: "{{ virtual_machines[0].folder }}" + state: absent + snapshot_id: "{{ item.snapshot_id }}" + loop: "{{ snapshot_ids }}" + when: + - item.name == "snap_b" + register: remove_snapshot_with_id_result + +- name: Make sure whether removed with snapshot_id + ansible.builtin.assert: + that: + - item.changed is sameas true + loop: "{{ remove_snapshot_with_id_result.results }}" + when: + - item.item.name == "snap_b"