Migrate sriov provider and routed prov net tests

Moved downstream tests with minor adjustments, changed uuids.
Added a config value to disable/enable the tests when needed.
Reimplemented function that retrieves data from nova database
in order to fit podified environment.
All tests will be skipped on devstack environments.

Change-Id: I4557207e397271430ec209a44d0ff62e5cf5116b
This commit is contained in:
Roman Safronov 2024-03-22 01:08:14 +02:00
parent ca0fa6fe11
commit 9bb38100ba
3 changed files with 1341 additions and 5 deletions

View File

@ -264,12 +264,13 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
@classmethod
def get_pod_of_service(cls, service='neutron'):
# (rsafrono) at this moment only neutron service pod handled
# since it's the only that existing tests are using
pods_list = "oc get pods"
if service == 'neutron':
return cls.proxy_host_client.exec_command(
"oc get pods | grep neutron | grep -v meta | "
"cut -d' ' -f1").strip()
filters = "grep neutron | grep -v meta | cut -d' ' -f1"
else:
filters = "grep {} | cut -d' ' -f1".format(service)
return cls.proxy_host_client.exec_command(
"{} | {}".format(pods_list, filters)).strip()
@classmethod
def get_configs_of_service(cls, service='neutron'):

View File

@ -0,0 +1,851 @@
# Copyright 2024 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import re
import time
import netaddr
from neutron_lib import constants as lib_constants
from neutron_tempest_plugin.common import ssh
from neutron_tempest_plugin import config
from neutron_tempest_plugin.scenario import constants
from oslo_log import log
from oslo_serialization import jsonutils
from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import exceptions
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
import testtools
from whitebox_neutron_tempest_plugin.common import utils
from whitebox_neutron_tempest_plugin.tests.scenario import base
CONF = config.CONF
WB_CONF = config.CONF.whitebox_neutron_plugin_options
LOG = log.getLogger(__name__)
class ProviderNetworkSriovBaseTest(base.ProviderBaseTest):
"""Base class for SRIOV tests using provisioning networks
Admin user is needed to create ports on the existing provisioning network
"""
MAC_RE = re.compile(r'([0-9a-f]{2}(?::[0-9a-f]{2}){5})', re.IGNORECASE)
# Interface names might match any of these patterns
# Examples:
# 1) PF: p5p7, p2p1; VF: p5p7_2, p2p1_0
# 2) PF: enp6s0f3, enp1s1f2; VF: enp6s0f3v4, enp1s1f2v1
# 3) PF: enp6s0, enp1s1; VF: enp6s0v4, enp1s1v1
PF_NAME_REGEX1 = re.compile(r'p\d+p\d+')
VF_NAME_SEPARATOR1 = '_'
PF_NAME_REGEX2 = re.compile(r'enp\d+s\d+f\d+')
VF_NAME_SEPARATOR2 = 'v'
PF_NAME_REGEX3 = re.compile(r'enp\d+s\d+')
VF_NAME_SEPARATOR3 = 'v'
PF_VF_REGEX_LIST = [{'pf_name_regex': PF_NAME_REGEX1,
'vf_name_separator': VF_NAME_SEPARATOR1},
{'pf_name_regex': PF_NAME_REGEX2,
'vf_name_separator': VF_NAME_SEPARATOR2},
{'pf_name_regex': PF_NAME_REGEX3,
'vf_name_separator': VF_NAME_SEPARATOR3}]
@classmethod
def skip_checks(cls):
super(ProviderNetworkSriovBaseTest, cls).skip_checks()
if not (CONF.neutron_plugin_options.advanced_image_ref or
CONF.neutron_plugin_options.default_image_is_advanced):
raise cls.skipException(
'Advanced image is required to run these tests.')
if WB_CONF.openstack_type == 'devstack':
raise cls.skipException("The tests are currently not supported "
"on devstack environment")
@classmethod
def setup_clients(cls):
super(ProviderNetworkSriovBaseTest, cls).setup_clients()
cls.client = cls.os_adm.network_client
cls.keypairs_client = cls.os_adm.keypairs_client
cls.servers_client = cls.os_adm.servers_client
@classmethod
def resource_setup(cls):
super(ProviderNetworkSriovBaseTest, cls).resource_setup()
if not cls.has_sriov_support:
raise cls.skipException("Skipped because SRIOV is not supported")
# info about SRIOV MACs
cls._get_initial_sriov_macs()
# initialize mysql nova command
cls._get_nova_db_cmd()
# verify number of available VF and PF before tests start
cls._check_vfpf_nova_db()
# set image and flavor in case default image is not advanced
if not CONF.neutron_plugin_options.default_image_is_advanced:
cls.flavor_ref = \
CONF.neutron_plugin_options.advanced_image_flavor_ref
cls.image_ref = CONF.neutron_plugin_options.advanced_image_ref
cls.username = CONF.neutron_plugin_options.advanced_image_ssh_user
@classmethod
def _get_nova_db_cmd(cls):
# check that number of available VF and PF ports is correct before
# any server has been created
# (rsafrono) This code below experimental.
# I tried to avoid hard-coding existing cell1 that exist on VA1
# podified environment since the name can probably change
# or more than one cell will be supported in the future
nova_scheduler_pod = cls.get_pod_of_service("nova-scheduler")
cells = cls.proxy_host_client.exec_command(
"oc rsh {} nova-manage cell_v2 list_hosts | grep compute | "
"tr -d '|' | tr -s ' ' ".format(nova_scheduler_pod) + "| "
"awk '{print $1}' | uniq").strip().split()
if len(cells) != 1:
cls.fail("Currently only environments with a single cell "
"are supported")
galera_pod = cls.get_pod_of_service(
'openstack-{}-galera-0'.format(cells[0]))
galera_db_exec = "oc rsh {}".format(galera_pod)
data_filter = ".data.Nova{}DatabasePassword|base64decode".format(
cells[0].capitalize())
db_password = cls.proxy_host_client.exec_command(
"oc get secret osp-secret -o go-template --template="
"\"{{" + data_filter + "}}\"").strip()
db_credentials = "-u root -p{}".format(db_password)
mysql_cmd = ('mysql --skip-column-names {} nova_{} -e '
'"select pci_stats from compute_nodes;"'.format(
db_credentials, cells[0]))
cls.nova_db_cmd = "{} {} ".format(galera_db_exec, mysql_cmd)
@classmethod
def _check_vfpf_nova_db(cls, timeout=60, interval=5):
def _get_nova_objects():
output = cls.run_on_master_controller(cls.nova_db_cmd)
LOG.debug("pci_stats obtained from nova DB:")
LOG.debug(output)
output_rows = output.splitlines()
# number of expected rows equals number of compute nodes
assert (len(output_rows) == CONF.compute.min_compute_nodes)
nova_objects = [
jsonutils.loads(row)['nova_object.data']['objects']
for row in output_rows
]
return nova_objects
# check all PF and all VF are available
db_checkings = []
start = time.time()
while time.time() - start < timeout:
nova_objects = _get_nova_objects()
db_checkings = [False for i in range(len(nova_objects))]
for i, nova_object in enumerate(nova_objects):
# each nova_object includes:
# - an entry with information about the available PF ports
# - an entry for each PF port, with information about their
# available VF ports
bool_nova_objects = len(nova_object) == (
WB_CONF.sriov_pfs_per_host + 1)
# initialize other booleans to False
pf_bool_count = False
vf_bool_count = False
pf_found = False
vf_found = False
for pci_device_pool in nova_object:
dev_type = pci_device_pool['nova_object.data']['tags'][
'dev_type']
count = pci_device_pool['nova_object.data']['count']
if dev_type == 'type-PF':
pf_found = True
# expected available PF ports
pf_bool_count = count == WB_CONF.sriov_pfs_per_host
elif dev_type == 'type-VF':
vf_found = True
# expected available VF ports
vf_bool_count = count == WB_CONF.sriov_vfs_per_pf
else:
raise RuntimeError('Unexpected dev_type %s' % dev_type)
db_checkings[i] = (bool_nova_objects and pf_bool_count and
vf_bool_count and pf_found and vf_found)
if not all(checking for checking in db_checkings):
time.sleep(interval)
else:
break
# TODO(eolivare): uncomment this assert when rhbz#2101328 is resolved
# assert(db_checkings and all(checking for checking in db_checkings))
@classmethod
def _get_initial_sriov_macs(cls):
cls.sriov_macs = {}
compute_nodes = [node for node in cls.nodes
if node['is_compute'] is True]
cls.compute_ssh_clients = {}
for node in compute_nodes:
cls.sriov_macs[node['name']] = []
cls.compute_ssh_clients.update(
{node['name']: node['client']})
nova_config_path = (
'/var/lib/config-data/nova_libvirt/etc/nova/nova.conf')
passthrough_whitelist_str = node['client'].exec_command(
('sudo cat %s | grep "^passthrough_whitelist" | '
'cut -d"=" -f2') % nova_config_path)
for line in passthrough_whitelist_str.splitlines():
passthrough_whitelist = eval(line.rstrip())
pf_name = passthrough_whitelist.get('devname')
trusted = passthrough_whitelist.get('trusted', 'false')
cmd_pf = 'PATH=$PATH:/usr/sbin ip link show %s' % pf_name
try:
output_pf = node['client'].exec_command(
cmd_pf).rstrip()
except lib_exc.SSHExecCommandFailed:
# This interface does not exist on current compute node
continue
else:
# Multiple SRIOV interfaces can be found per compute node
cls.sriov_macs[node['name']].append({
'pf_name': pf_name,
'trusted': trusted})
mac_pf = re.findall(cls.MAC_RE, output_pf)[0]
cls.sriov_macs[node['name']][-1].update(
{pf_name: mac_pf})
# Obtain MAC for each VF associated to the PF
for i in range(WB_CONF.sriov_vfs_per_pf):
cmd_vf = None
for pf_vf_regex in cls.PF_VF_REGEX_LIST:
if pf_vf_regex['pf_name_regex'].findall(pf_name):
cmd_vf = (cmd_pf +
pf_vf_regex['vf_name_separator'] +
str(i))
if cmd_vf is None:
raise RuntimeError('Unexpected pf_name %s' % pf_name)
output_vf = node['client'].exec_command(
cmd_vf).rstrip()
mac_vf = re.findall(cls.MAC_RE, output_vf)[0]
cls.sriov_macs[node['name']][-1].update(
{cmd_vf.split()[-1]: mac_vf})
def check_port_status(self, port_type,
port_index=-1, server_index=-1):
port_details = (super(ProviderNetworkSriovBaseTest, self)
.check_port_status(port_type,
port_index,
server_index))
self._check_port_mac(port_details=port_details,
port_index=port_index,
server_index=server_index)
@classmethod
def resource_cleanup(cls):
super(ProviderNetworkSriovBaseTest, cls).resource_cleanup()
# verify number of available VF and PF after tests end
cls._check_vfpf_nova_db()
def _test_create_instance_with_network_port(self, port_type,
vm_name=None,
reuse_port=False):
security_groups, port, user_data, config_drive = \
self._create_network_port(port_type,
reuse_port=reuse_port,
use_provider_net=True)
vm_name = vm_name or "vm-" + port_type + "-" + self._testMethodName
self._create_server(
security_groups=security_groups, networks=[port],
user_data=user_data, config_drive=config_drive,
name=vm_name)
def _test_create_instance_with_two_ports(self, port_types, cidr,
vm_name=None,
reused_tenant_net=None):
"""Two ports will be used for each VM. The first one will be connected
to the existing provider network and the second one to a tenant network
"""
# Fist, create external port (connected to provider network)
_, port1, user_data, config_drive = \
self._create_network_port(port_types[0],
use_provider_net=True)
# Second, create internal port (connected to tenant network)
# This port should not have a default route, hence its subnet is
# created without a default gateway
_, port2, user_data, config_drive = \
self._create_network_port(port_types[1],
use_provider_net=False,
reused_tenant_net=reused_tenant_net,
cidr=cidr,
gateway=False)
vm_name = vm_name or "vm-" + self._testMethodName
self._create_server(
networks=[port1, port2], user_data=user_data,
config_drive=config_drive, name=vm_name)
def _test_instance_with_one_port_prov_net(self, port_type):
self._test_create_instance_with_network_port(port_type)
self.check_connectivity(self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
def _check_port_mac(self, port_details, port_index=-1, server_index=-1):
# MAC obtained via OSP API after server creation/migration/reboot
port_mac_api = port_details['mac_address']
# Initial port MAC assigned by neutron at port creation
mac_neutron_port_creation = self.ports[port_index]['mac_address']
# MAC obtained from VM instance
vm_ip = port_details['fixed_ips'][0]['ip_address']
cmd = 'PATH=$PATH:/usr/sbin ; ip link show %s' % \
WB_CONF.default_instance_interface
vm_ssh_client = ssh.Client(vm_ip,
self.username,
pkey=self.keypair['private_key'])
output = vm_ssh_client.exec_command(cmd).rstrip()
vm_mac = re.findall(self.MAC_RE, output)[0]
self.assertEqual(port_mac_api, vm_mac)
# MAC obtained from hypervisor
server_id = self.servers[server_index]['id']
host = self.servers_client.show_server(
server_id)['server']['OS-EXT-SRV-ATTR:host'].split('.')[0]
host_macs = self.sriov_macs[host]
if port_details['binding:vnic_type'] in ('direct', 'macvtap'):
vf_pci_slot = port_details['binding:profile']['pci_slot']
vf_id = vf_pci_slot.split('.')[-1]
pf_name = self._get_pf_name_from_vf(host, vf_pci_slot)
host_macs_this_pf = None
for host_macs_item in host_macs:
if host_macs_item['pf_name'] == pf_name:
host_macs_this_pf = host_macs_item
self.assertIsNotNone(host_macs_this_pf)
if host_macs_this_pf['trusted'].lower() == 'true':
# Verify initial neutron MAC has not changed
self.assertEqual(port_mac_api, mac_neutron_port_creation)
# Updated VF MAC value applies when trusted (neutron applies
# its own MAC value to the interface)
vf_mac = self._get_updated_sriov_mac(host, host_macs_this_pf,
vf_id=vf_id)
else:
# Verify initial neutron MAC has changed
self.assertNotEqual(port_mac_api, mac_neutron_port_creation)
# Initial VF MAC value applies when not trusted
vf_name = None
for pf_vf_regex in self.PF_VF_REGEX_LIST:
if pf_vf_regex['pf_name_regex'].findall(pf_name):
vf_name = (pf_name +
pf_vf_regex['vf_name_separator'] +
vf_id)
if vf_name is None:
raise RuntimeError('Unexpected pf_name %s' % pf_name)
vf_mac = host_macs_this_pf[vf_name]
self.assertEqual(port_mac_api, vf_mac)
elif 'direct-physical' == port_details['binding:vnic_type']:
# Verify initial neutron MAC has changed
self.assertNotEqual(port_mac_api, mac_neutron_port_creation)
# Initial PF MAC value applies
pf_macs = [host_macs_item[host_macs_item['pf_name']]
for host_macs_item in host_macs]
self.assertIn(port_mac_api, pf_macs)
# HV MAC does not need to be validated for normal ports
def _get_updated_sriov_mac(self, host, host_macs, vf_id=None):
compute_ssh_client = self.compute_ssh_clients[host]
cmd = 'PATH=$PATH:/usr/sbin ; ip link show %s' % host_macs['pf_name']
if vf_id is not None:
cmd += ' | grep "vf %s"' % vf_id
output = compute_ssh_client.exec_command(cmd).rstrip()
mac = re.findall(self.MAC_RE, output)[0]
return mac
def _get_pf_name_from_vf(self, host, vf_pci_slot):
compute_ssh_client = self.compute_ssh_clients[host]
cmd = 'ls /sys/bus/pci/devices/%s/physfn/net' % vf_pci_slot
output = compute_ssh_client.exec_command(cmd).rstrip()
return output
class OneServerProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""Class for tests creating one VM with one SRIOV port on provisioning
networks
These tests can be executed without needing to cleanup VMs or ports between
them
"""
@decorators.idempotent_id('bd4d51e7-49d3-4b56-9ef6-7ba68761d122')
def test_create_instance_with_normal_port_prov_net(self):
self._test_instance_with_one_port_prov_net('normal')
@decorators.idempotent_id('a6df084c-b1ff-46a8-a269-47d3008c0572')
def test_create_instance_with_direct_port_prov_net(self):
self._test_instance_with_one_port_prov_net('direct')
@decorators.idempotent_id('fef94a15-ddf5-4094-9b3f-ecac370dafad')
def test_create_instance_with_direct_physical_port_prov_net(self):
self._test_instance_with_one_port_prov_net('direct-physical')
@decorators.idempotent_id('3f3a4ec4-9a92-41d3-836c-59b5809d1d18')
def test_create_instance_with_macvtap_port_prov_net(self):
self._test_instance_with_one_port_prov_net('macvtap')
class ExtraDhcpOptsSriovTest(ProviderNetworkSriovBaseTest):
"""Class for tests creating one VM with one SRIOV port on provisioning
networks using extra_dhcp_options parameter at port creation
These tests can be executed without needing to cleanup VMs or ports between
them
"""
required_extensions = ['extra_dhcp_opt']
extra_dhcp_opts = [
{'opt_value': '8.8.8.8',
'opt_name': 'dns-server',
'ip_version': lib_constants.IP_VERSION_4},
{'opt_value': '1600',
'opt_name': 'mtu'}]
def _validate_dhcp_opts(self):
vm_ip = self.ports[-1]['fixed_ips'][0]['ip_address']
vm_ssh_client = ssh.Client(vm_ip,
self.username,
pkey=self.keypair['private_key'])
if self.ports[-1]['binding:vnic_type'] == 'direct-physical':
network_id = self.ports[-1]['network_id']
vlan = self.client.show_network(
network_id)['network']['provider:segmentation_id']
else:
vlan = None
obtained_dhcp_options = utils.parse_dhcp_options_from_nmcli(
vm_ssh_client, lib_constants.IP_VERSION_4, vlan=vlan)
for extra_dhcp_opt in self.extra_dhcp_opts:
self.assertIn(extra_dhcp_opt['opt_name'], obtained_dhcp_options)
self.assertEqual(extra_dhcp_opt['opt_value'],
obtained_dhcp_options[extra_dhcp_opt['opt_name']])
@decorators.idempotent_id('5f676e8a-3d74-49c7-ab87-1679b9b7155a')
def test_extra_dhcp_opts_direct_port(self):
self._test_instance_with_one_port_prov_net('direct')
self._validate_dhcp_opts()
@decorators.idempotent_id('0bd26a9e-9c0f-40e4-a317-374ef48ac5b6')
def test_extra_dhcp_opts_direct_physical_port(self):
self._test_instance_with_one_port_prov_net('direct-physical')
self._validate_dhcp_opts()
@decorators.idempotent_id('667df5dd-9302-4bfd-8d8c-7326abff2bb6')
def test_extra_dhcp_opts_macvtap_port(self):
self._test_instance_with_one_port_prov_net('macvtap')
self._validate_dhcp_opts()
class RebootServerProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""Class for SRIOV test that creates VM instances with different SRIOV port
types, reboot those instances and checks their behavior is correct after
reboot
"""
@decorators.idempotent_id('a44deae1-2f84-48fd-a644-faf6390e88e7')
def test_reboot_vm_with_sriov_port_prov_net(self):
for port_type in ('direct', 'direct-physical'):
self._test_instance_with_one_port_prov_net(port_type)
for reboot_type in ('SOFT', 'HARD'):
self.servers_client.reboot_server(self.servers[-1]['id'],
type=reboot_type)
waiters.wait_for_server_status(self.servers_client,
self.servers[-1]['id'],
constants.SERVER_STATUS_ACTIVE)
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
class UnshelveServerProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""Class for SRIOV test that creates VM instances with different SRIOV port
types, shelves those instances, unshelves them and checks their behavior
is correct after unshelve
"""
@decorators.idempotent_id('7b9d6590-c61e-46e1-834b-c02e6be71866')
def test_unshelve_vm_with_sriov_port_prov_net(self):
# TODO(eolivare): remove the skip exception once the BZ is fixed
raise self.skipException("Not supported due to BZ1767797")
offload_time = CONF.compute.shelved_offload_time
for port_type in ('direct', 'direct-physical'):
self._test_instance_with_one_port_prov_net(port_type)
self.servers_client.shelve_server(self.servers[-1]['id'])
waiters.wait_for_server_status(self.servers_client,
self.servers[-1]['id'],
'SHELVED_OFFLOADED',
extra_timeout=offload_time)
self.servers_client.unshelve_server(self.servers[-1]['id'])
waiters.wait_for_server_status(self.servers_client,
self.servers[-1]['id'],
constants.SERVER_STATUS_ACTIVE)
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
class ReusePortProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""Class for SRIOV test that creates VM instances with different SRIOV port
types, delete those instances and reuse the existing SRIOV ports on new VM
instances
"""
@decorators.idempotent_id('9ad4aed9-0985-49fa-886e-fa6286a26492')
def test_reuse_sriov_port_prov_net(self):
# TODO(eolivare): only VF ports supported at this moment
# for port_type in ('direct', 'direct-physical'):
for port_type in ('direct',):
self._test_instance_with_one_port_prov_net(port_type)
old_port_id = self.ports[-1]['id']
old_num_ports = len(self.ports)
# delete the server and create a new server attached to the
# existing port
self.servers_client.delete_server(self.servers[-1]['id'])
waiters.wait_for_server_termination(self.servers_client,
self.servers[-1]['id'])
del self.servers[-1]
# validate port is not reachable anymore
self.assertRaises(
lib_exc.SSHTimeout,
self.check_connectivity,
host=self.ports[-1]['fixed_ips'][0]['ip_address'],
ssh_user=self.username,
ssh_key=self.keypair['private_key'],
ssh_timeout=10)
# create a new server reusing the existing port
self._test_create_instance_with_network_port(
port_type, reuse_port=True)
# check no new ports have been created
self.assertEqual(old_num_ports, len(self.ports))
self.assertEqual(old_port_id, self.ports[-1]['id'])
# validate port is reachable again
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
@decorators.idempotent_id('6a382f97-50ea-4a1b-b012-aaa955f1a51a')
def test_detach_attach_sriov_port_prov_net(self):
interfaces_client = self.os_adm.interfaces_client
# TODO(eolivare): only VF ports supported at this moment
# for port_type in ('direct', 'direct-physical'):
for port_type in ('direct',):
self._test_instance_with_one_port_prov_net(port_type)
old_port_id = self.ports[-1]['id']
old_num_ports = len(self.ports)
# remove port from server
req_id = interfaces_client.delete_interface(
self.servers[-1]['id'],
self.ports[-1]['id']).response['x-openstack-request-id']
# wait until port is really removed
waiters.wait_for_interface_detach(
self.servers_client,
self.servers[-1]['id'],
self.ports[-1]['id'],
req_id)
# validate port is not reachable anymore
self.assertRaises(
lib_exc.SSHTimeout,
self.check_connectivity,
host=self.ports[-1]['fixed_ips'][0]['ip_address'],
ssh_user=self.username,
ssh_key=self.keypair['private_key'],
ssh_timeout=10)
# reattach port on a new server (reattaching to a running VM is
# not supported)
self._test_create_instance_with_network_port(
port_type, reuse_port=True)
# check no new ports have been created
self.assertEqual(old_num_ports, len(self.ports))
self.assertEqual(old_port_id, self.ports[-1]['id'])
# validate port is reachable again
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
class NegativeProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""Assuming we have hosts with one SRIOV port and it is already occupied,
then creation of VM with VF or PF port should fail
We create a VM with PF port on each compute node in order to occupy SRIOV
port; creating VM with PF or VF should fail as there is no available port
"""
@decorators.idempotent_id('3cf78b03-c88d-41c3-a891-d446518aca9f')
def test_try_create_instance_with_sriov_port(self):
for i in range(CONF.compute.min_compute_nodes *
WB_CONF.sriov_pfs_per_host):
self._test_create_instance_with_network_port('direct-physical')
for port_type in ('direct-physical', 'direct'):
vm_name = 'vm-%s-error' % port_type
self.assertRaises(
exceptions.BuildErrorException,
self._test_create_instance_with_network_port,
port_type=port_type,
vm_name=vm_name)
class TwoServersProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""Base class for SRIOV tests creating two VMs with one SRIOV port on
provisioning networks
"""
def _test_create_two_instances_with_ports(self, port_type1, port_type2):
self._test_create_instance_with_network_port(port_type1)
ip1 = self.ports[-1]['fixed_ips'][0]['ip_address']
self._test_create_instance_with_network_port(port_type2)
ip2 = self.ports[-1]['fixed_ips'][0]['ip_address']
for ip in (ip1, ip2):
self.check_connectivity(ip,
self.username,
self.keypair['private_key'])
server_ssh_client = remote_client.RemoteClient(
ip1,
self.username,
pkey=self.keypair['private_key'], server=self.servers[0])
server_ssh_client.ping_host(ip2)
class NormalAndOtherServersProvNetSriovTest(TwoServersProvNetSriovTest):
"""The following tests can be executed without needing to cleanup between
them because in total one normal, one VF and one PF ports are created
"""
@decorators.idempotent_id('61a19404-b819-4451-b4a6-d834bed6f3e9')
def test_create_instances_with_normal_normal_ports_prov_net(self):
self._test_create_two_instances_with_ports('normal', 'normal')
@decorators.idempotent_id('060c08ed-dc11-41e3-a2aa-1b28702986f2')
def test_create_instances_with_normal_vf_ports_prov_net(self):
self._test_create_two_instances_with_ports('direct', 'normal')
@decorators.idempotent_id('c12bee5f-7d11-425c-b75e-1a198793d7b0')
def test_create_instances_with_normal_pf_ports_prov_net(self):
self._test_create_two_instances_with_ports('direct-physical', 'normal')
class VfServersProvNetSriovTest(TwoServersProvNetSriovTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after its execution)
"""
@decorators.idempotent_id('97c176c7-f1a0-45d5-879f-e8715b320d06')
def test_create_instances_with_vf_vf_ports_prov_net(self):
self._test_create_two_instances_with_ports('direct', 'direct')
class VfAndPfServersProvNetSriovTest(TwoServersProvNetSriovTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after its execution)
"""
@decorators.idempotent_id('98f8b841-8193-4b68-90e5-030879cbf774')
def test_create_instances_with_vf_pf_ports_prov_net(self):
self._test_create_two_instances_with_ports('direct', 'direct-physical')
class PfServersProvNetSriovTest(TwoServersProvNetSriovTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after it)
"""
@decorators.idempotent_id('935fb660-763f-4393-a780-f519c8f7dc95')
def test_create_instances_with_pf_pf_ports_prov_net(self):
self._test_create_two_instances_with_ports('direct-physical',
'direct-physical')
class BaseMigrationProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""Class for SRIOV test that verify that connectivity with SRIOV ports is
correct after the server where this port was attached has been migrated to
a different compute node
"""
def _test_migration_with_sriov_port_prov_net(self, migration_method):
# TODO(eolivare): PF ports do not support neither cold nor live
# migration at this moment - see BZ1851417 and BZ1745842
# for port_type in ('direct', 'macvtap', 'direct-physical'):
for port_type in ('direct', 'macvtap'):
self._test_instance_with_one_port_prov_net(port_type)
server_id = self.servers[-1]['id']
# get the host where the VM is running
host = self.servers_client.show_server(
server_id)['server']['OS-EXT-SRV-ATTR:host']
# migrate the VM
if migration_method == 'cold-migration':
self.servers_client.migrate_server(server_id)
waiters.wait_for_server_status(self.servers_client,
server_id,
'VERIFY_RESIZE')
# confirm migration
self.servers_client.confirm_resize_server(server_id)
elif migration_method == 'live-migration':
block_migration = (CONF.compute_feature_enabled.
block_migration_for_live_migration)
self.servers_client.live_migrate_server(
server_id, host=None,
block_migration=block_migration, disk_over_commit=False)
else:
raise RuntimeError('Unsupported migration method %s'
% migration_method)
# wait until server status is active
waiters.wait_for_server_status(self.servers_client,
server_id,
constants.SERVER_STATUS_ACTIVE)
# get the host where the VM after the migration
new_host = self.servers_client.show_server(
server_id)['server']['OS-EXT-SRV-ATTR:host']
self.assertNotEqual(host, new_host, 'VM did not migrate')
# check port connectivity and status after migration
waiters.wait_for_interface_status(self.os_adm.interfaces_client,
server_id,
self.ports[-1]['id'],
lib_constants.PORT_STATUS_ACTIVE)
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
# delete the server before next iteration
# otherwise PF server could not be migrated
self.servers_client.delete_server(server_id)
waiters.wait_for_server_termination(self.servers_client,
server_id)
del self.servers[-1]
class ColdMigrationProvNetSriovTest(BaseMigrationProvNetSriovTest):
"""Class for SRIOV test that verify that connectivity with SRIOV ports is
correct after the server where this port was attached has been migrated to
a different compute node, by means of cold migration procedure
"""
@decorators.idempotent_id('339f3bf7-48a6-461c-99d7-2b3b49126e65')
@testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
'Cold migration is not available.')
def test_cold_migration_with_sriov_port_prov_net(self):
self._test_migration_with_sriov_port_prov_net('cold-migration')
class LiveMigrationProvNetSriovTest(BaseMigrationProvNetSriovTest):
"""Class for SRIOV test that verify that connectivity with SRIOV ports is
correct after the server where this port was attached has been migrated to
a different compute node, by means of live migration procedure
"""
@decorators.idempotent_id('1a261026-3ef9-4254-a309-37e9db3dc33a')
@testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
'Live migration is not available.')
def test_live_migration_with_sriov_port_prov_net(self):
self._test_migration_with_sriov_port_prov_net('live-migration')
class AdminStateProvNetSriovTest(BaseMigrationProvNetSriovTest):
"""Class for SRIOV test that verify that both SRIOV agents and ports
behave properly when admin state is set to UP or DOWN
"""
@decorators.idempotent_id('f884cb13-05e0-48a1-a393-20fc47bc458e')
def test_sriov_agent_admin_state_with_sriov_port_prov_net(self):
# TODO(eolivare): not supported due to LP1892741 (both ovs and ovn)
raise self.skipException("Not supported due to LP1892741")
for port_type in ('direct', 'direct-physical'):
self._test_instance_with_one_port_prov_net(port_type)
# get all SRIOV agents
sriov_agents = self.client.list_agents(
binary='neutron-sriov-nic-agent')['agents']
# set agents admin-state to DOWN
state_up = {"admin_state_up": True}
state_down = {"admin_state_up": False}
for sriov_agent in sriov_agents:
self.addCleanup(self.client.update_agent,
sriov_agent['id'], agent_info=state_up)
self.client.update_agent(sriov_agent['id'],
agent_info=state_down)
server_id = self.servers[-1]['id']
port_id = self.ports[-1]['id']
# check port connectivity and status after update
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
waiters.wait_for_interface_status(self.os_adm.interfaces_client,
server_id,
port_id,
lib_constants.PORT_STATUS_ACTIVE)
vm_name = 'vm-%s-error' % port_type
self.assertRaises(
exceptions.BuildErrorException,
self._test_create_instance_with_network_port,
port_type=port_type,
vm_name=vm_name)
# set agents admin-state to UP before next iteration
for sriov_agent in sriov_agents:
self.client.update_agent(sriov_agent['id'],
agent_info=state_up)
@decorators.idempotent_id('d1599884-c507-4724-ae17-c5034b532543')
def test_port_admin_state_with_sriov_port_prov_net(self):
# TODO(eolivare): only VF ports supported at this moment
# for port_type in ('direct', 'direct-physical'):
for port_type in ('direct',):
self._test_instance_with_one_port_prov_net(port_type)
# set port admin-state to DOWN
server_id = self.servers[-1]['id']
port_id = self.ports[-1]['id']
self.client.update_port(port_id, admin_state_up=False)
# check port connectivity and status after update
waiters.wait_for_interface_status(self.os_adm.interfaces_client,
server_id,
port_id,
lib_constants.PORT_STATUS_DOWN)
# validate port is not reachable
# it might take a moment until the port becomes unreachable
time.sleep(.5)
self.assertRaises(
lib_exc.SSHTimeout,
self.check_connectivity,
host=self.ports[-1]['fixed_ips'][0]['ip_address'],
ssh_user=self.username,
ssh_key=self.keypair['private_key'],
ssh_timeout=10)
# set port admin-state to UP
self.client.update_port(port_id, admin_state_up=True)
# check port connectivity and status after update
waiters.wait_for_interface_status(self.os_adm.interfaces_client,
server_id,
port_id,
lib_constants.PORT_STATUS_ACTIVE)
# validate port is reachable again
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
class TwoPortsServersProvNetSriovTest(ProviderNetworkSriovBaseTest):
"""VM instances are created with two ports:
- an SRIOV VF port on a provider network
- a normal port on a tenant network
"""
@decorators.idempotent_id('21ffa191-26a7-4f83-99f6-56ed09b4116a')
def test_create_two_instances_with_two_ports(self):
port_types = ['direct', 'normal']
int_cidr = netaddr.IPNetwork('10.100.0.0/16')
self._test_create_instance_with_two_ports(port_types, int_cidr)
ext_ip1 = self.ports[-2]['fixed_ips'][0]['ip_address']
self._test_create_instance_with_two_ports(
port_types, int_cidr, reused_tenant_net=self.networks[-1])
ext_ip2 = self.ports[-2]['fixed_ips'][0]['ip_address']
# check connectivity with external IPs (SRIOV ports connected to
# provider network)
for ip in (ext_ip1, ext_ip2):
self.check_connectivity(ip,
self.username,
self.keypair['private_key'])
# check connectivity from both VMs to all 4 ports
for ip in (ext_ip1, ext_ip2):
server_ssh_client = remote_client.RemoteClient(
ip,
self.username,
pkey=self.keypair['private_key'])
for port in self.ports:
fixed_ip = port['fixed_ips'][0]['ip_address']
server_ssh_client.ping_host(fixed_ip)

View File

@ -0,0 +1,484 @@
# Copyright 2024 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron_tempest_plugin import config
from neutron_tempest_plugin.scenario import constants
from oslo_log import log
from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import exceptions
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from whitebox_neutron_tempest_plugin.tests.scenario import \
test_sriov_provider_network
CONF = config.CONF
WB_CONF = config.CONF.whitebox_neutron_plugin_options
LOG = log.getLogger(__name__)
class RoutedProviderNetworkSriovBaseTest(
test_sriov_provider_network.ProviderNetworkSriovBaseTest):
"""Base class for tests using provisioning networks
These tests need the same deployment:
- datacentre with controllers and 1 compute over subnet 1
- leaf1 1 computes over subnet 2
and the next preconfiguration:
- Admin user is needed to create ports on the existing provisioning network
- 2 network segments called segment1, segment2
- 2 subnets segment1(subnet1), segment2(subnet2)
- 2 AZs segment1(central site), segment2(leaf1)
"""
@classmethod
def skip_checks(cls):
super(RoutedProviderNetworkSriovBaseTest, cls).skip_checks()
if not WB_CONF.provroutednetwork_support:
raise cls.skipException(
"Skipped since according to provroutednetwork_support config "
"value Provider Routed Networks are not supported")
def _test_create_instance_with_network_port(self, port_type,
subnet_id='1',
vm_name=None,
reuse_port=False):
# Create vm in segmentX, az segmentX, subnet segmentX
# Vm created directly over the external network
# az segmentX
# X=subnet_id
security_groups, port, user_data, config_drive = \
self._create_network_port(port_type,
reuse_port=reuse_port,
use_provider_net=True,
subnet_id=subnet_id)
vm_name = vm_name or "vm-" + port_type + "-" + self._testMethodName
subnet_name = 'segment' + subnet_id
self._create_server(
security_groups=security_groups, networks=[port],
user_data=user_data, config_drive=config_drive,
availability_zone=subnet_name, name=vm_name)
def _test_instance_with_one_port_prov_net(self, port_type, subnet_id='1'):
# Create vm in segmentX, az segmentX, subnet segmentX
# Vm created over a pre created port in subnet
# segmentX and az segmentX
# X=subnet_id
self._test_create_instance_with_network_port(port_type, subnet_id)
self.check_connectivity(self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'], ssh_timeout=60)
self.check_port_status(port_type)
class OneServerRoutedProvNetSriovTest(RoutedProviderNetworkSriovBaseTest):
"""Class for SRIOV tests creating one VM with one SRIOV port on routed
provider networks
These tests can be executed without needing to cleanup VMs or ports between
them
"""
@decorators.idempotent_id('57bc00f2-d166-41c1-8a87-600bb087f248')
def test_create_instance_with_normal_port_prov_net_seg1(self):
# Create vm in datacentre network, segment1, az segment1,
# subnet segment1
# Vm created over a pre created port in subnet
# segment1 and az segment1
self._test_instance_with_one_port_prov_net('normal', '1')
@decorators.idempotent_id('d6356ffd-e521-48d2-bc69-13f2cd72690a')
def test_create_instance_with_normal_port_prov_net_seg2(self):
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
self._test_instance_with_one_port_prov_net('normal', '2')
@decorators.idempotent_id('aea44620-6e01-4cf1-8b9c-9171717092b0')
def test_create_instance_with_direct_port_prov_net_seg1(self):
# Create vm in datacentre network, segment1, az segment1,
# subnet segment1
# Vm created over a pre created port in subnet
# segment1 and az segment1
self._test_instance_with_one_port_prov_net('direct', '1')
@decorators.idempotent_id('17e96d5d-c5b6-4731-8027-7810a0761da3')
def test_create_instance_with_direct_port_prov_net_seg2(self):
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
self._test_instance_with_one_port_prov_net('direct', '2')
@decorators.idempotent_id('6d2f7a06-6f41-42e7-a239-f722914914da')
def test_create_instance_with_macvtap_port_prov_net_seg1(self):
# Create vm in datacentre network, segment1, az segment1,
# subnet segment1
# Vm created over a pre created port in subnet
# segment1 and az segment1
self._test_instance_with_one_port_prov_net('macvtap', '1')
@decorators.idempotent_id('955c6502-9cc6-4c7e-bb12-726be03a2c75')
def test_create_instance_with_macvtap_port_prov_net_seg2(self):
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
self._test_instance_with_one_port_prov_net('macvtap', '2')
class OneServerPfRoutedProvNetSriovTest(RoutedProviderNetworkSriovBaseTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after its execution)
"""
@decorators.idempotent_id('18e1fc90-440a-43ea-b269-524064332bb0')
def test_create_instance_with_direct_physical_port_prov_net_seg1(self):
# Create vm in datacentre network, segment1, az segment1,
# subnet segment1
# Vm created over a pre created port in subnet
# segment1 and az segment1
self._test_instance_with_one_port_prov_net('direct-physical', '1')
@decorators.idempotent_id('a9fa54d0-ec91-4d46-978d-48e3cef4492e')
def test_create_instance_with_direct_physical_port_prov_net_seg2(self):
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
self._test_instance_with_one_port_prov_net('direct-physical', '2')
class RebootServerRoutedProvNetSriovRoutedTest(
RoutedProviderNetworkSriovBaseTest):
"""Class for SRIOV test that creates VM instances with different SRIOV port
types, reboot those instances and checks their behavior is correct after
reboot
"""
@decorators.idempotent_id('43482b46-bb26-422f-96cd-99508eb30a75')
def test_reboot_vm_with_sriov_port_prov_net_seg2(self):
# Create vm in datacentre network, segment1, az segment1,
# subnet segment1
# Vm created over a pre created port in subnet
# segment1 and az segment1
# Reboot the vm
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
# Reboot the vm
cont = 0
for port_type in ('direct', 'direct-physical'):
cont += 1
self._test_instance_with_one_port_prov_net(port_type, str(cont))
for reboot_type in ('SOFT', 'HARD'):
self.servers_client.reboot_server(self.servers[-1]['id'],
type=reboot_type)
waiters.wait_for_server_status(self.servers_client,
self.servers[-1]['id'],
constants.SERVER_STATUS_ACTIVE)
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
class ReusePortRoutedProvNetSriovRoutedTest(
RoutedProviderNetworkSriovBaseTest):
"""Class for SRIOV test that creates VM instances with different SRIOV port
types, delete those instances and reuse the existing SRIOV ports on new VM
instances
"""
@decorators.idempotent_id('eab71091-8a5f-4609-b259-91de74ad8744')
def test_reuse_sriov_port_prov_net_seg2(self):
# TODO(eolivare): only VF ports supported at this moment
# for port_type in ('direct', 'direct-physical'):
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
# Delete vm
# Create vm reusing the port
for port_type in ('direct',):
self._test_instance_with_one_port_prov_net(port_type, '2')
old_port_id = self.ports[-1]['id']
old_num_ports = len(self.ports)
# delete the server and create a new server attached to the
# existing port
self.servers_client.delete_server(self.servers[-1]['id'])
waiters.wait_for_server_termination(self.servers_client,
self.servers[-1]['id'])
del self.servers[-1]
# validate port is not reachable anymore
self.assertRaises(
lib_exc.SSHTimeout,
self.check_connectivity,
host=self.ports[-1]['fixed_ips'][0]['ip_address'],
ssh_user=self.username,
ssh_key=self.keypair['private_key'],
ssh_timeout=10)
# create a new server reusing the existing port
self._test_create_instance_with_network_port(
port_type, '2', reuse_port=True)
waiters.wait_for_server_status(self.servers_client,
self.servers[-1]['id'],
constants.SERVER_STATUS_ACTIVE)
# check no new ports have been created
self.assertEqual(old_num_ports, len(self.ports))
self.assertEqual(old_port_id, self.ports[-1]['id'])
# validate port is reachable again
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
@decorators.idempotent_id('b7bed0e4-9c34-4bf1-b411-246345ef7338')
def test_detach_attach_sriov_port_prov_net_seg2(self):
interfaces_client = self.os_adm.interfaces_client
# TODO(eolivare): only VF ports supported at this moment
# for port_type in ('direct', 'direct-physical'):
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
# Remove interface from vm
# Create vm reusing the port
for port_type in ('direct',):
self._test_instance_with_one_port_prov_net(port_type, '2')
old_port_id = self.ports[-1]['id']
old_num_ports = len(self.ports)
# remove port from server
interfaces_client.delete_interface(self.servers[-1]['id'],
self.ports[-1]['id'])
# validate port is not reachable anymore
self.assertRaises(
lib_exc.SSHTimeout,
self.check_connectivity,
host=self.ports[-1]['fixed_ips'][0]['ip_address'],
ssh_user=self.username,
ssh_key=self.keypair['private_key'],
ssh_timeout=10)
# reattach port on a new server (reattaching to a running VM is
# not supported)
self._test_create_instance_with_network_port(
port_type, '2', reuse_port=True)
waiters.wait_for_server_status(self.servers_client,
self.servers[-1]['id'],
constants.SERVER_STATUS_ACTIVE)
# check no new ports have been created
self.assertEqual(old_num_ports, len(self.ports))
self.assertEqual(old_port_id, self.ports[-1]['id'])
# validate port is reachable again
self.check_connectivity(
self.ports[-1]['fixed_ips'][0]['ip_address'],
self.username,
self.keypair['private_key'])
self.check_port_status(port_type)
class NegativeProvRoutedNetSriovRoutedTest(RoutedProviderNetworkSriovBaseTest):
"""Assuming we have hosts with one SRIOV port and it is already occupied,
then creation of VM with VF or PF port should fail
We create a VM with PF port on each compute node in order to occupy SRIOV
port; creating VM with PF or VF should fail as there is no available port
"""
@decorators.idempotent_id('94dd5592-3cc9-4636-bad7-077c0b6b5558')
def test_try_create_instance_with_sriov_port_seg2(self):
# Create vm in leaf1 network, segment2, az segment2,
# subnet segment2
# Vm created over a pre created port in subnet
# segment2 and az segment2
# Try to create a second vm with vp and pf
self._test_create_instance_with_network_port('direct-physical', '2')
for port_type in ('direct-physical', 'direct'):
vm_name = 'vm-%s-error' % port_type
self.assertRaises(
exceptions.BuildErrorException,
self._test_create_instance_with_network_port,
port_type=port_type, subnet_id='2',
vm_name=vm_name)
class TwoServersProvNetSriovRoutedTest(RoutedProviderNetworkSriovBaseTest):
"""Base class for SRIOV tests creating two VMs with one SRIOV port on
routed provider networks
# Create 2 vm:
# 1 segmentX1, az segmentX1, subnet segmentX1
# 2 segmentX2, az segmentX2, subnet segmentX2
# Vms created over a pre created port
# az segmentX, subnet segmentX
# X1=subnet_id1
# X2=subnet_id2
"""
def _test_create_two_instances_with_ports_seg(self,
port_type1, segment1,
port_type2, segment2):
self._test_create_instance_with_network_port(port_type1, segment1)
ip1 = self.ports[0]['fixed_ips'][0]['ip_address']
self._test_create_instance_with_network_port(port_type2, segment2)
ip2 = self.ports[1]['fixed_ips'][0]['ip_address']
for ip in (ip1, ip2):
self.check_connectivity(ip,
self.username,
self.keypair['private_key'])
server_ssh_client = remote_client.RemoteClient(
ip1,
self.username,
pkey=self.keypair['private_key'], server=self.servers[0])
server_ssh_client.ping_host(ip2)
class TwoPortsTwoServersRoutedProvNetSriovTest(
TwoServersProvNetSriovRoutedTest):
"""The following tests can be executed without needing to cleanup between
them because only normal and Vf ports are created
"""
@decorators.idempotent_id('4523524a-b70e-4f44-9984-f6e622e652d1')
def test_create_instances_with_normal_normal_ports_seg1_seg2(self):
# Create 2 vm:
# 1 segment1, az segment1, subnet segment1
# 2 segment2, az segment2, subnet segment2
# 2 vms in the different segment(central site and leaf)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('normal', '1',
'normal', '2')
@decorators.idempotent_id('b5a96f9f-68b7-4559-b98f-b2c1b3f3a940')
def test_create_instances_with_normal_normal_ports_seg2(self):
# Create 2 vm:
# 1 segment2, az segment2, subnet segment2
# 2 segment2, az segment2, subnet segment2
# 2 vms in the same segment and compute(leaf1)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('normal', '2',
'normal', '2')
@decorators.idempotent_id('6cbfaf93-b3d0-4a52-83c2-69a387e815e1')
def test_create_instances_with_normal_vf_ports_seg1_seg2(self):
# Create 2 vm:
# 1 segment1, az segment1, subnet segment1
# 2 segment2, az segment2, subnet segment2
# 2 vms in the different segment(central site and leaf)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('direct', '1',
'normal', '2')
@decorators.idempotent_id('b45d44e4-aa13-484a-86d8-19482bdd9c25')
def test_create_instances_with_normal_vf_ports_seg2(self):
# Create 2 vm:
# 1 segment2, az segment2, subnet segment2
# 2 segment2, az segment2, subnet segment2
# 2 vms in the same segment and compute(leaf1)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('direct', '2',
'normal', '2')
@decorators.idempotent_id('bec613f7-57ab-44ea-879f-e6a21647493a')
def test_create_instances_with_vf_vf_ports_seg1_seg2(self):
# Create 2 vm:
# 1 segment1, az segment1, subnet segment1
# 2 segment2, az segment2, subnet segment2
# 2 vms in the different segment(central site and leaf)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('direct', '1',
'direct', '2')
class PfAndPfServersProvNetSriovTest(
TwoServersProvNetSriovRoutedTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after its execution)
"""
@decorators.idempotent_id('128f6070-b0fc-4dc3-a815-2aeaf43f2815')
def test_create_instances_with_pf_pf_ports_seg1_seg2(self):
# Create 2 vm:
# 1 segment1, az segment1, subnet segment1
# 2 segment2, az segment2, subnet segment2
# 2 vms in the different segment(central site and leaf)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('direct-physical', '1',
'direct-physical', '2')
class VfAndPfServersRoutedProvNetSriovTest(
TwoServersProvNetSriovRoutedTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after its execution)
"""
@decorators.idempotent_id('7eecb5f4-2dde-4cf6-bf60-e3663bade307')
def test_create_instances_with_vf_pf_ports_seg1_seg2(self):
# Create 2 vm:
# 1 segment1, az segment1, subnet segment1
# 2 segment2, az segment2, subnet segment2
# 2 vms in the different segment(central site and leaf)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('direct-physical', '1',
'direct', '2')
class NormalAndPf1SegServersRoutedProvNetSriovTest(
TwoServersProvNetSriovRoutedTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after its execution)
"""
@decorators.idempotent_id('9de6e9c3-b1e1-4509-b97b-dd9800fee2b9')
def test_create_instances_with_normal_pf_ports_seg2(self):
# Create 2 vm:
# 1 segment2, az segment2, subnet segment2
# 2 segment2, az segment2, subnet segment2
# 2 vms in the same segment and compute(leaf1)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('direct-physical', '2',
'normal', '2')
class NormalAndPfServersRoutedProvNetSriovTest(
TwoServersProvNetSriovRoutedTest):
"""The following test need to be executed isolated (VM and port cleanup is
needed before and after its execution)
"""
@decorators.idempotent_id('5360a20f-9168-494a-9c32-72841a9f7563')
def test_create_instances_with_normal_pf_ports_seg1_seg2(self):
# Create 2 vm:
# 1 segment1, az segment1, subnet segment1
# 2 segment2, az segment2, subnet segment2
# 2 vms in the different segment(central site and leaf)
# Vms created over a pre created port
# az segmentX, subnet segmentX
self._test_create_two_instances_with_ports_seg('direct-physical', '1',
'normal', '2')