Skip to content

Commit ce31457

Browse files
committed
Add more abstractions for Host, Network, PIF, Tunnel, VIF, VLAN
Signed-off-by: Sebastien Rodot <sebastien.rodot@vates.tech>
1 parent 6d807c1 commit ce31457

6 files changed

Lines changed: 184 additions & 0 deletions

File tree

lib/host.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
from lib.network import Network
3232
from lib.pif import PIF
3333
from lib.sr import SR
34+
from lib.tunnel import Tunnel
35+
from lib.vlan import VLAN
3436
from lib.vm import VM
3537
from lib.xo import xo_cli, xo_object_exists
3638

@@ -715,6 +717,9 @@ def yum_restore_saved_state(self) -> None:
715717
self.saved_packages_list = None
716718
self.saved_rollback_id = None
717719

720+
def service_started(self, name: str) -> bool:
721+
return self.ssh(f'systemctl is-active {name}', check=False) == 'active'
722+
718723
def reboot(self, verify: bool = False) -> None:
719724
logging.info(f"[{self}] Reboot host")
720725
# Running `reboot` directly immediately disconnects the ssh session and makes the ssh client return with an
@@ -1050,6 +1055,9 @@ def pifs(self, device: str | None = None) -> list[PIF]:
10501055

10511056
return [PIF(uuid, self) for uuid in safe_split(self.xe("pif-list", args, minimal=True))]
10521057

1058+
def tunnels(self) -> list[Tunnel]:
1059+
return [Tunnel(self, uuid) for uuid in safe_split(self.xe("tunnel-list", {}, minimal=True))]
1060+
10531061
def create_bond(self, network: Network, pifs: list[PIF], mode: str | None = None) -> Bond:
10541062
args: dict[str, str | bool | dict[str, str]] = {
10551063
'network-uuid': network.uuid,
@@ -1077,3 +1085,35 @@ def create_network(self, label: str, description: str | None = None) -> Network:
10771085
logging.info(f"[{self}] New Network: {uuid}")
10781086

10791087
return Network(self, uuid)
1088+
1089+
def create_vlan(self, network: Network, pif: PIF, vlan: int) -> VLAN:
1090+
args: dict[str, str | bool | dict[str, str]] = {
1091+
'network-uuid': network.uuid,
1092+
'pif-uuid': pif.uuid,
1093+
'vlan': str(vlan),
1094+
}
1095+
1096+
untagged_pif_uuid = self.xe("vlan-create", args, minimal=True)
1097+
uuid = self.xe("pif-param-get", {
1098+
"uuid": untagged_pif_uuid,
1099+
"param-name": "vlan-master-of",
1100+
})
1101+
logging.info(f"New VLAN: {uuid} (untagged-pif: {untagged_pif_uuid})")
1102+
1103+
return VLAN(self, uuid)
1104+
1105+
def create_tunnel(self, network: Network, pif: PIF, protocol: str) -> Tunnel:
1106+
args: dict[str, str | bool | dict[str, str]] = {
1107+
'network-uuid': network.uuid,
1108+
'pif-uuid': pif.uuid,
1109+
'protocol': protocol,
1110+
}
1111+
1112+
access_pif_uuid = self.xe("tunnel-create", args, minimal=True)
1113+
uuid = self.xe("pif-param-get", {
1114+
"uuid": access_pif_uuid,
1115+
"param-name": "tunnel-access-PIF-of",
1116+
})
1117+
logging.info(f"New Tunnel: {uuid} (access-pif: {access_pif_uuid})")
1118+
1119+
return Tunnel(self, uuid)

lib/network.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,8 @@ def managed(self) -> bool:
6464

6565
def MTU(self) -> int:
6666
return int(self.param_get('MTU') or '0')
67+
68+
def bridge(self) -> str:
69+
bridge = self.param_get('bridge')
70+
assert bridge is not None, "network must have a bridge"
71+
return bridge

lib/pif.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,20 @@ def network_uuid(self) -> str:
6666
assert uuid is not None, "unexpected PIF without network-uuid"
6767
return uuid
6868

69+
def ip_configuration_mode(self) -> str:
70+
mode = self.param_get("IP-configuration-mode")
71+
assert mode
72+
return mode
73+
74+
def vlan(self) -> int | None:
75+
vlan_str = self.param_get('VLAN')
76+
assert vlan_str
77+
vlan = int(vlan_str)
78+
if vlan == -1:
79+
return None
80+
else:
81+
return vlan
82+
6983
def reconfigure_ip(self, mode: str) -> None:
7084
self.host.xe("pif-reconfigure-ip", {
7185
"uuid": self.uuid,

lib/tunnel.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
5+
from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
6+
from lib.pif import PIF
7+
8+
from typing import TYPE_CHECKING, Literal, overload
9+
10+
if TYPE_CHECKING:
11+
from lib.host import Host
12+
13+
class Tunnel:
14+
xe_prefix = "tunnel"
15+
16+
def __init__(self, host: Host, uuid: str):
17+
self.host = host
18+
self.uuid = uuid
19+
20+
@overload
21+
def param_get(self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[False] = ...) -> str:
22+
...
23+
24+
@overload
25+
def param_get(
26+
self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[True] = ...
27+
) -> str | None:
28+
...
29+
30+
def param_get(self, param_name: str, key: str | None = None, accept_unknown_key: bool = False) -> str | None:
31+
return _param_get(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)
32+
33+
def param_set(self, param_name: str, value: str | bool | dict[str, str], key: str | None = None) -> None:
34+
_param_set(self.host, self.xe_prefix, self.uuid, param_name, value, key)
35+
36+
def param_remove(self, param_name: str, key: str, accept_unknown_key: bool = False) -> None:
37+
_param_remove(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)
38+
39+
def param_add(self, param_name: str, value: str, key: str | None = None) -> None:
40+
_param_add(self.host, self.xe_prefix, self.uuid, param_name, value, key)
41+
42+
def param_clear(self, param_name: str) -> None:
43+
_param_clear(self.host, self.xe_prefix, self.uuid, param_name)
44+
45+
def destroy(self):
46+
logging.info(f"Destroying Tunnel: {self.uuid}")
47+
self.host.xe('tunnel-destroy', {'uuid': self.uuid})
48+
49+
def access_pif(self) -> PIF:
50+
uuid = self.param_get("access-PIF")
51+
assert uuid
52+
return PIF(uuid, self.host)
53+
54+
def transport_pif(self) -> PIF:
55+
uuid = self.param_get("transport-PIF")
56+
assert uuid
57+
return PIF(uuid, self.host)

lib/vif.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import time
55

66
from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
7+
from lib.network import Network
78

89
from typing import TYPE_CHECKING, Literal, overload
910

@@ -134,3 +135,8 @@ def configure_ipv6(
134135
gateway: str | None = None,
135136
) -> None:
136137
self._configure("ipv6", mode, address, gateway)
138+
139+
def network(self) -> Network:
140+
network_uuid = self.param_get('network-uuid')
141+
assert network_uuid is not None, "VIF must have a network-uuid"
142+
return Network(self.vm.host, network_uuid)

lib/vlan.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
5+
from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
6+
from lib.pif import PIF
7+
8+
from typing import TYPE_CHECKING, Literal, overload
9+
10+
if TYPE_CHECKING:
11+
from lib.host import Host
12+
13+
class VLAN:
14+
xe_prefix = "vlan"
15+
16+
def __init__(self, host: Host, uuid: str):
17+
self.host = host
18+
self.uuid = uuid
19+
20+
@overload
21+
def param_get(self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[False] = ...) -> str:
22+
...
23+
24+
@overload
25+
def param_get(
26+
self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[True] = ...
27+
) -> str | None:
28+
...
29+
30+
def param_get(self, param_name: str, key: str | None = None, accept_unknown_key: bool = False) -> str | None:
31+
return _param_get(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)
32+
33+
def param_set(self, param_name: str, value: str | bool | dict[str, str], key: str | None = None) -> None:
34+
_param_set(self.host, self.xe_prefix, self.uuid, param_name, value, key)
35+
36+
def param_remove(self, param_name: str, key: str, accept_unknown_key: bool = False) -> None:
37+
_param_remove(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)
38+
39+
def param_add(self, param_name: str, value: str, key: str | None = None) -> None:
40+
_param_add(self.host, self.xe_prefix, self.uuid, param_name, value, key)
41+
42+
def param_clear(self, param_name: str) -> None:
43+
_param_clear(self.host, self.xe_prefix, self.uuid, param_name)
44+
45+
def destroy(self):
46+
logging.info(f"Destroying VLAN: {self.uuid}")
47+
self.host.xe('vlan-destroy', {'uuid': self.uuid})
48+
49+
def tag(self) -> int:
50+
tag = self.param_get('tag')
51+
assert tag
52+
return int(tag)
53+
54+
def tagged_pif(self) -> PIF:
55+
uuid = self.param_get("tagged-PIF")
56+
assert uuid
57+
return PIF(uuid, self.host)
58+
59+
def untagged_pif(self) -> PIF:
60+
uuid = self.param_get("untagged-PIF")
61+
assert uuid
62+
return PIF(uuid, self.host)

0 commit comments

Comments
 (0)