Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Openstack cloud tests #179

Merged
merged 19 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7065af3
ovn-tester/ovn_workload: Extract generic methods from WorkerNode class.
fnordahl Oct 4, 2023
8d10c59
ovn-tester/ovn_workload: Extract generic methods from Cluster class.
fnordahl Oct 25, 2023
84e495f
ovn-tester/ovn_workload: Move Namespace class to CMS plugin.
fnordahl Oct 25, 2023
cb528e6
ovn_utils: Additional OVN NB command wrappers.
mkalcok Sep 22, 2023
b7d6a78
ovn_utils: Additional parameters for OvnNbctl methods.
mkalcok Sep 22, 2023
3b0a2bc
CMS: Implementation of Openstack CMS
mkalcok Sep 22, 2023
fc8e54d
CMS Openstack: Basic Openstack cloud scenario
mkalcok Sep 22, 2023
9b8d931
OS Test: Make number of projects configurable.
mkalcok Sep 26, 2023
69cf5d8
CMS Openstack: Evenly distribute GW chassis
mkalcok Sep 26, 2023
64167cb
Cluster: Add full-mesh pinging option
mkalcok Sep 30, 2023
e4e6aab
CMS Openstack: Add ability to simulate VMs
mkalcok Sep 30, 2023
1e987a1
CMS Openstack: Decouple project and ext. network
mkalcok Oct 2, 2023
329d03f
CMS Openstack: Rename chassis config option
mkalcok Oct 3, 2023
6138899
CI: Add task to run low-scale OS test
mkalcok Oct 3, 2023
6b73cca
CI: Use CMS name in the OVN Kubernetes test.
fnordahl Oct 10, 2023
d2815be
cms/openstack: Drop mcast_flood_reports port option.
fnordahl Oct 10, 2023
1817839
cms/openstack: Drop empty requested-chassis for metadata port.
fnordahl Oct 10, 2023
7a90bd7
cms/openstack: Set MTU for VM and GW ports.
fnordahl Oct 10, 2023
799324e
ovn-tester/ovn_workload: Collect stats for `mesh_ping_ports`.
fnordahl Oct 10, 2023
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
630 changes: 614 additions & 16 deletions ovn-tester/cms/ovn_kubernetes/ovn_kubernetes.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/cluster_density.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd
import ovn_exceptions

Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/density_heavy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd
import ovn_load_balancer as lb
import ovn_exceptions
Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/density_light.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd


Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/netpol.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd
from itertools import chain
import ovn_exceptions
Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/netpol_cross_ns.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd

NpCrossNsCfg = namedtuple('NpCrossNsCfg', ['n_ns', 'pods_ns_ratio'])
Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/netpol_multitenant.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections import namedtuple
import netaddr
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd


Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/service_route.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd

import netaddr
Expand Down
50 changes: 9 additions & 41 deletions ovn-tester/ovn_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@
import time

from collections import namedtuple
from ovn_context import Context
from ovn_sandbox import PhysicalNode
from ovn_workload import (
BrExConfig,
CentralNode,
Cluster,
ClusterConfig,
RelayNode,
)
from ovn_utils import DualStackSubnet
from ovs.stream import Stream
Expand Down Expand Up @@ -178,7 +176,7 @@ def load_cms(cms_name):
mod = importlib.import_module(f'cms.{cms_name}')
class_name = getattr(mod, 'OVN_HEATER_CMS_PLUGIN')
cls = getattr(mod, class_name)
return cls()
return cls


def configure_tests(yaml, clusters, global_cfg):
Expand All @@ -196,40 +194,6 @@ def configure_tests(yaml, clusters, global_cfg):
return tests


def create_cluster(cluster_cfg, central, workers, brex_cfg, cms, az):
protocol = "ssl" if cluster_cfg.enable_ssl else "tcp"
db_containers = (
[
f'ovn-central-az{az+1}-1',
f'ovn-central-az{az+1}-2',
f'ovn-central-az{az+1}-3',
]
if cluster_cfg.clustered_db
else [f'ovn-central-az{az+1}-1']
)

mgmt_ip = cluster_cfg.node_net.ip + 2 + az * len(db_containers)
central_nodes = [
CentralNode(central, c, mgmt_ip + i, protocol)
for i, c in enumerate(db_containers)
]

mgmt_ip = (
cluster_cfg.node_net.ip
+ 2
+ cluster_cfg.n_az * len(central_nodes)
+ az * cluster_cfg.n_relays
)
relay_nodes = [
RelayNode(central, f'ovn-relay-az{az+1}-{i+1}', mgmt_ip + i, protocol)
for i in range(cluster_cfg.n_relays)
]

cluster = Cluster(central_nodes, relay_nodes, cluster_cfg, brex_cfg, az)
cms.add_cluster_worker_nodes(cluster, workers, az)
return cluster


def set_ssl_keys(cluster_cfg):
Stream.ssl_set_private_key_file(cluster_cfg.ssl_private_key)
Stream.ssl_set_certificate_file(cluster_cfg.ssl_cert)
Expand All @@ -253,19 +217,23 @@ def set_ssl_keys(cluster_cfg):
):
raise ovn_exceptions.OvnInvalidConfigException()

cms = load_cms(global_cfg.cms_name)
cms_cls = load_cms(global_cfg.cms_name)
central, workers = read_physical_deployment(sys.argv[1], global_cfg)
clusters = [
create_cluster(cluster_cfg, central, workers, brex_cfg, cms, i)
cms_cls(cluster_cfg, central, brex_cfg, i)
for i in range(cluster_cfg.n_az)
]
for c in clusters:
c.add_cluster_worker_nodes(workers)

tests = configure_tests(config, clusters, global_cfg)

if cluster_cfg.enable_ssl:
set_ssl_keys(cluster_cfg)

cms.prepare_test(clusters)
with Context(clusters, 'prepare_test clusters'):
for c in clusters:
c.prepare_test()
for test in tests:
test.run(clusters, global_cfg)
sys.exit(0)
127 changes: 104 additions & 23 deletions ovn-tester/ovn_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import time
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks a lot for adding the type hints!

from collections import namedtuple
from functools import partial
from typing import Dict, List, Optional
import ovsdbapp.schema.open_vswitch.impl_idl as ovs_impl_idl
import ovsdbapp.schema.ovn_northbound.impl_idl as nb_impl_idl
import ovsdbapp.schema.ovn_southbound.impl_idl as sb_impl_idl
Expand Down Expand Up @@ -45,6 +46,7 @@
AddressSet = namedtuple('AddressSet', ['name'])
LoadBalancer = namedtuple('LoadBalancer', ['name', 'uuid'])
LoadBalancerGroup = namedtuple('LoadBalancerGroup', ['name', 'uuid'])
DhcpOptions = namedtuple("DhcpOptions", ["uuid", "cidr"])

DEFAULT_CTL_TIMEOUT = 60

Expand Down Expand Up @@ -436,28 +438,53 @@ def set_inactivity_probe(self, value):
("inactivity_probe", value),
).execute()

def lr_add(self, name):
def lr_add(self, name, ext_ids: Optional[Dict] = None):
ext_ids = {} if ext_ids is None else ext_ids

log.info(f'Creating lrouter {name}')
uuid = self.uuid_transaction(partial(self.idl.lr_add, name))
uuid = self.uuid_transaction(
partial(self.idl.lr_add, name, external_ids=ext_ids)
)
return LRouter(name=name, uuid=uuid)

def lr_port_add(self, router, name, mac, dual_ip=None):
def lr_port_add(
self, router, name, mac, dual_ip=None, ext_ids: Optional[Dict] = None
):
ext_ids = {} if ext_ids is None else ext_ids
dceara marked this conversation as resolved.
Show resolved Hide resolved
networks = []
if dual_ip.ip4 and dual_ip.plen4:
networks.append(f'{dual_ip.ip4}/{dual_ip.plen4}')
if dual_ip.ip6 and dual_ip.plen6:
networks.append(f'{dual_ip.ip6}/{dual_ip.plen6}')

self.idl.lrp_add(router.uuid, name, str(mac), networks).execute()
self.idl.lrp_add(
router.uuid, name, str(mac), networks, external_ids=ext_ids
).execute()
return LRPort(name=name, mac=mac, ip=dual_ip)

def lr_port_set_gw_chassis(self, rp, chassis, priority=10):
log.info(f'Setting gw chassis {chassis} for router port {rp.name}')
self.idl.lrp_set_gateway_chassis(rp.name, chassis, priority).execute()

def ls_add(self, name, net_s):
def ls_add(
self,
name: str,
net_s: DualStackSubnet,
ext_ids: Optional[Dict] = None,
other_config: Optional[Dict] = None,
) -> LSwitch:
ext_ids = {} if ext_ids is None else ext_ids
other_config = {} if other_config is None else other_config

log.info(f'Creating lswitch {name}')
uuid = self.uuid_transaction(partial(self.idl.ls_add, name))
uuid = self.uuid_transaction(
partial(
self.idl.ls_add,
name,
external_ids=ext_ids,
other_config=other_config,
)
)
return LSwitch(
name=name,
cidr=net_s.n4,
Expand All @@ -478,17 +505,18 @@ def ls_get_uuid(self, name, timeout):

def ls_port_add(
self,
lswitch,
name,
router_port=None,
mac=None,
ip=None,
gw=None,
ext_gw=None,
metadata=None,
passive=False,
security=False,
localnet=False,
lswitch: LSwitch,
name: str,
router_port: Optional[LRPort] = None,
mac: Optional[str] = None,
ip: Optional[DualStackIP] = None,
gw: Optional[DualStackIP] = None,
ext_gw: Optional[DualStackIP] = None,
metadata=None, # typehint: ovn_workload.ChassisNode
passive: bool = False,
security: bool = False,
localnet: bool = False,
ext_ids: Optional[Dict] = None,
):
columns = dict()
if router_port:
Expand All @@ -512,6 +540,9 @@ def ls_port_add(
if security:
columns["port_security"] = addresses

if ext_ids is not None:
columns["external_ids"] = ext_ids

uuid = self.uuid_transaction(
partial(self.idl.lsp_add, lswitch.uuid, name, **columns)
)
Expand Down Expand Up @@ -545,7 +576,15 @@ def ls_port_add(
def ls_port_del(self, port):
self.idl.lsp_del(port.name).execute()

def ls_port_set_set_options(self, port, options):
def ls_port_set_set_options(self, port: LSPort, options: str):
"""Set 'options' column for Logical Switch Port.

:param port: Logical Switch Port to modify
:param options: Space-separated key-value pairs that are set as
options. Keys and values are separated by '='.
i.e.: 'opt1=val1 opt2=val2'
:return: None
"""
opts = dict(
(k, v)
for k, v in (element.split("=") for element in options.split())
Expand All @@ -555,14 +594,32 @@ def ls_port_set_set_options(self, port, options):
def ls_port_set_set_type(self, port, lsp_type):
self.idl.lsp_set_type(port.name, lsp_type).execute()

def port_group_create(self, name):
self.idl.pg_add(name).execute()
def ls_port_enable(self, port: LSPort) -> None:
"""Set Logical Switch Port's state to 'enabled'."""
self.idl.lsp_set_enabled(port.name, True).execute()

def ls_port_set_ipv4_address(self, port: LSPort, addr: str) -> LSPort:
mkalcok marked this conversation as resolved.
Show resolved Hide resolved
"""Set Logical Switch Port's IPv4 address.

:param port: LSPort to modify
:param addr: IPv4 address to set
:return: Modified LSPort object with updated 'ip' attribute
"""
addresses = [f"{port.mac} {addr}"]
log.info(f"Setting addresses for port {port.uuid}: {addresses}")
self.idl.lsp_set_addresses(port.uuid, addresses).execute()

return port._replace(ip=addr)

def port_group_create(self, name, ext_ids: Optional[Dict] = None):
ext_ids = {} if ext_ids is None else ext_ids
self.idl.pg_add(name, external_ids=ext_ids).execute()
return PortGroup(name=name)

def port_group_add(self, pg, lport):
self.idl.pg_add_ports(pg.name, lport.uuid).execute()

def port_group_add_ports(self, pg, lports):
def port_group_add_ports(self, pg: PortGroup, lports: List[LSPort]):
MAX_PORTS_IN_BATCH = 500
for i in range(0, len(lports), MAX_PORTS_IN_BATCH):
lports_slice = lports[i : i + MAX_PORTS_IN_BATCH]
Expand Down Expand Up @@ -601,14 +658,16 @@ def acl_add(
entity="switch",
match="",
verdict="allow",
ext_ids: Optional[Dict] = None,
):
ext_ids = {} if ext_ids is None else ext_ids
if entity == "switch":
self.idl.acl_add(
name, direction, priority, match, verdict
name, direction, priority, match, verdict, **ext_ids
).execute()
else: # "port-group"
self.idl.pg_acl_add(
name, direction, priority, match, verdict
name, direction, priority, match, verdict, **ext_ids
).execute()

def route_add(self, router, network, gw, policy="dst-ip"):
Expand Down Expand Up @@ -708,6 +767,28 @@ def lb_remove_from_switches(self, lb, switches):
for s in switches:
txn.add(self.idl.ls_lb_del(s, lb.uuid, if_exists=True))

def create_dhcp_options(
self, cidr: str, ext_ids: Optional[Dict] = None
) -> DhcpOptions:
"""Create entry in DHCP_Options table.

:param cidr: DHCP address pool (i.e. '192.168.1.0/24')
:param ext_ids: Optional entries to 'external_ids' column
:return: DhcpOptions object
"""
ext_ids = {} if ext_ids is None else ext_ids

log.info(f"Creating DHCP Options for {cidr}. External IDs: {ext_ids}")
add_command = self.idl.dhcp_options_add(cidr, **ext_ids)
add_command.execute()

return DhcpOptions(add_command.result.uuid, cidr)

def dhcp_options_set_options(self, uuid_: str, options: Dict) -> None:
"""Set 'options' column for 'DHCP_Options' entry."""
log.info(f"Setting DHCP options for {uuid_}: {options}")
self.idl.dhcp_options_set_options(uuid_, **options).execute()

def sync(self, wait="hv", timeout=DEFAULT_CTL_TIMEOUT):
with self.idl.transaction(
check_error=True, timeout=timeout, wait_type=wait
Expand Down
Loading