Skip to content

Commit 03eb1b7

Browse files
Adding vm_snapshot examples to collection (#223)
* Adding vm_snapshot examples to collection: - filter and delete based on special properties - filter and delete based on timestamps
1 parent 6a17236 commit 03eb1b7

File tree

8 files changed

+498
-15
lines changed

8 files changed

+498
-15
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
- name: Example - delete all snapshots that are older than X days.
3+
hosts: localhost
4+
connection: local
5+
gather_facts: false
6+
vars:
7+
# Format: 'YYYY-MM-DD hh:mm:ss'
8+
# All snapshots older than this date will be deleted.
9+
# use_date timezone should match the Scale cluster timezone
10+
use_date: '1999-05-03 12:52:00'
11+
12+
tasks:
13+
# ------------------------------------------------------
14+
- name: List all snapshots
15+
scale_computing.hypercore.vm_snapshot_info:
16+
register: snapshot_results
17+
18+
- name: Convert date to unix timestamp 'epoch'
19+
ansible.builtin.set_fact:
20+
epoch_timestamp: "{{ (use_date | to_datetime).strftime('%s') }}"
21+
22+
- name: Show epoch_timestamp
23+
ansible.builtin.debug:
24+
var: epoch_timestamp
25+
26+
- name: Create filtered_snapshots list
27+
ansible.builtin.set_fact:
28+
filtered_snapshots: []
29+
30+
- name: Loop through snapshots and add snapshots that are older than 'use_date'
31+
ansible.builtin.set_fact:
32+
filtered_snapshots: "{{ filtered_snapshots + [item] }}"
33+
when: item.timestamp < epoch_timestamp | int
34+
loop: "{{ snapshot_results.records }}"
35+
no_log: true
36+
37+
- name: Show only snapshots that are older than 'use_date'
38+
ansible.builtin.debug:
39+
var: filtered_snapshots
40+
41+
# We could reuse "filtered_snapshots" here instead of "snapshot_results" and avoid the "when" statement.
42+
# But leaving it as is for example purposes.
43+
# Since this is the only mandatory task of the playbook, can be copy-pasted and reused as standalone task.
44+
- name: Loop through list of snapshots and delete all older than the 'use_date'
45+
scale_computing.hypercore.vm_snapshot:
46+
vm_name: "{{ item.vm.name }}"
47+
uuid: "{{ item.snapshot_uuid }}"
48+
state: absent
49+
when: item.timestamp < epoch_timestamp | int
50+
loop: "{{ snapshot_results.records }}"
51+
52+
- name: Create filtered_snapshots list - second time
53+
ansible.builtin.set_fact:
54+
filtered_snapshots: []
55+
56+
- name: Loop through snapshots and add snapshots that are older than 'use_date' - second time
57+
ansible.builtin.set_fact:
58+
filtered_snapshots: "{{ filtered_snapshots + [item] }}"
59+
when: item.timestamp < epoch_timestamp | int
60+
loop: "{{ snapshot_results.records }}"
61+
no_log: true
62+
63+
- name: Show only snapshots that are older than 'use_date' - second time
64+
ansible.builtin.debug:
65+
var: filtered_snapshots
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
- name: Example - delete all snapshots with label "TEST" and type "USER".
3+
hosts: localhost
4+
connection: local
5+
gather_facts: false
6+
vars:
7+
# This variable is used to filter and delete snapshots.
8+
# All snapshots with 'use_label' will be DELETED.
9+
use_label: 'TEST'
10+
11+
tasks:
12+
# ------------------------------------------------------
13+
- name: List all snapshots
14+
scale_computing.hypercore.vm_snapshot_info:
15+
register: snapshot_results
16+
17+
- name: Create filtered_snapshots list
18+
ansible.builtin.set_fact:
19+
filtered_snapshots: []
20+
21+
- name: Loop through snapshots and add snapshots with use_label and type 'USER' to filtered_snapshots
22+
ansible.builtin.set_fact:
23+
filtered_snapshots: "{{ filtered_snapshots + [item] }}"
24+
when: item.label == use_label and item.type == 'USER'
25+
loop: "{{ snapshot_results.records }}"
26+
no_log: true
27+
28+
- name: Show only snapshots with use_label and type "USER"
29+
ansible.builtin.debug:
30+
var: filtered_snapshots
31+
32+
# We could reuse "filtered_snapshots" here instead of "snapshot_results" and avoid the "when" statement.
33+
# But leaving it as is for example purposes.
34+
# Since this is the only mandatory task of the playbook, can be copy-pasted and reused as standalone task.
35+
- name: Loop through list of snapshots delete if label is use_label and type is 'USER'
36+
scale_computing.hypercore.vm_snapshot:
37+
vm_name: "{{ item.vm.name }}"
38+
uuid: "{{ item.snapshot_uuid }}"
39+
state: absent
40+
when: item.label == use_label and item.type == 'USER'
41+
loop: "{{ snapshot_results.records }}"
42+
43+
- name: List all snapshots - second time
44+
scale_computing.hypercore.vm_snapshot_info:
45+
register: snapshot_results
46+
47+
- name: Create filtered_snapshots list - second time
48+
ansible.builtin.set_fact:
49+
filtered_snapshots: []
50+
51+
- name: Loop through snapshots and add snapshots with use_label and type 'USER' to filtered_snapshots - second time
52+
ansible.builtin.set_fact:
53+
filtered_snapshots: "{{ filtered_snapshots + [item] }}"
54+
when: item.label == use_label and item.type == 'USER'
55+
loop: "{{ snapshot_results.records }}"
56+
no_log: true
57+
58+
- name: Show only snapshots with use_label and type 'USER' - second time
59+
ansible.builtin.debug:
60+
var: filtered_snapshots

plugins/module_utils/vm_snapshot.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,7 @@ def get_snapshot_by_uuid(
226226
cls, snapshot_uuid: str, rest_client: RestClient, must_exist: bool = False
227227
) -> Optional[VMSnapshot]:
228228
hypercore_dict = rest_client.get_record(
229-
endpoint="/rest/v1/VirDomainSnapshot",
230-
query={"uuid": snapshot_uuid},
229+
endpoint=f"/rest/v1/VirDomainSnapshot/{snapshot_uuid}",
231230
must_exist=must_exist,
232231
)
233232
vm_snapshot = cls.from_hypercore(hypercore_dict)

plugins/modules/vm_snapshot.py

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
description: source VM name.
2929
label:
3030
type: str
31-
required: true
3231
description:
3332
- Snapshot label, used as identificator in combination with vm_name.
3433
- Must be unique for a specific VM.
@@ -49,6 +48,12 @@
4948
choices: [ present, absent]
5049
type: str
5150
required: True
51+
uuid:
52+
type: str
53+
description:
54+
- Snapshot uuid, used as identificator.
55+
- Can be used instead of label.
56+
- Must be unique.
5257
"""
5358

5459

@@ -145,6 +150,29 @@
145150
from ..module_utils.vm import VM
146151

147152

153+
def get_snapshot(
154+
module: AnsibleModule, rest_client: RestClient, vm_object: VM
155+
) -> List[TypedVMSnapshotToAnsible]:
156+
# Get snapshot by uuid first if parameter exists.
157+
if module.params["uuid"]:
158+
snapshot_list = VMSnapshot.get_snapshots_by_query(
159+
dict(uuid=module.params["uuid"], domainUUID=vm_object.uuid), rest_client
160+
)
161+
# Otherwise get by label
162+
else:
163+
snapshot_list = VMSnapshot.get_snapshots_by_query(
164+
dict(label=module.params["label"], domainUUID=vm_object.uuid), rest_client
165+
)
166+
167+
# Snapshot should be unique by this point.
168+
if len(snapshot_list) > 1:
169+
raise errors.ScaleComputingError(
170+
f"Virtual machine - {module.params['vm_name']} - has more than one snapshot with label - {module.params['label']}, specify uuid instead."
171+
)
172+
173+
return snapshot_list
174+
175+
148176
def ensure_present(
149177
module: AnsibleModule,
150178
rest_client: RestClient,
@@ -203,15 +231,7 @@ def run(
203231
module: AnsibleModule, rest_client: RestClient
204232
) -> Tuple[bool, Optional[TypedVMSnapshotToAnsible], TypedDiff]:
205233
vm_object: VM = VM.get_by_name(module.params, rest_client, must_exist=True) # type: ignore
206-
snapshot_list = VMSnapshot.get_snapshots_by_query(
207-
dict(label=module.params["label"], domainUUID=vm_object.uuid), rest_client
208-
)
209-
210-
# VM should only have one snapshot with a specific label, we use vm_name and label as snapshot identificator.
211-
if len(snapshot_list) > 1:
212-
raise errors.ScaleComputingError(
213-
f"Virtual machine - {module.params['vm_name']} - has more than one snapshot with label - {module.params['label']}."
214-
)
234+
snapshot_list = get_snapshot(module, rest_client, vm_object)
215235

216236
if module.params["state"] == State.present:
217237
return ensure_present(module, rest_client, vm_object, snapshot_list)
@@ -237,7 +257,6 @@ def main() -> None:
237257
),
238258
label=dict(
239259
type="str",
240-
required=True,
241260
),
242261
retain_for=dict(
243262
type="int",
@@ -246,7 +265,15 @@ def main() -> None:
246265
type="bool",
247266
default=True,
248267
),
268+
uuid=dict(
269+
type="str",
270+
),
249271
),
272+
mutually_exclusive=[("label", "uuid")],
273+
required_if=[
274+
("state", "absent", ("label", "uuid"), True),
275+
("state", "present", ["label"]),
276+
],
250277
)
251278

252279
try:

0 commit comments

Comments
 (0)