Merge "Add DPDK tests"

This commit is contained in:
Jenkins 2017-02-28 17:43:24 +00:00 committed by Gerrit Code Review
commit 5fee68f974
8 changed files with 198 additions and 21 deletions

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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'

View File

@ -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]))))