End to end scenario test case for l2gateway

Validating entries in the ovsdb after creating l2gateway connection
    Logical Switch for network and tunnel key
    UCast MAC Remote for MAC address and VTEP mapping
    Physical Port Validating vni binding
    Physical Locator for hosts

Test l2gateway connection
    Create a network
    Create a subnet
    Create a server
    Create an l2gateway
    Create an l2gateway connection
    Validate resources in ovsdb

Test l2gateway multiple connections
    Create a network
    Create a subnet
    Create a server
    Create an l2gateway
    Create an l2gateway connection
    Validate resources in ovsdb
    Repeat for one more connection

Test boot VM after connection create
    Create a network
    Create a subnet
    Create an l2gateway
    Create an l2gateway connection
    Create a server
    Validate resources in ovsdb

Test create connection after deleting old
    Create a network
    Create a subnet
    Create a server
    Create an l2gateway
    Create an l2gateway connection
    Validate resources in ovsdb
    Delete the l2gateway connection
    Create a new l2gateway connection
    Validate resources in ovsdb

Change-Id: Ia634336d3162cb91661ed2c6d21cb507f02a3d11
stable/ocata
jmehta 8 years ago committed by prabhu murthy
parent 7850111efa
commit 716bac8174

@ -0,0 +1,153 @@
# Copyright 2015 OpenStack Foundation
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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 collections
import json
import logging
import random
import socket
import threading
import time
logging.basicConfig(level=logging.DEBUG)
def default_echo_handler(message, ovsconn):
logging.debug("responding to echo")
ovsconn.send({"result": message.get("params", None),
"error": None, "id": message['id']})
def default_message_handler(message, ovsconn):
ovsconn.responses.append(message)
class OVSDBConnection(threading.Thread):
"""Connects to an ovsdb server that has manager set using
ovs-vsctl set-manager ptcp:5000
clients can make calls and register a callback for results, callbacks
are linked based on the message ids.
clients can also register methods which they are interested in by
providing a callback.
"""
def __init__(self, IP, PORT, **handlers):
super(OVSDBConnection, self).__init__()
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((IP, PORT))
self.responses = []
self.callbacks = {}
self.read_on = True
self.handlers = handlers or {"echo": default_echo_handler}
self.start()
def send(self, message, callback=None):
if callback:
self.callbacks[message['id']] = callback
self.socket.send(json.dumps(message))
def response(self, id):
return [x for x in self.responses if x['id'] == id]
def set_handler(self, method_name, handler):
self.handlers[method_name] = handler
def _on_remote_message(self, message):
try:
json_m = json.loads(message,
object_pairs_hook=collections.OrderedDict)
handler_method = json_m.get('method', None)
if handler_method:
self.handlers.get(handler_method, default_message_handler)(
json_m, self)
elif json_m.get("result", None) and json_m['id'] in self.callbacks:
id = json_m['id']
if not self.callbacks[id](json_m, self):
self.callbacks.pop(id)
else:
default_message_handler(message, self)
except Exception as e:
logging.exception(
"exception [%s] in handling message [%s]", e.message, message)
def __echo_response(message, self):
self.send({"result": message.get("params", None),
"error": None, "id": message['id']})
def run(self):
chunks = []
lc = rc = 0
while self.read_on:
try:
response = self.socket.recv(4096)
if response:
response = response.decode('utf8')
message_mark = 0
for i, c in enumerate(response):
if c == '{':
lc += 1
elif c == '}':
rc += 1
if rc > lc:
raise Exception("json string not valid")
elif lc == rc and lc is not 0:
chunks.append(response[message_mark:i + 1])
message = "".join(chunks)
self._on_remote_message(message)
lc = rc = 0
message_mark = i + 1
chunks = []
chunks.append(response[message_mark:])
except Exception:
# Pass to avoid EOF error
pass
def stop(self, force=False):
self.read_on = False
if force:
self.socket.close()
def select_table(self, table):
select_dict = {"op": "select", "table": table, "where": []}
op_id = str(random.getrandbits(128))
params = ['hardware_vtep']
params.append(select_dict)
query_select = {"method": "transact",
"params": params,
"id": op_id}
return query_select
def find_row(self, net_id, count, resp_dec):
for i in range(count):
row = str(resp_dec['result'][0]['rows'][i])
if net_id in row:
return row
def get_response(self, OVSDB_IP, OVSDB_PORT, table):
query = self.select_table(table)
self.send(query)
time.sleep(2)
resp = self.responses
resp = str(resp[0])
return resp

@ -0,0 +1,388 @@
# Copyright 2015 OpenStack Foundation
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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 networking_l2gw.tests.api import base_l2gw
from networking_l2gw.tests.scenario import ovsdb_connections
from networking_l2gw.tests.tempest import config
from neutron.i18n import _LI
from neutron.tests.api import base
from neutron.tests.tempest import exceptions
from neutron.tests.tempest import manager
from oslo_log import log
from tempest_lib.common import rest_client
from tempest_lib.common.utils import data_utils
from tempest_lib.common.utils import misc as misc_utils
from tempest_lib import exceptions as lib_exc
import json
import time
CONF = config.CONF
LOG = log.getLogger(__name__)
OVSDB_IP = CONF.network.ovsdb_ip
OVSDB_PORT = CONF.network.ovsdb_port
OVSDB_SCHEMA_NAME = CONF.network.ovsdb_schema_name
class TestL2GatewayBasic(base.BaseAdminNetworkTest):
"""This test case tests the basic end to end functionality of l2-gateway
and tests whether the appropriate entries are getting registered in
the ovsdb.
"""
@classmethod
def resource_setup(cls):
super(TestL2GatewayBasic, cls).resource_setup()
nova_creds = cls.isolated_creds.get_admin_creds()
cls.auth_provider = manager.get_auth_provider(nova_creds)
def _create_server(
self, name=None,
network=None, wait_on_boot=True, wait_on_delete=True):
region = CONF.compute.region
image = CONF.compute.image_ref
flavor = CONF.compute.flavor_ref
rs_client = rest_client.RestClient(
self.auth_provider, 'compute', region)
data = {'server': {
'name': name,
'imageRef': image,
'flavorRef': flavor,
'max_count': 1,
'min_count': 1,
'networks': [{'uuid': network}]}}
data = json.dumps(data)
(resp, body,) = rs_client.post('/servers', data)
rs_client.expected_success(202, resp.status)
body = json.loads(body)
server_id = body['server']['id']
self.wait_for_server_status(server_id, 'ACTIVE')
return server_id
def _delete_server(self, server=None):
rs_client = rest_client.RestClient(
self.auth_provider, 'compute', 'RegionOne')
(resp, body, ) = rs_client.delete('servers/%s' % str(server))
self.wait_for_server_termination(server)
rest_client.ResponseBody(resp, body)
def wait_for_server_status(self, server_id, status, ready_wait=True,
extra_timeout=0, raise_on_error=True):
"""Waits for a server to reach a given status."""
build_timeout = CONF.compute.build_timeout
build_interval = CONF.boto.build_interval
def _get_task_state(body):
return body.get('OS-EXT-STS:task_state', None)
rs = rest_client.RestClient(self.auth_provider, "compute", "RegionOne")
resp, body = rs.get("servers/%s" % str(server_id))
body = json.loads(body)
old_status = server_status = body['server']['status']
old_task_state = task_state = _get_task_state(body)
start_time = int(time.time())
timeout = build_timeout + extra_timeout
while True:
if status == 'BUILD' and server_status != 'UNKNOWN':
return
if server_status == status:
if ready_wait:
if status == 'BUILD':
return
if str(task_state) == "None":
time.sleep(CONF.compute.ready_wait)
return
else:
return
time.sleep(build_interval)
resp, body = rs.get("servers/%s" % str(server_id))
body = json.loads(body)
server_status = body['server']['status']
task_state = _get_task_state(body)
if (server_status != old_status) or (task_state != old_task_state):
oldstatus = '/'.join((old_status, str(old_task_state)))
serverstatus = '/'.join((server_status, str(task_state)))
waitsec = (time.time() - start_time)
LOG.info(
_LI('State transtion %(oldstatus)s => %(serverstatus)s'
'after %(waitsec)d second wait') %
{'oldstatus': oldstatus, 'serverstatus': serverstatus,
'waitsec': waitsec}
)
if (server_status == 'ERROR') and raise_on_error:
if 'fault' in body:
raise exceptions.BuildErrorException(body['fault'],
server_id=server_id)
else:
raise exceptions.BuildErrorException(server_id=server_id)
timed_out = int(time.time()) - start_time >= timeout
if timed_out:
expected_task_state = 'None' if ready_wait else 'n/a'
message = ('Server %(server_id)s failed to reach %(status)s '
'status and task state "%(expected_task_state)s" '
'within the required time (%(timeout)s s).' %
{'server_id': server_id,
'status': status,
'expected_task_state': expected_task_state,
'timeout': timeout})
message += ' Current status: %s.' % server_status
message += ' Current task state: %s.' % task_state
caller = misc_utils.find_test_caller()
if caller:
message = '(%s) %s' % (caller, message)
raise exceptions.TimeoutException(message)
old_status = server_status
old_task_state = task_state
def wait_for_server_termination(self, server_id, ignore_error=False):
"""Waits for server to reach termination."""
build_interval = CONF.boto.build_interval
while True:
try:
rs = rest_client.RestClient(
self.auth_provider, 'compute', 'RegionOne')
(resp, body,) = rs.get('servers/%s' % str(server_id))
body = json.loads(body)
except lib_exc.NotFound:
return
server_status = body['server']['status']
if server_status == 'ERROR' and not ignore_error:
raise exceptions.BuildErrorException(server_id=server_id)
time.sleep(build_interval)
def validate_ovsdb(self, seg_id, port, network_id_1, tunnel_key):
# Check Logical_Switch
objConnection = ovsdb_connections.OVSDBConnection(OVSDB_IP, OVSDB_PORT)
resp = objConnection.get_response(
OVSDB_IP, OVSDB_PORT, "Logical_Switch")
resp_dec = json.loads(resp)
count = resp.count('_uuid')
try:
self.assertIn(str(network_id_1), resp)
except Exception:
raise lib_exc.NotFound("Network not found in Logical Switch table")
row = objConnection.find_row(network_id_1, count, resp_dec)
try:
self.assertIn(str(tunnel_key), row)
except Exception:
raise lib_exc.NotFound(
"Tunnel key not found in Logical Switch table")
objConnection.stop("true")
# Check Physical_Port
objConnection = ovsdb_connections.OVSDBConnection(OVSDB_IP, OVSDB_PORT)
resp = objConnection.get_response(
OVSDB_IP, OVSDB_PORT, "Physical_Port")
count = resp.count('_uuid')
try:
self.assertIn(str(seg_id[0]), resp)
except Exception:
raise lib_exc.NotFound(
"Segmentation ID not found in Physical Port table")
objConnection.stop("true")
# Check Physical_Locator
objConnection = ovsdb_connections.OVSDBConnection(OVSDB_IP, OVSDB_PORT)
resp = objConnection.get_response(
OVSDB_IP, OVSDB_PORT, "Physical_Locator")
count = resp.count('_uuid')
port_str = str(port)
count_port = port_str.count('fixed_ips')
net_node_host = []
compute_node_host = []
# Extracting unique Network node host name and Compute host name
for i in range(count_port):
net_id = port['ports'][i]['network_id']
device_owner = port['ports'][i]['device_owner']
if net_id == network_id_1 and device_owner == 'network:dhcp':
if port['ports'][i]['binding:host_id'] not in net_node_host:
net_node_host.append(port['ports'][i]['binding:host_id'])
if port['ports'][i]['device_owner'] == 'compute:None':
if port['ports'][i]['binding:host_id'] not in net_node_host:
compute_node_host.append(
port['ports'][i]['binding:host_id'])
ip_SW = CONF.network.l2gw_switch_ip
host_and_ip = CONF.network.hosts
list_ = host_and_ip.split(', ')
host_ip_dict = {}
for i in list_:
sub_list = i.split(':')
host = sub_list[0]
ip = sub_list[1]
host_ip_dict.update({host: ip})
for net_node in net_node_host:
ip_NN = host_ip_dict[net_node]
try:
self.assertIn(ip_NN, resp)
except Exception:
raise lib_exc.NotFound(
"Network Node IP not found in Physical Locator table")
for compute_node in compute_node_host:
ip_CN = host_ip_dict[compute_node]
try:
self.assertIn(ip_CN, resp)
except Exception:
raise lib_exc.NotFound(
"Compute Node IP not found in Physical Locator table")
try:
self.assertIn(ip_SW, resp)
except Exception:
raise lib_exc.NotFound(
"Switch IP not found in Physical Locator table")
objConnection.stop("true")
# Check Ucast_macs_Remote
objConnection = ovsdb_connections.OVSDBConnection(OVSDB_IP, OVSDB_PORT)
resp = objConnection.get_response(
OVSDB_IP, OVSDB_PORT, "Ucast_Macs_Remote")
ip_mac_dict = {}
count_uuid = resp.count('_uuid')
resp_dec = json.loads(resp)
for i in range(count_port):
mac = port['ports'][i]['mac_address']
ip = port['ports'][i]['fixed_ips'][0]['ip_address']
ip_mac_dict.update({mac: ip})
try:
for key, value in ip_mac_dict.iteritems():
row = objConnection.find_row(key, count_uuid, resp_dec)
self.assertIn(value, row)
except Exception:
raise lib_exc.NotFound(
"MAC & its port not found in UCast MAC Remote table")
objConnection.stop("true")
def _create_l2_gateway(self, name, devices):
body_l2gateway = self.admin_client.create_l2_gateway(
name=name, devices=devices)
self.addCleanup(
self.admin_client.delete_l2_gateway,
body_l2gateway['l2_gateway']['id'])
return body_l2gateway
def _create_l2_gw_connection(
self, l2gw, net_id, seg_id=None, explicit=None):
l2gw_id = l2gw['l2_gateway']['id']
if l2gw['l2_gateway']['devices'][0]['interfaces'][
0]['segmentation_id']:
resp_l2gwconn = self.admin_client.create_l2_gateway_connection(
network_id=net_id, l2_gateway_id=l2gw_id)
else:
resp_l2gwconn = self.admin_client.create_l2_gateway_connection(
network_id=net_id,
l2_gateway_id=l2gw_id, segmentation_id=seg_id)
if explicit:
# Connection deleted explicitly, thus addCleanup not called
pass
else:
self.addCleanup(
self.admin_client.delete_l2_gateway_connection,
resp_l2gwconn['l2_gateway_connection']['id'])
return resp_l2gwconn
def _setup_network_and_server(self, cidr=None):
network = self.create_network()
self.addCleanup(self.client.delete_network, network['id'])
self.create_subnet(network=network, cidr=cidr)
name = data_utils.rand_name('server-smoke')
server_id = self._create_server(name, network=network['id'])
self.addCleanup(self._delete_server, server_id)
return network
def test_l2gw_create_connection(self):
network = self._setup_network_and_server()
network_body = self.admin_client.show_network(network['id'])
gw_name = data_utils.rand_name('l2gw')
devices = base_l2gw.get_l2gw_body(CONF.network.l2gw_switch)['devices']
l2_gw_body = self._create_l2_gateway(name=gw_name, devices=devices)
segmentation_id = l2_gw_body['l2_gateway']['devices'][0][
'interfaces'][0]['segmentation_id']
self._create_l2_gw_connection(l2_gw_body, network['id'])
tunnel_key = network_body['network']['provider:segmentation_id']
port = self.admin_client.list_ports()
self.validate_ovsdb(segmentation_id, port, network['id'], tunnel_key)
def test_multiple_connections(self):
# Create first connection and validate
network = self._setup_network_and_server()
network_body = self.admin_client.show_network(network['id'])
gw_name = data_utils.rand_name('l2gw')
devices = base_l2gw.get_l2gw_body(CONF.network.l2gw_switch)['devices']
l2_gw_body = self._create_l2_gateway(name=gw_name, devices=devices)
segmentation_id = l2_gw_body['l2_gateway']['devices'][0][
'interfaces'][0]['segmentation_id']
self._create_l2_gw_connection(l2_gw_body, network['id'])
tunnel_key = network_body['network']['provider:segmentation_id']
port = self.admin_client.list_ports()
self.validate_ovsdb(segmentation_id, port, network['id'], tunnel_key)
# Create second connection and validate
network_2 = self._setup_network_and_server()
network_body_2 = self.admin_client.show_network(network_2['id'])
gw_name_2 = data_utils.rand_name('l2gw')
devices_2 = base_l2gw.get_l2gw_body(
CONF.network.l2gw_switch_2)['devices']
l2_gw_body_2 = self._create_l2_gateway(
name=gw_name_2, devices=devices_2)
segmentation_id_2 = l2_gw_body_2['l2_gateway']['devices'][0][
'interfaces'][0]['segmentation_id']
self._create_l2_gw_connection(l2_gw_body_2, network_2['id'])
tunnel_key_2 = network_body_2['network']['provider:segmentation_id']
port_2 = self.admin_client.list_ports()
self.validate_ovsdb(
segmentation_id_2, port_2, network_2['id'], tunnel_key_2)
def test_boot_vm_after_create_connection(self):
network = self.create_network()
self.addCleanup(self.client.delete_network, network['id'])
self.create_subnet(network)
gw_name = data_utils.rand_name('l2gw')
devices = base_l2gw.get_l2gw_body(CONF.network.l2gw_switch)['devices']
l2_gw_body = self._create_l2_gateway(name=gw_name, devices=devices)
segmentation_id = l2_gw_body['l2_gateway']['devices'][0][
'interfaces'][0]['segmentation_id']
self._create_l2_gw_connection(l2_gw_body, network['id'])
name = data_utils.rand_name('server-smoke')
server_id = self._create_server(name, network=network['id'])
self.addCleanup(self._delete_server, server_id)
network_body = self.admin_client.show_network(network['id'])
segmentation_id = l2_gw_body['l2_gateway']['devices'][0][
'interfaces'][0]['segmentation_id']
tunnel_key = network_body['network']['provider:segmentation_id']
port = self.admin_client.list_ports()
self.validate_ovsdb(segmentation_id, port, network['id'], tunnel_key)
def test_create_new_connection_after_deleting_old_one(self):
network = self._setup_network_and_server()
network_body = self.admin_client.show_network(network['id'])
gw_name = data_utils.rand_name('l2gw')
devices = base_l2gw.get_l2gw_body(CONF.network.l2gw_switch)['devices']
l2_gw_body = self._create_l2_gateway(name=gw_name, devices=devices)
segmentation_id = l2_gw_body['l2_gateway']['devices'][0][
'interfaces'][0]['segmentation_id']
# Create a connection and validate ovsdb
l2gw_connection = self._create_l2_gw_connection(
l2_gw_body, network['id'], explicit=True)
tunnel_key = network_body['network']['provider:segmentation_id']
port = self.admin_client.list_ports()
self.validate_ovsdb(segmentation_id, port, network['id'], tunnel_key)
# Delete and create new connection and validate ovsdb
self.admin_client.delete_l2_gateway_connection(
l2gw_connection['l2_gateway_connection']['id'])
self._create_l2_gw_connection(l2_gw_body, network['id'])
self.validate_ovsdb(segmentation_id, port, network['id'], tunnel_key)

@ -403,7 +403,25 @@ network_group = cfg.OptGroup(name='network',
NetworkGroup = [
cfg.StrOpt('l2gw_switch',
default='',
help='Test'),
help='Switch name ,interface and vlan id information '),
cfg.StrOpt('l2gw_switch_2',
default='',
help='Switch name ,interface and vlan id information'),
cfg.StrOpt('hosts',
default='',
help='Network node and compute node host names and IPs'),
cfg.StrOpt('l2gw_switch_ip',
default='',
help='Switch IP'),
cfg.StrOpt('ovsdb_ip',
default='',
help='IP of ovsdb server'),
cfg.IntOpt('ovsdb_port',
default=6632,
help='Port of ovsdb server'),
cfg.StrOpt('ovsdb_schema_name',
default='',
help='schema name of ovsdb'),
cfg.StrOpt('catalog_type',
default='network',
help='Catalog type of the Neutron service.'),

@ -1,6 +1,12 @@
[l2_gateway]
[network]
#List of switch device,interfaces name and segmentation_ids for l2gateway
l2gw_switch = cell08-5930-01::FortyGigE1/0/1|100
l2gw_switch_2 = cell21-5930-01::FortyGigE1/0/1|101
#l2gw_switch = cell08-5930-01::FortyGigE1/0/1|100#200;FortyGigE1/0/2|300
#l2gw_switch = cell08-5930-01::FortyGigE1/0/1|100#200,cell08-5930-02::FortyGigE1/0/2|300
l2gw_switch_ip = switch_vtep_ip
hosts = cn_host_name:cn_ip, nn_host_name:nn_ip
ovsdb_ip = ovsdb_ip
ovsdb_port = 6632
ovsdb_schema_name = hardware_vtep

Loading…
Cancel
Save