Before Grizzly release, data format of OFC ID mapping tables was changed and there are two types of ID mapping tables for old and new format. This commit migrate data from old mapping tables into new tables, drop old mapping tables and remove the logic handling the old tables. In the db migration scripts, built-in compiler of sqlalchemy does not support "INSERT INTO table (col1, col2,...) (SELECT ....)" format, so a custom sqlalchemy.expression compiling method is defined. Closes-Bug: #1286733 Change-Id: I7dae6b728ab9e10f1dc5d63418a69ee4c26354ea
351 lines
13 KiB
Python
351 lines
13 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2012 NEC Corporation. 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.
|
|
# @author: Ryota MIBU
|
|
|
|
import random
|
|
|
|
import mock
|
|
|
|
from neutron.openstack.common import uuidutils
|
|
from neutron.plugins.nec.common import ofc_client
|
|
from neutron.plugins.nec.db import models as nmodels
|
|
from neutron.plugins.nec import drivers
|
|
from neutron.tests import base
|
|
|
|
|
|
class TestConfig(object):
|
|
"""Configuration for this test."""
|
|
host = '127.0.0.1'
|
|
port = 8888
|
|
|
|
|
|
class TremaDriverTestBase(base.BaseTestCase):
|
|
|
|
driver_name = "trema"
|
|
|
|
def setUp(self):
|
|
super(TremaDriverTestBase, self).setUp()
|
|
self.driver = drivers.get_driver(self.driver_name)(TestConfig)
|
|
self.do_request = mock.patch.object(ofc_client.OFCClient,
|
|
'do_request').start()
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
def get_ofc_item_random_params(self):
|
|
"""create random parameters for ofc_item test."""
|
|
tenant_id = uuidutils.generate_uuid()
|
|
network_id = uuidutils.generate_uuid()
|
|
port_id = uuidutils.generate_uuid()
|
|
mac = ':'.join(['%x' % random.randint(0, 255) for i in xrange(6)])
|
|
portinfo = nmodels.PortInfo(id=port_id, datapath_id="0x123456789",
|
|
port_no=1234, vlan_id=321,
|
|
mac=mac)
|
|
return tenant_id, network_id, portinfo
|
|
|
|
|
|
class TremaDriverNetworkTestBase(TremaDriverTestBase):
|
|
|
|
def test_create_tenant(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
ret = self.driver.create_tenant('dummy_desc', t)
|
|
ofc_t_path = "/tenants/%s" % t
|
|
self.assertEqual(ofc_t_path, ret)
|
|
# There is no API call.
|
|
self.assertEqual(0, self.do_request.call_count)
|
|
|
|
def test_update_tenant(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
path = "/tenants/%s" % t
|
|
self.driver.update_tenant(path, 'dummy_desc')
|
|
# There is no API call.
|
|
self.assertEqual(0, self.do_request.call_count)
|
|
|
|
def testc_delete_tenant(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
path = "/tenants/%s" % t
|
|
self.driver.delete_tenant(path)
|
|
# There is no API call.
|
|
self.assertEqual(0, self.do_request.call_count)
|
|
|
|
def testa_create_network(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
description = "desc of %s" % n
|
|
body = {'id': n, 'description': description}
|
|
ret = self.driver.create_network(t, description, n)
|
|
self.do_request.assert_called_once_with("POST", "/networks", body=body)
|
|
self.assertEqual(ret, '/networks/%s' % n)
|
|
|
|
def testc_delete_network(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
net_path = "/networks/%s" % n
|
|
self.driver.delete_network(net_path)
|
|
self.do_request.assert_called_once_with("DELETE", net_path)
|
|
|
|
|
|
class TremaPortBaseDriverTest(TremaDriverNetworkTestBase):
|
|
|
|
driver_name = "trema_port"
|
|
|
|
def test_filter_supported(self):
|
|
self.assertTrue(self.driver.filter_supported())
|
|
|
|
def testd_create_port(self):
|
|
_t, n, p = self.get_ofc_item_random_params()
|
|
net_path = "/networks/%s" % n
|
|
body = {'id': p.id,
|
|
'datapath_id': p.datapath_id,
|
|
'port': str(p.port_no),
|
|
'vid': str(p.vlan_id)}
|
|
ret = self.driver.create_port(net_path, p, p.id)
|
|
self.do_request.assert_called_once_with(
|
|
"POST", "/networks/%s/ports" % n, body=body)
|
|
self.assertEqual(ret, '/networks/%s/ports/%s' % (n, p.id))
|
|
|
|
def testd_delete_port(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
p_path = "/networks/%s/ports/%s" % (n, p.id)
|
|
self.driver.delete_port(p_path)
|
|
self.do_request.assert_called_once_with("DELETE", p_path)
|
|
|
|
|
|
class TremaPortMACBaseDriverTest(TremaDriverNetworkTestBase):
|
|
|
|
driver_name = "trema_portmac"
|
|
|
|
def test_filter_supported(self):
|
|
self.assertTrue(self.driver.filter_supported())
|
|
|
|
def testd_create_port(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
dummy_port = "dummy-%s" % p.id
|
|
|
|
net_path = "/networks/%s" % n
|
|
path_1 = "/networks/%s/ports" % n
|
|
body_1 = {'id': dummy_port,
|
|
'datapath_id': p.datapath_id,
|
|
'port': str(p.port_no),
|
|
'vid': str(p.vlan_id)}
|
|
path_2 = "/networks/%s/ports/%s/attachments" % (n, dummy_port)
|
|
body_2 = {'id': p.id, 'mac': p.mac}
|
|
path_3 = "/networks/%s/ports/%s" % (n, dummy_port)
|
|
ret = self.driver.create_port(net_path, p, p.id)
|
|
|
|
self.do_request.assert_has_calls([
|
|
mock.call("POST", path_1, body=body_1),
|
|
mock.call("POST", path_2, body=body_2),
|
|
mock.call("DELETE", path_3)
|
|
])
|
|
port_path = "/networks/%s/ports/%s/attachments/%s" % (n, dummy_port,
|
|
p.id)
|
|
self.assertEqual(ret, port_path)
|
|
|
|
def testd_delete_port(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
dummy_port = "dummy-%s" % p.id
|
|
path = "/networks/%s/ports/%s/attachments/%s" % (n, dummy_port, p.id)
|
|
self.driver.delete_port(path)
|
|
self.do_request.assert_called_once_with("DELETE", path)
|
|
|
|
|
|
class TremaMACBaseDriverTest(TremaDriverNetworkTestBase):
|
|
|
|
driver_name = "trema_mac"
|
|
|
|
def test_filter_supported(self):
|
|
self.assertFalse(self.driver.filter_supported())
|
|
|
|
def testd_create_port(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
net_path = "/networks/%s" % n
|
|
path = "/networks/%s/attachments" % n
|
|
body = {'id': p.id, 'mac': p.mac}
|
|
ret = self.driver.create_port(net_path, p, p.id)
|
|
self.do_request.assert_called_once_with("POST", path, body=body)
|
|
self.assertEqual(ret, '/networks/%s/attachments/%s' % (n, p.id))
|
|
|
|
def testd_delete_port(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
path = "/networks/%s/attachments/%s" % (n, p.id)
|
|
self.driver.delete_port(path)
|
|
self.do_request.assert_called_once_with("DELETE", path)
|
|
|
|
|
|
class TremaFilterDriverTest(TremaDriverTestBase):
|
|
def _test_create_filter(self, filter_dict=None, filter_post=None,
|
|
filter_wildcards=None, no_portinfo=False):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
src_mac = ':'.join(['%x' % random.randint(0, 255) for i in xrange(6)])
|
|
if filter_wildcards is None:
|
|
filter_wildcards = []
|
|
|
|
f = {'tenant_id': t,
|
|
'id': uuidutils.generate_uuid(),
|
|
'network_id': n,
|
|
'priority': 123,
|
|
'action': "ACCEPT",
|
|
'in_port': p.id,
|
|
'src_mac': src_mac,
|
|
'dst_mac': "",
|
|
'eth_type': 0,
|
|
'src_cidr': "",
|
|
'dst_cidr': "",
|
|
'src_port': 0,
|
|
'dst_port': 0,
|
|
'protocol': "TCP",
|
|
'admin_state_up': True,
|
|
'status': "ACTIVE"}
|
|
if filter_dict:
|
|
f.update(filter_dict)
|
|
|
|
net_path = "/networks/%s" % n
|
|
|
|
all_wildcards_ofp = ['dl_vlan', 'dl_vlan_pcp', 'nw_tos',
|
|
'in_port', 'dl_src', 'dl_dst',
|
|
'nw_src', 'nw_dst',
|
|
'dl_type', 'nw_proto',
|
|
'tp_src', 'tp_dst']
|
|
all_wildcards_non_ofp = ['in_datapath_id', 'slice']
|
|
|
|
body = {'id': f['id'],
|
|
'action': 'ALLOW',
|
|
'priority': 123,
|
|
'slice': n,
|
|
'in_datapath_id': '0x123456789',
|
|
'in_port': 1234,
|
|
'nw_proto': '0x6',
|
|
'dl_type': '0x800',
|
|
'dl_src': src_mac}
|
|
if filter_post:
|
|
body.update(filter_post)
|
|
|
|
if no_portinfo:
|
|
filter_wildcards += ['in_datapath_id', 'in_port']
|
|
p = None
|
|
|
|
for field in filter_wildcards:
|
|
if field in body:
|
|
del body[field]
|
|
|
|
ofp_wildcards = ["%s:32" % _f if _f in ['nw_src', 'nw_dst'] else _f
|
|
for _f in all_wildcards_ofp if _f not in body]
|
|
body['ofp_wildcards'] = set(ofp_wildcards)
|
|
|
|
non_ofp_wildcards = [_f for _f in all_wildcards_non_ofp
|
|
if _f not in body]
|
|
if non_ofp_wildcards:
|
|
body['wildcards'] = set(non_ofp_wildcards)
|
|
|
|
ret = self.driver.create_filter(net_path, f, p, f['id'])
|
|
# The content of 'body' is checked below.
|
|
self.do_request.assert_called_once_with("POST", "/filters",
|
|
body=mock.ANY)
|
|
self.assertEqual(ret, '/filters/%s' % f['id'])
|
|
|
|
# ofp_wildcards and wildcards in body are comma-separated
|
|
# string but the order of elements are not considered,
|
|
# so we check these fields as set.
|
|
actual_body = self.do_request.call_args[1]['body']
|
|
if 'ofp_wildcards' in actual_body:
|
|
ofp_wildcards = actual_body['ofp_wildcards'].split(',')
|
|
actual_body['ofp_wildcards'] = set(ofp_wildcards)
|
|
if 'wildcards' in actual_body:
|
|
actual_body['wildcards'] = set(actual_body['wildcards'].split(','))
|
|
self.assertEqual(body, actual_body)
|
|
|
|
def test_create_filter_accept(self):
|
|
self._test_create_filter(filter_dict={'action': 'ACCEPT'})
|
|
|
|
def test_create_filter_allow(self):
|
|
self._test_create_filter(filter_dict={'action': 'ALLOW'})
|
|
|
|
def test_create_filter_deny(self):
|
|
self._test_create_filter(filter_dict={'action': 'DENY'},
|
|
filter_post={'action': 'DENY'})
|
|
|
|
def test_create_filter_drop(self):
|
|
self._test_create_filter(filter_dict={'action': 'DROP'},
|
|
filter_post={'action': 'DENY'})
|
|
|
|
def test_create_filter_no_port(self):
|
|
self._test_create_filter(no_portinfo=True)
|
|
|
|
def test_create_filter_src_mac_wildcard(self):
|
|
self._test_create_filter(filter_dict={'src_mac': ''},
|
|
filter_wildcards=['dl_src'])
|
|
|
|
def test_create_filter_dst_mac(self):
|
|
dst_mac = ':'.join(['%x' % random.randint(0, 255) for i in xrange(6)])
|
|
self._test_create_filter(filter_dict={'dst_mac': dst_mac},
|
|
filter_post={'dl_dst': dst_mac})
|
|
|
|
def test_create_filter_src_cidr(self):
|
|
src_cidr = '10.2.0.0/24'
|
|
self._test_create_filter(filter_dict={'src_cidr': src_cidr},
|
|
filter_post={'nw_src': src_cidr})
|
|
|
|
def test_create_filter_dst_cidr(self):
|
|
dst_cidr = '192.168.10.0/24'
|
|
self._test_create_filter(filter_dict={'dst_cidr': dst_cidr},
|
|
filter_post={'nw_dst': dst_cidr})
|
|
|
|
def test_create_filter_proto_icmp(self):
|
|
self._test_create_filter(
|
|
filter_dict={'protocol': 'icmp'},
|
|
filter_post={'dl_type': '0x800', 'nw_proto': '0x1'})
|
|
|
|
def test_create_filter_proto_tcp(self):
|
|
self._test_create_filter(
|
|
filter_dict={'protocol': 'tcp'},
|
|
filter_post={'dl_type': '0x800', 'nw_proto': '0x6'})
|
|
|
|
def test_create_filter_proto_udp(self):
|
|
self._test_create_filter(
|
|
filter_dict={'protocol': 'udp'},
|
|
filter_post={'dl_type': '0x800', 'nw_proto': '0x11'})
|
|
|
|
def test_create_filter_proto_arp(self):
|
|
self._test_create_filter(
|
|
filter_dict={'protocol': 'arp'},
|
|
filter_post={'dl_type': '0x806'},
|
|
filter_wildcards=['nw_proto'])
|
|
|
|
def test_create_filter_proto_misc(self):
|
|
self._test_create_filter(
|
|
filter_dict={'protocol': '0x33', 'eth_type': '0x900'},
|
|
filter_post={'dl_type': '0x900', 'nw_proto': '0x33'})
|
|
|
|
def test_create_filter_proto_misc_dl_type_wildcard(self):
|
|
self._test_create_filter(
|
|
filter_dict={'protocol': '0x33', 'ether_type': ''},
|
|
filter_post={'nw_proto': '0x33'},
|
|
filter_wildcards=['dl_type'])
|
|
|
|
def test_create_filter_proto_wildcard(self):
|
|
self._test_create_filter(
|
|
filter_dict={'protocol': ''},
|
|
filter_wildcards=['dl_type', 'nw_proto'])
|
|
|
|
def test_create_filter_src_dst_port(self):
|
|
self._test_create_filter(filter_dict={'src_port': 8192,
|
|
'dst_port': 4096},
|
|
filter_post={'tp_src': '0x2000',
|
|
'tp_dst': '0x1000'})
|
|
|
|
def testb_delete_filter(self):
|
|
t, n, p = self.get_ofc_item_random_params()
|
|
f_path = "/filters/%s" % uuidutils.generate_uuid()
|
|
self.driver.delete_filter(f_path)
|
|
self.do_request.assert_called_once_with("DELETE", f_path)
|