From f7f262adc727ff34fdd78ebe1aa5410d97259115 Mon Sep 17 00:00:00 2001 From: Tim Rightnour Date: Mon, 30 Oct 2017 09:20:03 -0700 Subject: [PATCH] Add the ability to rename a snapshot, or change it's description. (#31441) Also add tests for vmware_guest_snapshot, but disable them due to vcsim not fully supporting such operations yet. Implement changes suggested in review. Also fix same in remove_or_revert_snapshot() for consistency --- .../cloud/vmware/vmware_guest_snapshot.py | 62 +++++- .../targets/vmware_guest_snapshot/aliases | 4 + .../vmware_guest_snapshot/tasks/main.yml | 178 ++++++++++++++++++ 3 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 test/integration/targets/vmware_guest_snapshot/aliases create mode 100644 test/integration/targets/vmware_guest_snapshot/tasks/main.yml diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py b/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py index a269012aaf2..5307182ce1a 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py +++ b/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py @@ -24,7 +24,7 @@ author: - James Tanner (@jctanner) - Loic Blot (@nerzhul) notes: - - Tested on vSphere 5.5 + - Tested on vSphere 5.5, 6.0 requirements: - "python >= 2.6" - PyVmomi @@ -101,6 +101,14 @@ options: for removal. required: False version_added: "2.4" + new_snapshot_name: + description: + - Value to rename the existing snapshot to + version_added: 2.5 + new_description: + description: + - Value to change the description of an existing snapshot to + version_added: 2.5 extends_documentation_fragment: vmware.documentation ''' @@ -175,6 +183,18 @@ EXAMPLES = ''' remove_children: True snapshot_name: snap1 delegate_to: localhost + + - name: Rename a snapshot + vmware_guest_snapshot: + hostname: 192.168.1.209 + username: administrator@vsphere.local + password: vmware + name: dummy_vm + state: present + snapshot_name: current_snap_name + new_snapshot_name: im_renamed + new_description: "renamed snapshot today" + delegate_to: localhost ''' RETURN = """ @@ -261,9 +281,35 @@ class PyVmomiHelper(object): return task + def rename_snapshot(self, vm): + if vm.snapshot is None: + self.module.exit_json(msg="VM - %s doesn't have any snapshots" % + self.module.params.get('uuid') or self.module.params.get('name')) + + snap_obj = self.get_snapshots_by_name_recursively(vm.snapshot.rootSnapshotList, + self.module.params["snapshot_name"]) + task = None + if len(snap_obj) == 1: + snap_obj = snap_obj[0].snapshot + if self.module.params["new_snapshot_name"] and self.module.params["new_description"]: + task = snap_obj.RenameSnapshot(name=self.module.params["new_snapshot_name"], + description=self.module.params["new_description"]) + elif self.module.params["new_snapshot_name"]: + task = snap_obj.RenameSnapshot(name=self.module.params["new_snapshot_name"]) + else: + task = snap_obj.RenameSnapshot(description=self.module.params["new_description"]) + else: + self.module.exit_json( + msg="Couldn't find any snapshots with specified name: %s on VM: %s" % + (self.module.params["snapshot_name"], + self.module.params.get('uuid') or self.module.params.get('name'))) + + return task + def remove_or_revert_snapshot(self, vm): if vm.snapshot is None: - self.module.exit_json(msg="VM - %s doesn't have any snapshots" % self.module.params["name"]) + self.module.exit_json(msg="VM - %s doesn't have any snapshots" % + self.module.params.get('uuid') or self.module.params.get('name')) snap_obj = self.get_snapshots_by_name_recursively(vm.snapshot.rootSnapshotList, self.module.params["snapshot_name"]) @@ -279,14 +325,20 @@ class PyVmomiHelper(object): else: self.module.exit_json( msg="Couldn't find any snapshots with specified name: %s on VM: %s" % - (self.module.params["snapshot_name"], self.module.params["name"])) + (self.module.params["snapshot_name"], + self.module.params.get('uuid') or self.module.params.get('name'))) return task def apply_snapshot_op(self, vm): result = {} if self.module.params["state"] == "present": - task = self.snapshot_vm(vm) + if self.module.params["new_snapshot_name"] or self.module.params["new_description"]: + self.rename_snapshot(vm) + result = {'changed': True, 'failed': False, 'renamed': True} + task = None + else: + task = self.snapshot_vm(vm) elif self.module.params["state"] in ["absent", "revert"]: task = self.remove_or_revert_snapshot(vm) elif self.module.params["state"] == "remove_all": @@ -319,6 +371,8 @@ def main(): quiesce=dict(type='bool', default=False), memory_dump=dict(type='bool', default=False), remove_children=dict(type='bool', default=False), + new_snapshot_name=dict(type='str'), + new_description=dict(type='str'), ) module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['name', 'uuid']]) diff --git a/test/integration/targets/vmware_guest_snapshot/aliases b/test/integration/targets/vmware_guest_snapshot/aliases new file mode 100644 index 00000000000..748b11da6d3 --- /dev/null +++ b/test/integration/targets/vmware_guest_snapshot/aliases @@ -0,0 +1,4 @@ +posix/ci/cloud/group1/vcenter +cloud/vcenter +skip/python3 +destructive diff --git a/test/integration/targets/vmware_guest_snapshot/tasks/main.yml b/test/integration/targets/vmware_guest_snapshot/tasks/main.yml new file mode 100644 index 00000000000..4d07cde6d6c --- /dev/null +++ b/test/integration/targets/vmware_guest_snapshot/tasks/main.yml @@ -0,0 +1,178 @@ +- name: make sure pyvmomi is installed + pip: + name: pyvmomi + state: latest + when: ansible_user_id == 'root' + +- name: store the vcenter container ip + set_fact: + vcsim: "{{ lookup('env', 'vcenter_host') }}" +- debug: var=vcsim + +- name: Wait for Flask controller to come up online + wait_for: + host: "{{ vcsim }}" + port: 5000 + state: started + +- name: kill vcsim + uri: + url: "{{ 'http://' + vcsim + ':5000/killall' }}" +- name: start vcsim with no folders + uri: + url: "{{ 'http://' + vcsim + ':5000/spawn?datacenter=1&cluster=1&folder=1' }}" + register: vcsim_instance + +- name: Wait for Flask controller to come up online + wait_for: + host: "{{ vcsim }}" + port: 443 + state: started + +- name: get a list of VMS from vcsim + uri: + url: "{{ 'http://' + vcsim + ':5000/govc_find?filter=VM' }}" + register: vmlist + +- set_fact: + vm1: "{{ vmlist['json'][0] }}" + +- name: get a list of datacenters from vcsim + uri: + url: "{{ 'http://' + vcsim + ':5000/govc_find?filter=DC' }}" + register: datacenters + +- set_fact: + dc1: "{{ datacenters['json'][0] }}" + +- debug: var=vcsim_instance +- debug: var=vmlist +- debug: var=vm1 +- debug: var=dc1 + +# FIXME: VCSIM does not currently implement snapshots +# Awaiting: https://github.com/vmware/govmomi/pull/861/files +# +# # Test0001: Try to delete the non-existent snapshot +# - name: 0001 - Delete non-existent snapshot +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: absent +# snapshot_name: snap_a + +# # Test0002: Create two snapshots +# - name: 0002 - Create snapshot +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: present +# snapshot_name: "snap_{{item}}" +# description: "snap named {{item}}" +# with_items: +# - a +# - b + +# # Test0003: Reanme a to c +# - name: 0003 - Rename snapshot +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: present +# snapshot_name: snap_a +# new_snapshot_name: snap_c + +# # Test0004: Create snap_a again +# - name: 0004 - Re-create snapshot a +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: present +# snapshot_name: snap_a +# description: "snap named a" + +# # Test0005: Change description of snap_c +# - name: 0005 - Change description of snap_c +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: present +# snapshot_name: snap_c +# new_description: "renamed to snap_c from snap_a" + +# # Test0006: Delete snap_b with child remove +# - name: 0006 - Delete snap_b with child remove +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: absent +# snapshot_name: snap_b +# remove_children: True + +# # Test0007: Delete all snapshots +# - name: 0007 - Delete all snapshots +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: remove_all + +# # Test0008: Create snap_a again and revert to it +# - name: 0008 - Re-create snapshot a +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: present +# snapshot_name: snap_a +# description: "snap named a" + +# - name: 0008 - Revert to snap_a +# vmware_guest_snapshot: +# validate_certs: False +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance['json']['username'] }}" +# password: "{{ vcsim_instance['json']['password'] }}" +# datacenter: "{{ dc1 | basename }}" +# folder: "{{ vm1 | dirname }}" +# name: "{{ vm1 | basename }}" +# state: revert +# snapshot_name: snap_a