Merge "Add DPDK tests"
This commit is contained in:
commit
5fee68f974
|
@ -147,21 +147,6 @@ def contrail_api_client(session, contrail_api_endpoint):
|
|||
url=contrail_api_endpoint, headers=headers, blocking=False)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nodes_ips(os_faults_steps):
|
||||
"""Return dict node_fqdn -> node_ips."""
|
||||
nodes = os_faults_steps.get_nodes()
|
||||
ip_fqdn = {node.ip: node.fqdn for node in nodes}
|
||||
cmd = """ip -o a | awk '/scope global/{split($4,ip,"/"); print ip[1]}'"""
|
||||
results = os_faults_steps.execute_cmd(nodes, cmd)
|
||||
node_ips_ = {}
|
||||
for node_result in results:
|
||||
fqdn = ip_fqdn[node_result.host]
|
||||
node_ips_[fqdn] = node_result.payload['stdout_lines']
|
||||
|
||||
return node_ips_
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def default_project(contrail_api_client):
|
||||
proj_id = contrail_api_client.project_get_default_id()
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import pytest
|
||||
|
||||
from vapor import settings
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nodes_ips(os_faults_steps):
|
||||
|
@ -14,3 +16,11 @@ def nodes_ips(os_faults_steps):
|
|||
nodes_ips_[fqdn] = node_result.payload['stdout_lines']
|
||||
|
||||
return nodes_ips_
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def computes(os_faults_steps):
|
||||
"""Return os-faults NodeCollection with only cloud computes."""
|
||||
fqdns = settings.CONTRAIL_ROLES_DISTRIBUTION[
|
||||
settings.ROLE_CONTRAIL_COMPUTE]
|
||||
return os_faults_steps.get_nodes(fqdns)
|
||||
|
|
|
@ -5,10 +5,10 @@ import re
|
|||
import attrdict
|
||||
from hamcrest import (empty, has_entries, contains_inanyorder,
|
||||
has_length) # noqa: H301
|
||||
from six import moves
|
||||
from stepler.third_party import waiter
|
||||
|
||||
from vapor.helpers import asserts
|
||||
from vapor.helpers import nodes_steps
|
||||
|
||||
|
||||
STATUS_ACTIVE = 'active'
|
||||
|
@ -61,7 +61,7 @@ def get_services_statuses(os_faults_steps):
|
|||
nodes = os_faults_steps.get_nodes_by_cmd('which ' + cmd)
|
||||
results = collections.defaultdict(list)
|
||||
for node_result in os_faults_steps.execute_cmd(nodes, cmd):
|
||||
node = next(moves.filter(lambda x: x.ip == node_result.host, nodes))
|
||||
node = nodes_steps.get_node_by_result(node_result, os_faults_steps)
|
||||
for service in parse_result(node_result.payload['stdout_lines']):
|
||||
results[node.fqdn].append(service)
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# 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 itertools
|
||||
|
||||
from stepler import config as stepler_config
|
||||
|
||||
from vapor.helpers import nodes_steps
|
||||
from vapor import settings
|
||||
|
||||
|
||||
def get_devices(os_faults_steps, nodes):
|
||||
result = os_faults_steps.execute_cmd(
|
||||
nodes, '{} --status'.format(settings.DPDK_NEC_BIND_PATH), check=False)
|
||||
node_statuses = {}
|
||||
for node_result in result:
|
||||
node = nodes_steps.get_node_by_result(node_result, os_faults_steps)
|
||||
statuses = {}
|
||||
if node_result.status == stepler_config.STATUS_OK:
|
||||
lines = node_result.payload['stdout_lines']
|
||||
for empty, section in itertools.groupby(
|
||||
lines, key=lambda x: x.strip() == ''):
|
||||
if empty:
|
||||
continue
|
||||
section = tuple(section)
|
||||
name = section[0]
|
||||
ifaces = [x for x in section[2:] if x.strip() != '<none>']
|
||||
statuses[name] = ifaces
|
||||
node_statuses[node.fqdn] = statuses
|
||||
return node_statuses
|
|
@ -17,6 +17,16 @@ def get_nodes_interfaces(os_faults_steps, nodes=None):
|
|||
results = os_faults_steps.execute_cmd(nodes, "ip -o a | awk '{print $2}'")
|
||||
ifaces = {}
|
||||
for node_result in results:
|
||||
node = next(node for node in nodes if node.ip == node_result.host)
|
||||
node = get_node_by_result(node_result, os_faults_steps)
|
||||
ifaces[node.fqdn] = set(node_result.payload['stdout_lines'])
|
||||
return ifaces
|
||||
|
||||
|
||||
def get_node_by_result(node_result, os_faults_steps):
|
||||
"""Match os_faults node by AnsibleResult.
|
||||
|
||||
AnsibleResult contains only node ip. To determine os-faults node we compare
|
||||
this ip with all nodes ips.
|
||||
"""
|
||||
nodes = os_faults_steps.get_nodes()
|
||||
return next(node for node in nodes if node.ip == node_result.host)
|
||||
|
|
|
@ -10,14 +10,60 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from vapor.helpers import nodes_steps
|
||||
|
||||
|
||||
def get_route_table(os_faults_steps, nodes):
|
||||
"""Return route tables for each node."""
|
||||
result = os_faults_steps.execute_cmd(nodes, 'ip r')
|
||||
tables = {}
|
||||
for node_result in result:
|
||||
for node in nodes:
|
||||
if node.ip == node_result.host:
|
||||
break
|
||||
node = nodes_steps.get_node_by_result(node_result, os_faults_steps)
|
||||
tables[node.fqdn] = node_result.payload['stdout_lines']
|
||||
return tables
|
||||
|
||||
|
||||
def get_interface_table(os_faults_steps, nodes):
|
||||
"""Return interface table for each node.
|
||||
|
||||
Format:
|
||||
{u'node-5.test.domain.local': [
|
||||
{'name': u'vif0/3',
|
||||
u'HWaddr': u'00:00:5e:00:01:00',
|
||||
u'Flags': u'PL3L2D',
|
||||
....},
|
||||
{.....}
|
||||
]}
|
||||
"""
|
||||
cmd = "vif --list"
|
||||
result = os_faults_steps.execute_cmd(nodes, cmd)
|
||||
tables = {}
|
||||
for node_result in result:
|
||||
node = nodes_steps.get_node_by_result(node_result, os_faults_steps)
|
||||
table = []
|
||||
iface = {}
|
||||
for line in node_result.payload['stdout_lines']:
|
||||
if not line.strip():
|
||||
if iface:
|
||||
table.append(iface)
|
||||
iface = {}
|
||||
else:
|
||||
if ':' not in line or line.startswith('Flags:'):
|
||||
continue
|
||||
elif line[0] != ' ':
|
||||
name, key, value = line.split(None, 2)
|
||||
key = key.strip(':')
|
||||
iface['name'] = name
|
||||
pairs = {key: value}
|
||||
else:
|
||||
pairs = line.split()
|
||||
if ':' not in pairs[0]:
|
||||
pairs = [
|
||||
u'{}_{}'.format(pairs[0], p) for p in pairs[1:]
|
||||
]
|
||||
pairs = dict(x.split(':', 1) for x in pairs)
|
||||
iface.update(pairs)
|
||||
if iface:
|
||||
table.append(iface)
|
||||
tables[node.fqdn] = table
|
||||
return tables
|
||||
|
|
|
@ -163,3 +163,5 @@ ZOOKEEPER_NODES = ["api-server",
|
|||
SERVER_ATTR_HYPERVISOR_HOSTNAME = 'OS-EXT-SRV-ATTR:hypervisor_hostname'
|
||||
|
||||
NEUTRON_SRIOV_NIC_AGENT = "neutron-sriov-nic-agent"
|
||||
|
||||
DPDK_NEC_BIND_PATH = '/opt/contrail/bin/dpdk_nic_bind.py'
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
# 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 hamcrest import (assert_that, has_entries, has_item, only_contains,
|
||||
is_not, empty, greater_than, has_length)
|
||||
|
||||
from vapor.helpers import contrail_status
|
||||
from vapor.helpers import dpdk
|
||||
from vapor.helpers import nodes_steps
|
||||
from vapor.helpers import vrouter_steps
|
||||
from vapor import settings
|
||||
|
||||
|
||||
def test_contrail_vrouter_dpdk(os_faults_steps):
|
||||
"""Validate existence and status for contrail-vrouter-dpdk service."""
|
||||
statuses = contrail_status.get_services_statuses(os_faults_steps)
|
||||
for fqdn in settings.CONTRAIL_ROLES_DISTRIBUTION[
|
||||
settings.ROLE_CONTRAIL_COMPUTE]:
|
||||
compute_services = statuses[fqdn]
|
||||
assert_that(
|
||||
compute_services,
|
||||
has_item(
|
||||
has_entries(name='contrail-vrouter-dpdk', status='active')))
|
||||
|
||||
|
||||
def test_bound_network_interfaces(os_faults_steps, computes):
|
||||
"""Verify if DPDK vRouter binds network interfaces."""
|
||||
devices = dpdk.get_devices(os_faults_steps, computes)
|
||||
assert_that(devices.values(),
|
||||
only_contains(
|
||||
has_entries('Network devices using DPDK-compatible driver',
|
||||
is_not(empty()))))
|
||||
|
||||
|
||||
def test_huge_pages_usage(os_faults_steps, computes):
|
||||
"""Verify if vRrouter uses Huge Pages."""
|
||||
result = os_faults_steps.execute_cmd(computes, 'grep Huge /proc/meminfo')
|
||||
for node_result in result:
|
||||
node = nodes_steps.get_node_by_result(node_result, os_faults_steps)
|
||||
data = {}
|
||||
for line in node_result.payload['stdout_lines']:
|
||||
key, value = line.split(':', 1)
|
||||
data[key] = value.strip()
|
||||
assert_that(data,
|
||||
has_entries(
|
||||
HugePages_Total=is_not('0'), AnonHugePages='0 kB'),
|
||||
node.fqdn)
|
||||
|
||||
|
||||
def test_contrail_vrouter_dpdk_cpu_usage(os_faults_steps, computes):
|
||||
"""Verify if vRouter uses CPU."""
|
||||
cmd = "ps -c contrail-vrouter-dpdk -o %cpu="
|
||||
result = os_faults_steps.execute_cmd(computes, cmd)
|
||||
for node_result in result:
|
||||
usage = node_result.payload['stdout']
|
||||
usage = float(usage.strip())
|
||||
assert_that(usage, greater_than(50))
|
||||
|
||||
|
||||
def test_vrouter_create_interface(request, os_faults_steps, computes):
|
||||
"""Verify if vRouter creates interface after creation of a virtual machine.
|
||||
|
||||
Steps:
|
||||
#. Remember count of virtual interfaces on vRouters
|
||||
#. Create server
|
||||
#. Check that count of virtual interfaces on server's compute vRouter
|
||||
is greater than it was.
|
||||
"""
|
||||
before_ifaces = vrouter_steps.get_interface_table(os_faults_steps,
|
||||
computes)
|
||||
server = request.getfixturevalue('server')
|
||||
compute_fqdn = getattr(server, settings.SERVER_ATTR_HYPERVISOR_HOSTNAME)
|
||||
after_ifaces = vrouter_steps.get_interface_table(os_faults_steps, computes)
|
||||
assert_that(after_ifaces[compute_fqdn],
|
||||
has_length(greater_than(len(before_ifaces[compute_fqdn]))))
|
Loading…
Reference in New Issue