Skip to content

Commit 118822f

Browse files
committed
add traffic rules tests:
- simple VIF rule (add/delete with simple vm.start/destroy cycle) - simple Network rule (add/delete with simple vm.start/destroy cycle) - migrate with simple VIF rule - migrate with Network rule rule - VLAN with simple VIF rule - VLAN with simple Network rule fixtures: - add connected_hosts_with_xo: returns the list of hosts which are already connected to xo-cli - add VLAN fixture: returns a configured VLAN network lib - add VLAN abstraction Signed-off-by: Sebastien Marie <semarie@kapouay.eu.org>
1 parent 457c3a5 commit 118822f

File tree

9 files changed

+657
-1
lines changed

9 files changed

+657
-1
lines changed

conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ def hosts_with_xo(hosts, registered_xo_cli):
267267
logging.info("<<< Disconnect host %s" % h)
268268
h.xo_server_remove()
269269

270+
@pytest.fixture(scope='session')
271+
def connected_hosts_with_xo(hosts: list[Host], registered_xo_cli):
272+
connected = [h for h in hosts if not h.skip_xo_config and h.xo_server_connected()]
273+
yield connected
274+
270275
@pytest.fixture(scope='session')
271276
def hostA1(hosts):
272277
""" Master of first pool (pool A). """

jobs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@
470470
"tests/migration/test_host_evacuate.py::TestHostEvacuateWithNetwork",
471471
# not really broken but has complex prerequisites (3 NICs)
472472
"tests/network/test_bond.py::test_bond",
473+
# not really broken but has complex prerequisites (xo-cli + 2 hosts)
474+
"tests/network/test_traffic_rules.py",
473475
# running quicktest on zfsvol generates dangling TAP devices that are hard to
474476
# cleanup. Bug needs to be fixed before enabling quicktest on zfsvol.
475477
"tests/storage/zfsvol/test_zfsvol_sr.py::TestZfsvolVm::test_quicktest",

lib/host.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from lib.pif import PIF
3838
from lib.sr import SR
3939
from lib.vdi import VDI
40+
from lib.vlan import VLAN
4041
from lib.vm import VM
4142
from lib.xo import xo_cli, xo_object_exists
4243

@@ -808,3 +809,19 @@ def create_network(self, label: str, description: Optional[str] = None) -> Netwo
808809
logging.info(f"New Network: {uuid}")
809810

810811
return Network(self, uuid)
812+
813+
def create_vlan(self, network: Network, pif: PIF, vlan: int) -> VLAN:
814+
args: dict[str, str | bool] = {
815+
'network-uuid': network.uuid,
816+
'pif-uuid': pif.uuid,
817+
'vlan': str(vlan),
818+
}
819+
820+
untagged_pif_uuid = self.xe("vlan-create", args, minimal=True)
821+
uuid = self.xe("pif-param-get", {
822+
"uuid": untagged_pif_uuid,
823+
"param-name": "vlan-master-of",
824+
})
825+
logging.info(f"New VLAN: {uuid} (untagged-pif: {untagged_pif_uuid})")
826+
827+
return VLAN(self, uuid)

lib/network.py

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

5050
def MTU(self) -> int:
5151
return int(self.param_get('MTU') or '0')
52+
53+
def bridge(self) -> str:
54+
bridge = self.param_get('bridge')
55+
assert bridge is not None, "network must have a bridge"
56+
return bridge

lib/pif.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set, strtobool
44

5-
from typing import TYPE_CHECKING
5+
from typing import TYPE_CHECKING, Optional
66

77
if TYPE_CHECKING:
88
from lib.host import Host
@@ -51,6 +51,13 @@ def network_uuid(self) -> str:
5151
assert uuid is not None, "unexpected PIF without network-uuid"
5252
return uuid
5353

54+
def vlan(self) -> Optional[int]:
55+
vlan = self.param_get('VLAN')
56+
if vlan is None:
57+
return None
58+
else:
59+
return int(vlan)
60+
5461
def reconfigure_ip(self, mode: str) -> None:
5562
self.host.xe("pif-reconfigure-ip", {
5663
"uuid": self.uuid,

lib/vif.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22

33
from lib.common import _param_add, _param_clear, _param_get, _param_remove, _param_set
4+
from lib.network import Network
45

56
class VIF:
67
xe_prefix = "vif"
@@ -42,6 +43,11 @@ def mac_address(self) -> str:
4243
assert mac_address is not None, "VIF must have a MAC address"
4344
return mac_address
4445

46+
def network(self) -> Network:
47+
network_uuid = self.param_get('network-uuid')
48+
assert network_uuid is not None, "VIF must have a network-uuid"
49+
return Network(self.vm.host, network_uuid)
50+
4551
def plug(self):
4652
logging.info("Plugging VIF %s on VM %s", self.param_get('device'), self.vm.uuid)
4753
self.vm.host.xe('vif-plug', {'uuid': self.uuid})

lib/vlan.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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
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+
def param_get(self, param_name, key=None, accept_unknown_key=False):
21+
return _param_get(self.host, VLAN.xe_prefix, self.uuid, param_name, key, accept_unknown_key)
22+
23+
def param_set(self, param_name, value, key=None):
24+
_param_set(self.host, VLAN.xe_prefix, self.uuid, param_name, value, key)
25+
26+
def param_add(self, param_name, value, key=None):
27+
_param_add(self.host, VLAN.xe_prefix, self.uuid, param_name, value, key)
28+
29+
def param_clear(self, param_name):
30+
_param_clear(self.host, VLAN.xe_prefix, self.uuid, param_name)
31+
32+
def param_remove(self, param_name, key, accept_unknown_key=False):
33+
_param_remove(self.host, VLAN.xe_prefix, self.uuid, param_name, key, accept_unknown_key)
34+
35+
def destroy(self):
36+
logging.info(f"Destroying VLAN: {self.uuid}")
37+
self.host.xe('vlan-destroy', {'uuid': self.uuid})
38+
39+
def tag(self) -> int:
40+
tag = self.param_get('tag')
41+
assert tag
42+
return int(tag)
43+
44+
def tagged_PIF(self) -> PIF:
45+
uuid = self.param_get("tagged-PIF")
46+
assert uuid
47+
return PIF(uuid, self.host)
48+
49+
def untagged_PIF(self) -> PIF:
50+
uuid = self.param_get("untagged-PIF")
51+
assert uuid
52+
return PIF(uuid, self.host)

tests/network/conftest.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,27 @@ def empty_network(host: Host) -> Generator[Network, None, None]:
2222
finally:
2323
net.destroy()
2424

25+
26+
@pytest.fixture(params=["eth0"])
27+
def vlan_device(request: pytest.FixtureRequest) -> str:
28+
return request.param
29+
30+
@pytest.fixture(params=[0])
31+
def vlan_tag(request: pytest.FixtureRequest) -> int:
32+
return request.param
33+
34+
@pytest.fixture
35+
def vlan(host: Host, empty_network: Network, vlan_tag: int, vlan_device: str):
36+
logging.info(f"vlan: resolve PIF on {host.hostname_or_ip} using \
37+
{[(pif.network_uuid(), pif.param_get('device')) for pif in host.pifs()]}")
38+
39+
[pif] = host.pifs(device=vlan_device)
40+
vlan = host.create_vlan(empty_network, pif, vlan_tag)
41+
try:
42+
yield vlan
43+
finally:
44+
vlan.destroy()
45+
2546
@pytest.fixture(params=[])
2647
def bond_devices(request: pytest.FixtureRequest) -> list[str]:
2748
return request.param

0 commit comments

Comments
 (0)