Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class JobData(TypedDict):
"network-advanced": {
"description": "a group of network tests with complex prerequisites",
"requirements": [
"A pool with at least 1 host.",
"A pool with at least 1 host (if more, with same network configuration).",
"At least 2 free NICs on every host.",
"A small VM that can be imported on the SRs.",
Comment on lines +83 to 85

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is important to mention here that xo_cli is necessary. This PR changes a situation where only one job used to require XO, and now we have another job that requires XO (unless XO was already required by this job previously but not mentioned at the time in the requirements).

Let's add it here to the list of requirements, and I'll make sure it's clear to the team managing CI that this job has such as requirement.

I don't expect any issue, but they need to know.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sent the message. Only remains the need to update the list of requirements.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added XO mention to the jobs entry (in the last commit I pushed).

],
Expand Down
40 changes: 40 additions & 0 deletions lib/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
from lib.network import Network
from lib.pif import PIF
from lib.sr import SR
from lib.tunnel import Tunnel
from lib.vlan import VLAN
from lib.vm import VM
from lib.xo import xo_cli, xo_object_exists

Expand Down Expand Up @@ -716,6 +718,9 @@ def yum_restore_saved_state(self) -> None:
self.saved_packages_list = None
self.saved_rollback_id = None

def service_started(self, name: str) -> bool:
return self.ssh(f'systemctl is-active {name}', check=False) == 'active'

def reboot(self, verify: bool = False) -> None:
logging.info(f"[{self}] Reboot host")
# Running `reboot` directly immediately disconnects the ssh session and makes the ssh client return with an
Expand Down Expand Up @@ -1051,6 +1056,9 @@ def pifs(self, device: str | None = None) -> list[PIF]:

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

def tunnels(self) -> list[Tunnel]:
return [Tunnel(self, uuid) for uuid in safe_split(self.xe("tunnel-list", {}, minimal=True))]

def create_bond(self, network: Network, pifs: list[PIF], mode: str | None = None) -> Bond:
args: dict[str, str | bool | dict[str, str]] = {
'network-uuid': network.uuid,
Expand Down Expand Up @@ -1078,3 +1086,35 @@ def create_network(self, label: str, description: str | None = None) -> Network:
logging.info(f"[{self}] New Network: {uuid}")

return Network(self, uuid)

def create_vlan(self, network: Network, pif: PIF, vlan: int) -> VLAN:
args: dict[str, str | bool | dict[str, str]] = {
'network-uuid': network.uuid,
'pif-uuid': pif.uuid,
'vlan': str(vlan),
}

untagged_pif_uuid = self.xe("vlan-create", args, minimal=True)
uuid = self.xe("pif-param-get", {
"uuid": untagged_pif_uuid,
"param-name": "vlan-master-of",
})
logging.info(f"New VLAN: {uuid} (untagged-pif: {untagged_pif_uuid})")

return VLAN(self, uuid)

def create_tunnel(self, network: Network, pif: PIF, protocol: str) -> Tunnel:
args: dict[str, str | bool | dict[str, str]] = {
'network-uuid': network.uuid,
'pif-uuid': pif.uuid,
'protocol': protocol,
}

access_pif_uuid = self.xe("tunnel-create", args, minimal=True)
uuid = self.xe("pif-param-get", {
"uuid": access_pif_uuid,
"param-name": "tunnel-access-PIF-of",
})
logging.info(f"New Tunnel: {uuid} (access-pif: {access_pif_uuid})")

return Tunnel(self, uuid)
5 changes: 5 additions & 0 deletions lib/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,8 @@ def managed(self) -> bool:

def MTU(self) -> int:
return int(self.param_get('MTU') or '0')

def bridge(self) -> str:
bridge = self.param_get('bridge')
assert bridge is not None, "network must have a bridge"
return bridge
14 changes: 14 additions & 0 deletions lib/pif.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ def network_uuid(self) -> str:
assert uuid is not None, "unexpected PIF without network-uuid"
return uuid

def ip_configuration_mode(self) -> str:
mode = self.param_get("IP-configuration-mode")
assert mode
return mode

def vlan(self) -> int | None:
vlan_str = self.param_get('VLAN')
assert vlan_str
vlan = int(vlan_str)
if vlan == -1:
return None
else:
return vlan

def reconfigure_ip(self, mode: str) -> None:
self.host.xe("pif-reconfigure-ip", {
"uuid": self.uuid,
Expand Down
57 changes: 57 additions & 0 deletions lib/tunnel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from __future__ import annotations

import logging

from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
from lib.pif import PIF

from typing import TYPE_CHECKING, Literal, overload

if TYPE_CHECKING:
from lib.host import Host

class Tunnel:
xe_prefix = "tunnel"

def __init__(self, host: Host, uuid: str):
self.host = host
self.uuid = uuid

@overload
def param_get(self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[False] = ...) -> str:
...

@overload
def param_get(
self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[True] = ...
) -> str | None:
...

def param_get(self, param_name: str, key: str | None = None, accept_unknown_key: bool = False) -> str | None:
return _param_get(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)

def param_set(self, param_name: str, value: str | bool | dict[str, str], key: str | None = None) -> None:
_param_set(self.host, self.xe_prefix, self.uuid, param_name, value, key)

def param_remove(self, param_name: str, key: str, accept_unknown_key: bool = False) -> None:
_param_remove(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)

def param_add(self, param_name: str, value: str, key: str | None = None) -> None:
_param_add(self.host, self.xe_prefix, self.uuid, param_name, value, key)

def param_clear(self, param_name: str) -> None:
_param_clear(self.host, self.xe_prefix, self.uuid, param_name)

def destroy(self):
logging.info(f"Destroying Tunnel: {self.uuid}")
self.host.xe('tunnel-destroy', {'uuid': self.uuid})

def access_pif(self) -> PIF:
uuid = self.param_get("access-PIF")
assert uuid
return PIF(uuid, self.host)

def transport_pif(self) -> PIF:
uuid = self.param_get("transport-PIF")
assert uuid
return PIF(uuid, self.host)
6 changes: 6 additions & 0 deletions lib/vif.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import time

from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
from lib.network import Network

from typing import TYPE_CHECKING, Literal, overload

Expand Down Expand Up @@ -134,3 +135,8 @@ def configure_ipv6(
gateway: str | None = None,
) -> None:
self._configure("ipv6", mode, address, gateway)

def network(self) -> Network:
network_uuid = self.param_get('network-uuid')
assert network_uuid is not None, "VIF must have a network-uuid"
return Network(self.vm.host, network_uuid)
62 changes: 62 additions & 0 deletions lib/vlan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from __future__ import annotations

import logging

from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
from lib.pif import PIF

from typing import TYPE_CHECKING, Literal, overload

if TYPE_CHECKING:
from lib.host import Host

class VLAN:
xe_prefix = "vlan"

def __init__(self, host: Host, uuid: str):
self.host = host
self.uuid = uuid

@overload
def param_get(self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[False] = ...) -> str:
...

@overload
def param_get(
self, param_name: str, key: str | None = ..., accept_unknown_key: Literal[True] = ...
) -> str | None:
...

def param_get(self, param_name: str, key: str | None = None, accept_unknown_key: bool = False) -> str | None:
return _param_get(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)

def param_set(self, param_name: str, value: str | bool | dict[str, str], key: str | None = None) -> None:
_param_set(self.host, self.xe_prefix, self.uuid, param_name, value, key)

def param_remove(self, param_name: str, key: str, accept_unknown_key: bool = False) -> None:
_param_remove(self.host, self.xe_prefix, self.uuid, param_name, key, accept_unknown_key)

def param_add(self, param_name: str, value: str, key: str | None = None) -> None:
_param_add(self.host, self.xe_prefix, self.uuid, param_name, value, key)

def param_clear(self, param_name: str) -> None:
_param_clear(self.host, self.xe_prefix, self.uuid, param_name)

def destroy(self):
logging.info(f"Destroying VLAN: {self.uuid}")
self.host.xe('vlan-destroy', {'uuid': self.uuid})

def tag(self) -> int:
tag = self.param_get('tag')
assert tag
return int(tag)

def tagged_pif(self) -> PIF:
uuid = self.param_get("tagged-PIF")
assert uuid
return PIF(uuid, self.host)

def untagged_pif(self) -> PIF:
uuid = self.param_get("untagged-PIF")
assert uuid
return PIF(uuid, self.host)
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies = [
"pytest-dependency",
"requests",
"ipdb",
"rpm-version>=0.5.1",
]

[dependency-groups]
Expand Down
1 change: 1 addition & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ pytest>=9.1.1
pytest-dependency
requests
ipdb
rpm-version>=0.5.1
Loading