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:
parent
ca0fa6fe11
commit
9bb38100ba
@ -264,12 +264,13 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_pod_of_service(cls, service='neutron'):
|
def get_pod_of_service(cls, service='neutron'):
|
||||||
# (rsafrono) at this moment only neutron service pod handled
|
pods_list = "oc get pods"
|
||||||
# since it's the only that existing tests are using
|
|
||||||
if service == 'neutron':
|
if service == 'neutron':
|
||||||
return cls.proxy_host_client.exec_command(
|
filters = "grep neutron | grep -v meta | cut -d' ' -f1"
|
||||||
"oc get pods | grep neutron | grep -v meta | "
|
else:
|
||||||
"cut -d' ' -f1").strip()
|
filters = "grep {} | cut -d' ' -f1".format(service)
|
||||||
|
return cls.proxy_host_client.exec_command(
|
||||||
|
"{} | {}".format(pods_list, filters)).strip()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_configs_of_service(cls, service='neutron'):
|
def get_configs_of_service(cls, service='neutron'):
|
||||||
|
@ -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)
|
@ -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')
|
Loading…
Reference in New Issue
Block a user