Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Commit

Permalink
Add test against OVS
Browse files Browse the repository at this point in the history
The patch adds simple test where LLC information is passed to a Neutron
logical port. This triggers Ansible mechanism driver that is configured
to talk to local Open vSwitch database. The port on OVS side should be
configured with VLAN tag that is taken from Neutron logical network
segmentation ID. VLAN tag is validated using ovsdbapp querying Port OVS
table.

update_port method for openvswitch provider is added in order to be able
to talk to OVS DB.

NOTE: Current Ansible contains bug in openvswitch_db module, the PR is
      pending review at the time of pushing this patch at
      ansible/ansible#42110

This is not a real tempest test as it assumes all-in-one and checks OVS
installed on the local machine from which tempest is run. This is
because we're in time pressure and such test adds a big value and there
is no better testing framework at this moment.

Change-Id: Ic73065175746a10ebef1ec731f947ee1c0919e72
  • Loading branch information
cubeek committed Jul 4, 2018
1 parent 07368b9 commit a8105eb
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 0 deletions.
@@ -0,0 +1,8 @@
---
- name: "openvswitch: run update_port"
openvswitch_db:
table: Port
record: "{{ ml2_port_name }}"
col: tag
value: "{{ ml2_segmentation_id }}"
become: yes
Empty file added net_ansible_tempest/__init__.py
Empty file.
42 changes: 42 additions & 0 deletions net_ansible_tempest/config.py
@@ -0,0 +1,42 @@
# Copyright 2018 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 oslo_config import cfg

service_option = cfg.BoolOpt(
'netansible',
default=False,
help='Whether or not Networking Ansbile mech driver is expected to be '
'available.')

ovs_opt_group = cfg.OptGroup(
name='net_ansible_openvswitch',
title='Settings for OVS provider.',
help='Options group for OVS Ansible provider.')

OVS_GROUP = [
cfg.StrOpt(
'ovsdb_connection',
default='tcp:127.0.0.1:6640',
help='Connection string to OVSDB.'),
cfg.StrOpt(
'bridge_name',
default='net-ans-br',
help='Name of the bridge which port is attached to.'),
cfg.StrOpt(
'port_name',
default='net-ans-p0',
help='Name of the port that is being tested'),
]
45 changes: 45 additions & 0 deletions net_ansible_tempest/plugin.py
@@ -0,0 +1,45 @@
# Copyright 2018 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 os

from tempest import config
from tempest.test_discover import plugins

from net_ansible_tempest import config as plugin_config


class NetAnsibleTempestPlugin(plugins.TempestPlugin):
def get_opt_lists(self):
return [
(plugin_config.ovs_opt_group.name, plugin_config.OVS_GROUP),
('service_available', [plugin_config.service_option]),
]

def get_service_clients(self):
pass

def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = os.path.join("net_ansible_tempest", "tests")
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path

def register_opts(self, conf):
config.register_opt_group(
conf, plugin_config.ovs_opt_group, plugin_config.OVS_GROUP)
conf.register_opt(
plugin_config.service_option, group='service_available')
Empty file.
20 changes: 20 additions & 0 deletions net_ansible_tempest/tests/base.py
@@ -0,0 +1,20 @@
# Copyright 2018 Red Hat, Inc.
#
# 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 tempest.api.network import base


class NetAnsibleAdminBaseTest(base.BaseAdminNetworkTest):

credentials = ["primary", "admin"]
Empty file.
99 changes: 99 additions & 0 deletions net_ansible_tempest/tests/scenario/test_basic_ops.py
@@ -0,0 +1,99 @@
# Copyright 2018 Red Hat, Inc.
#
# 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 oslo_config import cfg
from tempest.lib import decorators
from tempest.lib import exceptions

from net_ansible_tempest.tests import base
from net_ansible_tempest.tests import utils


class TestWithOvs(base.NetAnsibleAdminBaseTest):

@classmethod
def skip_checks(cls):
super(TestWithOvs, cls).skip_checks()
if not cfg.CONF.service_available.netansible:
raise cls.skipException("networking ansible is not enabled")

def setUp(self):
super(TestWithOvs, self).setUp()
self.ovs = utils.get_idl_singleton()
current_tag = self.ovs.db_get(
'Port', self.ovs_port_name, 'tag').execute()
restore_command = self.ovs.db_set(
'Port', self.ovs_port_name, ('tag', current_tag))
self.addCleanup(restore_command.execute)

def cleanup_port(self, port_id):
"""Remove Neutron port and skip NotFound exceptions."""
try:
self.admin_ports_client.delete_port(port_id)
except exceptions.NotFound:
pass

@property
def ovs_bridge_name(self):
return cfg.CONF.net_ansible_openvswitch.bridge_name

@property
def ovs_bridge_mac(self):
return self.ovs.db_get(
'Interface', self.ovs_bridge_name, 'mac_in_use').execute()

@property
def ovs_port_name(self):
return cfg.CONF.net_ansible_openvswitch.port_name

def get_network_segmentation_id(self, network_id):
return self.admin_networks_client.show_network(
network_id)['network']['provider:segmentation_id']

def create_port(self, network_id):
port = self.admin_ports_client.create_port(
network_id=network_id, name=self.ovs_port_name)['port']
self.addCleanup(self.cleanup_port, port['id'])

host = self.admin_agents_client.list_agents(
agent_type='Open vSwitch agent'
)['agents'][0]['host']

llc = [{'switch_info': 'localhost',
'switch_id': self.ovs_bridge_mac,
'port_id': self.ovs_port_name}]

update_args = {
'device_owner': 'baremetal:none',
'device_id': 'fake-instance-uuid',
'admin_state_up': True,
'binding:vnic_type': 'baremetal',
'binding:host_id': host,
'binding:profile': {
'local_link_information': llc
}
}
self.admin_ports_client.update_port(
port['id'],
**update_args
)

@decorators.idempotent_id('40b81fe4-1e9c-4f10-a808-c23f85aea5e2')
def test_update_port(self):
net_id = self.admin_networks_client.list_networks(
name='private')['networks'][0]['id']
self.create_port(net_id)
current_tag = self.ovs.db_get('Port', 'net-ans-p0', 'tag').execute()
network_segmentation_id = self.get_network_segmentation_id(net_id)
self.assertEqual(network_segmentation_id, current_tag)
43 changes: 43 additions & 0 deletions net_ansible_tempest/tests/utils.py
@@ -0,0 +1,43 @@
# Copyright 2018 Red Hat, Inc.
#
# 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 oslo_config import cfg
from ovs.db import idl
from ovsdbapp.backend.ovs_idl import connection
from ovsdbapp.backend.ovs_idl import idlutils
from ovsdbapp.schema.open_vswitch import impl_idl

_idl = None


def idl_factory(conn, schema):
helper = idlutils.get_schema_helper(conn, schema)
helper.register_all()

return idl.Idl(conn, helper)


def get_idl_singleton():
global _idl

conn = cfg.CONF.net_ansible_openvswitch.ovsdb_connection
schema = "Open_vSwitch"

if _idl is None:
_connection = connection.Connection(
idl=idl_factory(conn, schema),
timeout=10)
_idl = impl_idl.OvsdbIdl(_connection)

return _idl
2 changes: 2 additions & 0 deletions setup.cfg
Expand Up @@ -27,6 +27,8 @@ data_files =
[entry_points]
neutron.ml2.mechanism_drivers =
ansible = networking_ansible.ml2.mech_driver:AnsibleMechanismDriver
tempest.test_plugins =
networking_ansible_whitebox = net_ansible_tempest.plugin:NetAnsibleTempestPlugin

[build_sphinx]
all-files = 1
Expand Down

0 comments on commit a8105eb

Please sign in to comment.