Skip to content

Commit 2ad5a24

Browse files
committed
lib/basevm.py: add vdis related function
Add a list of vdis object to a VM Add get_dom0_vm in host.py Add function to connect/disconnect a VDI from a VM Signed-off-by: Damien Thenot <[email protected]>
1 parent 1d1e036 commit 2ad5a24

File tree

4 files changed

+68
-4
lines changed

4 files changed

+68
-4
lines changed

lib/basevm.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import logging
22

3-
from typing import TYPE_CHECKING, Any, Literal, Optional, overload
3+
from typing import TYPE_CHECKING, Any, List, Literal, Optional, overload
44

55
if TYPE_CHECKING:
66
import lib.host
77

8+
from lib.commands import SSHCommandFailed
89
from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
910
from lib.sr import SR
11+
from lib.vdi import VDI
1012

1113
class BaseVM:
1214
""" Base class for VM and Snapshot. """
@@ -18,6 +20,15 @@ def __init__(self, uuid: str, host: 'lib.host.Host'):
1820
logging.info("New %s: %s", type(self).__name__, uuid)
1921
self.uuid = uuid
2022
self.host = host
23+
try:
24+
self.vdis = [VDI(vdi_uuid, host=host) for vdi_uuid in self.vdi_uuids()]
25+
except SSHCommandFailed as e:
26+
# Doesn't work with Dom0 since `vm-disk-list` doesn't work on it so we create empty list
27+
if e.stdout == "Error: No matching VMs found":
28+
logging.info("Couldn't get disks list. We are Dom0. Continuing...")
29+
self.vdis = []
30+
else:
31+
raise
2132

2233
@overload
2334
def param_get(self, param_name: str, key: Optional[str] = ...,
@@ -59,7 +70,7 @@ def name(self) -> str:
5970
def _disk_list(self):
6071
raise NotImplementedError()
6172

62-
def vdi_uuids(self, sr_uuid=None):
73+
def vdi_uuids(self, sr_uuid=None) -> List[str]:
6374
output = self._disk_list()
6475
if output == '':
6576
return []
@@ -77,6 +88,9 @@ def vdi_uuids(self, sr_uuid=None):
7788

7889
def destroy_vdi(self, vdi_uuid: str) -> None:
7990
self.host.xe('vdi-destroy', {'uuid': vdi_uuid})
91+
for vdi in self.vdis:
92+
if vdi.uuid == vdi_uuid:
93+
self.vdis.remove(vdi)
8094

8195
def all_vdis_on_host(self, host):
8296
for vdi_uuid in self.vdi_uuids():

lib/host.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def __init__(self, pool: 'lib.pool.Pool', hostname_or_ip):
6767
self.uuid = self.inventory['INSTALLATION_UUID']
6868
self.xcp_version = version.parse(self.inventory['PRODUCT_VERSION'])
6969
self.xcp_version_short = f"{self.xcp_version.major}.{self.xcp_version.minor}"
70+
self._dom0: Optional[VM] = None
7071

7172
def __str__(self):
7273
return self.hostname_or_ip
@@ -711,3 +712,20 @@ def enable_hsts_header(self):
711712
def disable_hsts_header(self):
712713
self.ssh(['rm', '-f', f'{XAPI_CONF_DIR}/00-XCP-ng-tests-enable-hsts-header.conf'])
713714
self.restart_toolstack(verify=True)
715+
716+
def get_dom0_uuid(self):
717+
return self.inventory["CONTROL_DOMAIN_UUID"]
718+
719+
def get_dom0_VM(self) -> VM:
720+
if not self._dom0:
721+
self._dom0 = VM(self.get_dom0_uuid(), self)
722+
return self._dom0
723+
724+
def get_sr_from_vdi_uuid(self, vdi_uuid: str) -> Optional[SR]:
725+
sr_uuid = self.xe("vdi-param-get", {
726+
"param-name": "sr-uuid",
727+
"uuid": vdi_uuid,
728+
})
729+
if not sr_uuid:
730+
return None
731+
return SR(sr_uuid, self.pool)

lib/sr.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import logging
22
import time
3-
from typing import Optional
43

54
import lib.commands as commands
6-
from lib.common import prefix_object_name, safe_split, strtobool, wait_for, wait_for_not
5+
from lib.common import (
6+
prefix_object_name,
7+
safe_split,
8+
strtobool,
9+
wait_for,
10+
wait_for_not,
11+
)
712
from lib.vdi import VDI
813

14+
from typing import Optional
15+
916
class SR:
1017
def __init__(self, uuid, pool):
1118
self.uuid = uuid

lib/vm.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
)
2020
from lib.snapshot import Snapshot
2121
from lib.vbd import VBD
22+
from lib.vdi import VDI
2223
from lib.vif import VIF
2324

2425
from typing import TYPE_CHECKING, List, Literal, Optional, Union, overload
@@ -287,6 +288,30 @@ def checkpoint(self) -> Snapshot:
287288
'new-name-label': 'Checkpoint of %s' % self.uuid}),
288289
self.host)
289290

291+
def connect_vdi(self, vdi: VDI, device: str = "autodetect") -> str:
292+
logging.info(f">> Plugging VDI {vdi.uuid} on VM {self.uuid}")
293+
vbd_uuid = self.host.xe("vbd-create", {
294+
"vdi-uuid": vdi.uuid,
295+
"vm-uuid": self.uuid,
296+
"device": device,
297+
})
298+
self.host.xe("vbd-plug", {"uuid": vbd_uuid})
299+
300+
self.vdis.append(vdi)
301+
302+
return vbd_uuid
303+
304+
def disconnect_vdi(self, vdi: VDI):
305+
logging.info(f"<< Unplugging VDI {vdi.uuid} from VM {self.uuid}")
306+
assert vdi in self.vdis, "VDI {vdi.uuid} not in VM {self.uuid} VDI list"
307+
vbd_uuid = self.host.xe("vbd-list", {
308+
"vdi-uuid": vdi.uuid,
309+
"vm-uuid": self.uuid
310+
}, minimal=True)
311+
self.host.xe("vbd-unplug", {"uuid": vbd_uuid})
312+
self.host.xe("vbd-destroy", {"uuid": vbd_uuid})
313+
self.vdis.remove(vdi)
314+
290315
def vifs(self):
291316
_vifs = []
292317
for vif_uuid in safe_split(self.host.xe('vif-list', {'vm-uuid': self.uuid}, minimal=True)):

0 commit comments

Comments
 (0)