Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
106 changes: 94 additions & 12 deletions tests/network/upgrade/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from collections.abc import Generator
from typing import TYPE_CHECKING

import pytest
from ocp_resources.virtual_machine import VirtualMachine

if TYPE_CHECKING:
from collections.abc import Generator
Comment thread
servolkov marked this conversation as resolved.
Comment thread
servolkov marked this conversation as resolved.
Comment thread
servolkov marked this conversation as resolved.

from kubernetes.dynamic import DynamicClient
from ocp_resources.namespace import Namespace

Expand All @@ -20,10 +21,14 @@
from tests.network.libs import cloudinit
from tests.network.libs.localnet import (
GUEST_1ST_IFACE_NAME,
GUEST_2ND_IFACE_NAME,
LOCALNET_BR_EX_INTERFACE,
LOCALNET_BR_EX_NETWORK,
LOCALNET_OVS_BRIDGE_INTERFACE,
LOCALNET_OVS_BRIDGE_NETWORK,
LOCALNET_TEST_LABEL,
LOCALNET_VM_ANTI_AFFINITY,
create_nncp_localnet_on_secondary_node_nic,
ip_addresses_from_pool,
localnet_cloudinit,
localnet_cudn,
Expand Down Expand Up @@ -211,15 +216,27 @@ def vm_localnet_upgrade_a(
unprivileged_client: DynamicClient,
namespace_localnet_upgrade: Namespace,
cudn_localnet_upgrade: ClusterUserDefinedNetwork,
cudn_dedicated_nic_bridge_localnet_upgrade: ClusterUserDefinedNetwork,
ipv4_localnet_address_pool_upgrade: Generator[str],
ipv6_localnet_address_pool_upgrade: Generator[str],
ipv4_dedicated_nic_bridge_localnet_address_pool_upgrade: Generator[str],
ipv6_dedicated_nic_bridge_localnet_address_pool_upgrade: Generator[str],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
) -> Generator[BaseVirtualMachine]:
with localnet_vm(
namespace=namespace_localnet_upgrade.name,
name="upgrade-localnet-vm-a",
client=unprivileged_client,
networks=[Network(name=LOCALNET_BR_EX_INTERFACE, multus=Multus(networkName=cudn_localnet_upgrade.name))],
interfaces=[Interface(name=LOCALNET_BR_EX_INTERFACE, bridge={})],
networks=[
Network(name=LOCALNET_BR_EX_INTERFACE, multus=Multus(networkName=cudn_localnet_upgrade.name)),
Network(
name=LOCALNET_OVS_BRIDGE_INTERFACE,
multus=Multus(networkName=cudn_dedicated_nic_bridge_localnet_upgrade.name),
),
],
interfaces=[
Interface(name=LOCALNET_BR_EX_INTERFACE, bridge={}),
Interface(name=LOCALNET_OVS_BRIDGE_INTERFACE, bridge={}),
],
cloud_init=localnet_cloudinit(
network_data=cloudinit.NetworkData(
ethernets={
Expand All @@ -229,6 +246,12 @@ def vm_localnet_upgrade_a(
ipv6_pool=ipv6_localnet_address_pool_upgrade,
),
),
GUEST_2ND_IFACE_NAME: cloudinit.EthernetDevice(
addresses=ip_addresses_from_pool(
ipv4_pool=ipv4_dedicated_nic_bridge_localnet_address_pool_upgrade,
ipv6_pool=ipv6_dedicated_nic_bridge_localnet_address_pool_upgrade,
),
),
}
)
),
Expand All @@ -242,15 +265,27 @@ def vm_localnet_upgrade_b(
unprivileged_client: DynamicClient,
namespace_localnet_upgrade: Namespace,
cudn_localnet_upgrade: ClusterUserDefinedNetwork,
cudn_dedicated_nic_bridge_localnet_upgrade: ClusterUserDefinedNetwork,
ipv4_localnet_address_pool_upgrade: Generator[str],
ipv6_localnet_address_pool_upgrade: Generator[str],
ipv4_dedicated_nic_bridge_localnet_address_pool_upgrade: Generator[str],
ipv6_dedicated_nic_bridge_localnet_address_pool_upgrade: Generator[str],
) -> Generator[BaseVirtualMachine]:
with localnet_vm(
namespace=namespace_localnet_upgrade.name,
name="upgrade-localnet-vm-b",
client=unprivileged_client,
networks=[Network(name=LOCALNET_BR_EX_INTERFACE, multus=Multus(networkName=cudn_localnet_upgrade.name))],
interfaces=[Interface(name=LOCALNET_BR_EX_INTERFACE, bridge={})],
networks=[
Network(name=LOCALNET_BR_EX_INTERFACE, multus=Multus(networkName=cudn_localnet_upgrade.name)),
Network(
name=LOCALNET_OVS_BRIDGE_INTERFACE,
multus=Multus(networkName=cudn_dedicated_nic_bridge_localnet_upgrade.name),
),
],
interfaces=[
Interface(name=LOCALNET_BR_EX_INTERFACE, bridge={}),
Interface(name=LOCALNET_OVS_BRIDGE_INTERFACE, bridge={}),
],
cloud_init=localnet_cloudinit(
network_data=cloudinit.NetworkData(
ethernets={
Expand All @@ -260,6 +295,12 @@ def vm_localnet_upgrade_b(
ipv6_pool=ipv6_localnet_address_pool_upgrade,
),
),
GUEST_2ND_IFACE_NAME: cloudinit.EthernetDevice(
addresses=ip_addresses_from_pool(
ipv4_pool=ipv4_dedicated_nic_bridge_localnet_address_pool_upgrade,
ipv6_pool=ipv6_dedicated_nic_bridge_localnet_address_pool_upgrade,
),
),
}
)
),
Expand All @@ -278,11 +319,52 @@ def localnet_running_vms_upgrade(
ip_family for ip_family, enabled in ((4, ipv4_supported_cluster()), (6, ipv6_supported_cluster())) if enabled
]
for vm in (vm_a, vm_b):
lookup_iface_status(
vm=vm,
iface_name=LOCALNET_BR_EX_INTERFACE,
predicate=lambda interface: (
len(filter_link_local_addresses(ip_addresses=interface.get("ipAddresses", []))) == len(ip_families)
),
)
for iface_name in (LOCALNET_BR_EX_INTERFACE, LOCALNET_OVS_BRIDGE_INTERFACE):
lookup_iface_status(
vm=vm,
iface_name=iface_name,
predicate=lambda interface: (
len(filter_link_local_addresses(ip_addresses=interface.get("ipAddresses", []))) == len(ip_families)
),
)
return vm_a, vm_b


@pytest.fixture(scope="session")
def nncp_dedicated_nic_bridge_localnet_upgrade(
nmstate_dependent_placeholder: None,
admin_client: DynamicClient,
hosts_common_available_ports: list[str],
) -> Generator[libnncp.NodeNetworkConfigurationPolicy]:
with create_nncp_localnet_on_secondary_node_nic(
node_nic_name=hosts_common_available_ports[-1],
client=admin_client,
) as nncp:
yield nncp


@pytest.fixture(scope="session")
def cudn_dedicated_nic_bridge_localnet_upgrade(
admin_client: DynamicClient,
nncp_dedicated_nic_bridge_localnet_upgrade: libnncp.NodeNetworkConfigurationPolicy,
namespace_localnet_upgrade: Namespace,
) -> Generator[ClusterUserDefinedNetwork]:
with localnet_cudn(
name=LOCALNET_OVS_BRIDGE_NETWORK,
match_labels=LOCALNET_TEST_LABEL,
vlan_id=cluster_vlans()[0],
Comment thread
servolkov marked this conversation as resolved.
physical_network_name=LOCALNET_OVS_BRIDGE_NETWORK,
client=admin_client,
) as cudn:
cudn.wait_for_status_success()
yield cudn


@pytest.fixture(scope="session")
def ipv4_dedicated_nic_bridge_localnet_address_pool_upgrade() -> Generator[str]:
return (f"{random_ipv4_address(net_seed=1, host_address=host)}/24" for host in range(1, 254))
Comment thread
servolkov marked this conversation as resolved.


@pytest.fixture(scope="session")
def ipv6_dedicated_nic_bridge_localnet_address_pool_upgrade() -> Generator[str]:
return (f"{random_ipv6_address(net_seed=1, host_address=host)}/64" for host in range(1, 254))
90 changes: 80 additions & 10 deletions tests/network/upgrade/test_localnet_connectivity.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""
Localnet connectivity upgrade tests.

Verifies IPAM-less localnet VM connectivity is preserved across cluster upgrades.
Verifies IPAM-less localnet VM connectivity is preserved across cluster upgrades,
for both default bridge (br-ex) and dedicated NIC bridge.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
https://redhat.atlassian.net/browse/CNV-85783

Preconditions:
Comment thread
servolkov marked this conversation as resolved.
- OVN bridge mapping configured via NNCP
- IPAM-less localnet CUDN
- Two running VMs on different nodes with static IPs on localnet
- OVN bridge mapping configured via NNCP for the default bridge (br-ex)
- OVS bridge mapping configured via NNCP on a secondary NIC available on all worker nodes
- IPAM-less localnet CUDNs configured for both default bridge and dedicated NIC bridge
- Two running VMs on different nodes with static IPs on both localnet interfaces
"""

import os
Expand All @@ -17,14 +19,19 @@
from libs.net.ip import filter_link_local_addresses
from libs.net.traffic_generator import client_server_active_connection, is_tcp_connection
from libs.net.vmspec import lookup_iface_status
from tests.network.libs.localnet import LOCALNET_BR_EX_INTERFACE
from tests.network.libs.localnet import LOCALNET_BR_EX_INTERFACE, LOCALNET_OVS_BRIDGE_INTERFACE
from tests.upgrade_params import (
IUO_UPGRADE_TEST_DEPENDENCY_NODE_ID,
IUO_UPGRADE_TEST_ORDERING_NODE_ID,
)
from utilities.constants.pytest import DEPENDENCY_SCOPE_SESSION

BEFORE_UPGRADE_TEST_ID = f"{os.path.abspath(__file__)}::test_default_bridge_localnet_connectivity_before_upgrade"
BEFORE_UPGRADE_DEFAULT_BRIDGE_TEST_ID = (
f"{os.path.abspath(__file__)}::test_default_bridge_localnet_connectivity_before_upgrade"
)
BEFORE_UPGRADE_DEDICATED_NIC_BRIDGE_TEST_ID = (
f"{os.path.abspath(__file__)}::test_dedicated_nic_bridge_localnet_connectivity_before_upgrade"
)

pytestmark = [
pytest.mark.upgrade,
Expand All @@ -34,10 +41,10 @@
]


@pytest.mark.single_nic
@pytest.mark.polarion("CNV-16258")
Comment thread
servolkov marked this conversation as resolved.
@pytest.mark.order(before=IUO_UPGRADE_TEST_ORDERING_NODE_ID)
@pytest.mark.dependency(name=BEFORE_UPGRADE_TEST_ID, scope=DEPENDENCY_SCOPE_SESSION)
# Post-upgrade test depends on this to skip if pre-upgrade connectivity already fails.
@pytest.mark.dependency(name=BEFORE_UPGRADE_DEFAULT_BRIDGE_TEST_ID, scope=DEPENDENCY_SCOPE_SESSION)
def test_default_bridge_localnet_connectivity_before_upgrade(subtests, localnet_running_vms_upgrade):
"""
Preconditions:
Expand All @@ -62,13 +69,41 @@ def test_default_bridge_localnet_connectivity_before_upgrade(subtests, localnet_
assert is_tcp_connection(server=server, client=client)


@pytest.mark.single_nic
@pytest.mark.polarion("CNV-16332")
@pytest.mark.order(before=IUO_UPGRADE_TEST_ORDERING_NODE_ID)
# Post-upgrade test depends on this to skip if pre-upgrade connectivity already fails.
@pytest.mark.dependency(name=BEFORE_UPGRADE_DEDICATED_NIC_BRIDGE_TEST_ID, scope=DEPENDENCY_SCOPE_SESSION)
Comment thread
servolkov marked this conversation as resolved.
def test_dedicated_nic_bridge_localnet_connectivity_before_upgrade(subtests, localnet_running_vms_upgrade):
"""
Preconditions:
- Two running VMs on different nodes with static IPs on localnet over dedicated NIC bridge

Steps:
1. Establish TCP connection between the VMs over localnet.

Expected:
- TCP connection succeeds.
"""
vm_a, vm_b = localnet_running_vms_upgrade
iface = lookup_iface_status(vm=vm_b, iface_name=LOCALNET_OVS_BRIDGE_INTERFACE)
for dst_ip in filter_link_local_addresses(ip_addresses=iface.ipAddresses):
with subtests.test(msg=f"IPv{dst_ip.version}"):
with client_server_active_connection(
client_vm=vm_a,
server_vm=vm_b,
spec_logical_network=LOCALNET_OVS_BRIDGE_INTERFACE,
ip_family=dst_ip.version,
) as (client, server):
assert is_tcp_connection(server=server, client=client)


@pytest.mark.polarion("CNV-16259")
@pytest.mark.order(after=IUO_UPGRADE_TEST_ORDERING_NODE_ID)
# Requires upgrade completion and pre-upgrade baseline connectivity.
@pytest.mark.dependency(
depends=[
IUO_UPGRADE_TEST_DEPENDENCY_NODE_ID,
BEFORE_UPGRADE_TEST_ID,
BEFORE_UPGRADE_DEFAULT_BRIDGE_TEST_ID,
],
scope=DEPENDENCY_SCOPE_SESSION,
)
Expand All @@ -95,3 +130,38 @@ def test_default_bridge_localnet_connectivity_after_upgrade(subtests, localnet_r
ip_family=dst_ip.version,
) as (client, server):
assert is_tcp_connection(server=server, client=client)


@pytest.mark.polarion("CNV-16333")
@pytest.mark.order(after=IUO_UPGRADE_TEST_ORDERING_NODE_ID)
# Requires upgrade completion and pre-upgrade baseline connectivity.
@pytest.mark.dependency(
Comment thread
servolkov marked this conversation as resolved.
depends=[
IUO_UPGRADE_TEST_DEPENDENCY_NODE_ID,
BEFORE_UPGRADE_DEDICATED_NIC_BRIDGE_TEST_ID,
],
scope=DEPENDENCY_SCOPE_SESSION,
)
def test_dedicated_nic_bridge_localnet_connectivity_after_upgrade(subtests, localnet_running_vms_upgrade):
"""
Preconditions:
- Cluster upgraded successfully
- Two running VMs on different nodes with static IPs on localnet over dedicated NIC bridge

Steps:
1. Establish TCP connection between the VMs over localnet.

Expected:
- TCP connection succeeds, connectivity preserved after upgrade.
"""
vm_a, vm_b = localnet_running_vms_upgrade
iface = lookup_iface_status(vm=vm_b, iface_name=LOCALNET_OVS_BRIDGE_INTERFACE)
for dst_ip in filter_link_local_addresses(ip_addresses=iface.ipAddresses):
with subtests.test(msg=f"IPv{dst_ip.version}"):
with client_server_active_connection(
client_vm=vm_a,
server_vm=vm_b,
spec_logical_network=LOCALNET_OVS_BRIDGE_INTERFACE,
ip_family=dst_ip.version,
) as (client, server):
assert is_tcp_connection(server=server, client=client)