Skip to content

Commit 141d852

Browse files
committed
Shutdown VM if disk cannot be removed from running VM
Before VM was (always) shutdown only if IDE CD-ROM was removed. Now VM will be shutdown if disk removal from running VM fails. Fixes #249 Signed-off-by: Justin Cinkelj <justin.cinkelj@xlab.si>
1 parent d480511 commit 141d852

File tree

6 files changed

+76
-23
lines changed

6 files changed

+76
-23
lines changed

plugins/module_utils/disk.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,10 @@ def needs_reboot(self, action: str, desired_disk=None) -> bool:
198198
# Delete and change type.
199199
if desired_disk and action == "update" and self.type != desired_disk.type:
200200
return True
201-
if (
202-
action == "delete" and self.type == "ide_cdrom"
203-
): # ide_cdrom can never be deleted when VM is running.
201+
if action == "delete" and self.type == "ide_cdrom":
202+
# ide_cdrom can never be deleted when VM is running.
203+
# Also other disks types cannot be deleted when VM is running
204+
# if HyperCore thinks disk is being "used".
204205
return True
205206
return False
206207

plugins/module_utils/errors.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
__metaclass__ = type
99

10+
import json
1011
from typing import Union
1112
from ansible.module_utils.urls import Request
1213

@@ -111,3 +112,13 @@ class ScaleTimeoutError(ScaleComputingError):
111112
def __init__(self, data: Union[str, Exception]):
112113
self.message = f"Request timed out: {data}."
113114
super(ScaleTimeoutError, self).__init__(self.message)
115+
116+
117+
class TaskTagError(ScaleComputingError):
118+
def __init__(self, task_tag: dict):
119+
message = "There was a problem during this task execution."
120+
message += f" Task details: {json.dumps(task_tag)}"
121+
self.message = message
122+
self.task_tag_state = task_tag["state"]
123+
self.task_tag = task_tag
124+
super().__init__(self.message)

plugins/module_utils/task_tag.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
__metaclass__ = type
1111

12-
import json
1312
from time import sleep
1413

1514
from ..module_utils import errors
@@ -47,9 +46,7 @@ def wait_task(
4746
"ERROR",
4847
"UNINITIALIZED",
4948
): # TaskTag has finished unsucessfully or was never initialized, both are errors.
50-
msg = "There was a problem during this task execution."
51-
msg += f" Task details: {json.dumps(task_status)}"
52-
raise errors.ScaleComputingError(msg)
49+
raise errors.TaskTagError(task_status)
5350
if task_status.get("state", "") not in (
5451
"RUNNING",
5552
"QUEUED",

plugins/module_utils/vm.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,10 @@ def _delete_not_used_disks(cls, module, rest_client, vm, changed, disk_key):
10911091
):
10921092
to_delete = False
10931093
if to_delete:
1094+
# HyperCore is sometimes able to delete disk on running VM,
1095+
# but sometimes we need to shutdown VM to remove disk.
1096+
# It is hard to know in advance if shutdown is required.
1097+
# We try to remove disk without shutdown, if delete fails, we shutdown VM and try again.
10941098
if existing_disk.needs_reboot("delete"):
10951099
vm.do_shutdown_steps(module, rest_client)
10961100
task_tag = rest_client.delete_record(
@@ -1099,7 +1103,33 @@ def _delete_not_used_disks(cls, module, rest_client, vm, changed, disk_key):
10991103
),
11001104
module.check_mode,
11011105
)
1102-
TaskTag.wait_task(rest_client, task_tag, module.check_mode)
1106+
try:
1107+
TaskTag.wait_task(rest_client, task_tag, module.check_mode)
1108+
except errors.TaskTagError as ex:
1109+
# Delete failed, maybe because VM was running and disk was in use.
1110+
# If VM is running, shutdown VM and retry delete.
1111+
if ex.task_tag_state != "ERROR":
1112+
raise
1113+
# The particular "formattedMessage" is returned by HyperCore 9.2.17
1114+
if (
1115+
ex.task_tag["formattedMessage"]
1116+
!= "Unable to delete block device from VM '%@': Still in use"
1117+
):
1118+
raise
1119+
vm_fresh_data = rest_client.get_record(
1120+
f"/rest/v1/VirDomain/{vm.uuid}", must_exist=True
1121+
)
1122+
if vm_fresh_data["state"] != "RUNNING":
1123+
raise
1124+
# shutdown and retry remove
1125+
vm.do_shutdown_steps(module, rest_client)
1126+
task_tag = rest_client.delete_record(
1127+
"{0}/{1}".format(
1128+
"/rest/v1/VirDomainBlockDevice", existing_disk.uuid
1129+
),
1130+
module.check_mode,
1131+
)
1132+
TaskTag.wait_task(rest_client, task_tag, module.check_mode)
11031133
changed = True
11041134
return changed
11051135

plugins/modules/vm.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
description:
1919
- Use this module to create, update or delete a VM. When creating or
2020
updating a VM, setting the disks, network nics and boot order is possible.
21+
22+
- Module tries to remove disks from a running VM.
23+
If disk cannot be removed from running VM,
24+
then VM will be shutdown, disk will be removed, and VM is started back.
25+
- VM has C(shutdown_timeout) time to respond to shutdown request.
26+
If VM is not shutoff within I(shutdown_timeout),
27+
then a force shutdown will be issued if C(force_reboot=True).
2128
version_added: 1.0.0
2229
extends_documentation_fragment:
2330
- scale_computing.hypercore.cluster_instance

plugins/modules/vm_disk.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,28 @@
1515
- Tjaž Eržen (@tjazsch)
1616
short_description: Manage VM's disks
1717
description:
18-
Use this module to add, delete or set disks to the VM.
19-
The module can also remove all disks from a VM,
20-
attach and/or detach ISO image to the VM by ISO's name,
21-
detach ISO image from the VM by disk's disk slot,
22-
or update the existing disks (disk size etc.).
23-
24-
For a given VM, a particular disk is selected by combination of (I(type), I(disk_slot)).
25-
I(disk_slot) means slot on bus (IDE, virtio or SCSI bus).
26-
27-
Changing disk I(type) can change its I(disk_slot).
28-
For example, VM has one IDE CD-ROM and one virtio_disk.
29-
The disk will have C(type=virtio_disk) and C(disk_slot=0),
30-
and CD-ROM will have C(type=ide_cdrom) and C(disk_slot=0).
31-
Changing disk I(type) to C(ide_disk) will as place disk on IDE bus,
32-
after the CD-ROM, and disk will get C(disk_slot=1).
18+
- Use this module to add, delete or set disks to the VM.
19+
The module can also remove all disks from a VM,
20+
attach and/or detach ISO image to the VM by ISO's name,
21+
detach ISO image from the VM by disk's disk slot,
22+
or update the existing disks (disk size etc.).
23+
24+
- For a given VM, a particular disk is selected by combination of (I(type), I(disk_slot)).
25+
I(disk_slot) means slot on bus (IDE, virtio or SCSI bus).
26+
27+
- Changing disk I(type) can change its I(disk_slot).
28+
For example, VM has one IDE CD-ROM and one virtio_disk.
29+
The disk will have C(type=virtio_disk) and C(disk_slot=0),
30+
and CD-ROM will have C(type=ide_cdrom) and C(disk_slot=0).
31+
Changing disk I(type) to C(ide_disk) will as place disk on IDE bus,
32+
after the CD-ROM, and disk will get C(disk_slot=1).
33+
34+
- Module tries to remove disks from a running VM.
35+
If disk cannot be removed from running VM,
36+
then VM will be shutdown, disk will be removed, and VM is started back.
37+
- VM has C(shutdown_timeout) time to respond to shutdown request.
38+
If VM is not shutoff within I(shutdown_timeout),
39+
then a force shutdown will be issued if C(force_reboot=True).
3340
3441
version_added: 1.0.0
3542
extends_documentation_fragment:

0 commit comments

Comments
 (0)