plugin/nec: Make sure resources on OFC is globally unique.
Fixes bug 1127664 Network cannot be created in NEC plugin when OFC network ID is unique inside a tenant. Some OFC implmenetations generate a network ID unique inside a tenant. In this case generated network IDs on can be duplicated in system-wide. To fix it, this changes resource ID on OFC to REST URI to make sure IDs on OFC globally unique. Fixes bug 1120962 Make sure NEC plugin creates shared networks In Quantum resource relationship is not limited inside a tenant. E.g., a non-owner tenant can create a port on a shared network. To deal with it the provider layer should not be aware of tenants each resource belongs to even when it has a kind of tenant concept. This commit changes ofc_manager to pass a parent resource for resource creation and identify a resouce by REST URI used to access OFC resources. It decouples Quantum resource access model from OFC resource models. OFC IDs created before this commit are also looked up. Primary keys of OFC ID mapping tables are changed to quantum_id because most of all accesses to these mapping tables are done by quantum_id. However the current version of alembic does not support changing primary keys, so new OFC ID mapping tables for tenant, network, port and packet filter are created. Dropping the previous mapping tables will be done along with the data migration logic. This commit also changes the following minor issues. - Make sure ID on ProgrammableFlow OpenFlow controller (PFC) is less than 32 chars. The current PFC accepts only 31 chars max as ID and 127 chars as a description string. - Some database accesses created their own session and did not support subtransactions. Make sure to use context.session passed from the API layer. - Removes Unused methods (update_network, update_port) in trema/pfc drivers. Change-Id: Ib4bb830e5f537c789974fa7b77f06eaeacb65333
This commit is contained in:
parent
4298be01bf
commit
7a7675c748
@ -0,0 +1,84 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 OpenStack LLC
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""NEC plugin sharednet
|
||||||
|
|
||||||
|
Revision ID: 3b54bf9e29f7
|
||||||
|
Revises: 54c2c487e913
|
||||||
|
Create Date: 2013-02-17 09:21:48.287134
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '3b54bf9e29f7'
|
||||||
|
down_revision = '54c2c487e913'
|
||||||
|
|
||||||
|
# Change to ['*'] if this migration applies to all plugins
|
||||||
|
|
||||||
|
migration_for_plugins = [
|
||||||
|
'quantum.plugins.nec.nec_plugin.NECPluginV2'
|
||||||
|
]
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
from quantum.db import migration
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(active_plugin=None, options=None):
|
||||||
|
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'ofctenantmappings',
|
||||||
|
sa.Column('ofc_id', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('quantum_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('quantum_id'),
|
||||||
|
sa.UniqueConstraint('ofc_id')
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
'ofcnetworkmappings',
|
||||||
|
sa.Column('ofc_id', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('quantum_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('quantum_id'),
|
||||||
|
sa.UniqueConstraint('ofc_id')
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
'ofcportmappings',
|
||||||
|
sa.Column('ofc_id', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('quantum_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('quantum_id'),
|
||||||
|
sa.UniqueConstraint('ofc_id')
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
'ofcfiltermappings',
|
||||||
|
sa.Column('ofc_id', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('quantum_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('quantum_id'),
|
||||||
|
sa.UniqueConstraint('ofc_id')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(active_plugin=None, options=None):
|
||||||
|
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.drop_table('ofcfiltermappings')
|
||||||
|
op.drop_table('ofcportmappings')
|
||||||
|
op.drop_table('ofcnetworkmappings')
|
||||||
|
op.drop_table('ofctenantmappings')
|
@ -54,9 +54,10 @@ class OFCClient(object):
|
|||||||
return httplib.HTTPConnection
|
return httplib.HTTPConnection
|
||||||
|
|
||||||
def do_request(self, method, action, body=None):
|
def do_request(self, method, action, body=None):
|
||||||
LOG.debug(_("Client request: %(method)s %(action)s [%(body)s]"),
|
LOG.debug(_("Client request: %(host)s:%(port)s "
|
||||||
locals())
|
"%(method)s %(action)s [%(body)s]"),
|
||||||
|
{'host': self.host, 'port': self.port,
|
||||||
|
'method': method, 'action': action, 'body': body})
|
||||||
if type(body) is dict:
|
if type(body) is dict:
|
||||||
body = json.dumps(body)
|
body = json.dumps(body)
|
||||||
try:
|
try:
|
||||||
|
@ -34,6 +34,26 @@ LOG = logging.getLogger(__name__)
|
|||||||
OFP_VLAN_NONE = 0xffff
|
OFP_VLAN_NONE = 0xffff
|
||||||
|
|
||||||
|
|
||||||
|
resource_map = {'ofc_tenant': nmodels.OFCTenantMapping,
|
||||||
|
'ofc_network': nmodels.OFCNetworkMapping,
|
||||||
|
'ofc_port': nmodels.OFCPortMapping,
|
||||||
|
'ofc_packet_filter': nmodels.OFCFilterMapping}
|
||||||
|
|
||||||
|
old_resource_map = {'ofc_tenant': nmodels.OFCTenant,
|
||||||
|
'ofc_network': nmodels.OFCNetwork,
|
||||||
|
'ofc_port': nmodels.OFCPort,
|
||||||
|
'ofc_packet_filter': nmodels.OFCFilter}
|
||||||
|
|
||||||
|
|
||||||
|
# utitlity methods
|
||||||
|
|
||||||
|
def _get_resource_model(resource, old_style):
|
||||||
|
if old_style:
|
||||||
|
return old_resource_map[resource]
|
||||||
|
else:
|
||||||
|
return resource_map[resource]
|
||||||
|
|
||||||
|
|
||||||
def initialize():
|
def initialize():
|
||||||
db.configure_db()
|
db.configure_db()
|
||||||
|
|
||||||
@ -42,30 +62,52 @@ def clear_db(base=model_base.BASEV2):
|
|||||||
db.clear_db(base)
|
db.clear_db(base)
|
||||||
|
|
||||||
|
|
||||||
def get_ofc_item(model, id):
|
def get_ofc_item(session, resource, quantum_id, old_style=False):
|
||||||
session = db.get_session()
|
|
||||||
try:
|
try:
|
||||||
return (session.query(model).
|
model = _get_resource_model(resource, old_style)
|
||||||
filter_by(id=id).
|
return session.query(model).filter_by(quantum_id=quantum_id).one()
|
||||||
one())
|
|
||||||
except sa.orm.exc.NoResultFound:
|
except sa.orm.exc.NoResultFound:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def find_ofc_item(model, quantum_id):
|
def get_ofc_id(session, resource, quantum_id, old_style=False):
|
||||||
session = db.get_session()
|
ofc_item = get_ofc_item(session, resource, quantum_id, old_style)
|
||||||
|
if ofc_item:
|
||||||
|
if old_style:
|
||||||
|
return ofc_item.id
|
||||||
|
else:
|
||||||
|
return ofc_item.ofc_id
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def exists_ofc_item(session, resource, quantum_id, old_style=False):
|
||||||
|
if get_ofc_item(session, resource, quantum_id, old_style):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def find_ofc_item(session, resource, ofc_id, old_style=False):
|
||||||
try:
|
try:
|
||||||
return (session.query(model).
|
model = _get_resource_model(resource, old_style)
|
||||||
filter_by(quantum_id=quantum_id).
|
if old_style:
|
||||||
one())
|
params = dict(id=ofc_id)
|
||||||
|
else:
|
||||||
|
params = dict(ofc_id=ofc_id)
|
||||||
|
return (session.query(model).filter_by(**params).one())
|
||||||
except sa.orm.exc.NoResultFound:
|
except sa.orm.exc.NoResultFound:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def add_ofc_item(model, id, quantum_id):
|
def add_ofc_item(session, resource, quantum_id, ofc_id, old_style=False):
|
||||||
session = db.get_session()
|
|
||||||
try:
|
try:
|
||||||
item = model(id=id, quantum_id=quantum_id)
|
model = _get_resource_model(resource, old_style)
|
||||||
|
if old_style:
|
||||||
|
params = dict(quantum_id=quantum_id, id=ofc_id)
|
||||||
|
else:
|
||||||
|
params = dict(quantum_id=quantum_id, ofc_id=ofc_id)
|
||||||
|
item = model(**params)
|
||||||
session.add(item)
|
session.add(item)
|
||||||
session.flush()
|
session.flush()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@ -74,21 +116,61 @@ def add_ofc_item(model, id, quantum_id):
|
|||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def del_ofc_item(model, id):
|
def del_ofc_item(session, resource, quantum_id, old_style=False,
|
||||||
session = db.get_session()
|
warning=True):
|
||||||
try:
|
try:
|
||||||
item = (session.query(model).
|
model = _get_resource_model(resource, old_style)
|
||||||
filter_by(id=id).
|
item = session.query(model).filter_by(quantum_id=quantum_id).one()
|
||||||
one())
|
|
||||||
session.delete(item)
|
session.delete(item)
|
||||||
session.flush()
|
session.flush()
|
||||||
|
return True
|
||||||
except sa.orm.exc.NoResultFound:
|
except sa.orm.exc.NoResultFound:
|
||||||
LOG.warning(_("_del_ofc_item(): NotFound item "
|
if warning:
|
||||||
"(model=%(model)s, id=%(id)s) "), locals())
|
LOG.warning(_("_del_ofc_item(): NotFound item "
|
||||||
|
"(model=%(model)s, id=%(id)s) "),
|
||||||
|
{'model': model, 'id': quantum_id})
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_portinfo(id):
|
def get_ofc_id_lookup_both(session, resource, quantum_id):
|
||||||
session = db.get_session()
|
ofc_id = get_ofc_id(session, resource, quantum_id)
|
||||||
|
# Lookup old style of OFC mapping table
|
||||||
|
if not ofc_id:
|
||||||
|
ofc_id = get_ofc_id(session, resource, quantum_id,
|
||||||
|
old_style=True)
|
||||||
|
if not ofc_id:
|
||||||
|
reason = (_("NotFound %(resource)s for quantum_id=%(id)s.")
|
||||||
|
% {'resource': resource, 'id': quantum_id})
|
||||||
|
raise nexc.OFCConsistencyBroken(reason=reason)
|
||||||
|
return ofc_id
|
||||||
|
|
||||||
|
|
||||||
|
def exists_ofc_item_lookup_both(session, resource, quantum_id):
|
||||||
|
if exists_ofc_item(session, resource, quantum_id):
|
||||||
|
return True
|
||||||
|
# Check old style of OFC mapping table
|
||||||
|
if exists_ofc_item(session, resource, quantum_id,
|
||||||
|
old_style=True):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def del_ofc_item_lookup_both(session, resource, quantum_id):
|
||||||
|
# Delete the mapping from new style of OFC mapping table
|
||||||
|
if del_ofc_item(session, resource, quantum_id,
|
||||||
|
old_style=False, warning=False):
|
||||||
|
return
|
||||||
|
# Delete old style of OFC mapping table
|
||||||
|
if del_ofc_item(session, resource, quantum_id,
|
||||||
|
old_style=True, warning=False):
|
||||||
|
return
|
||||||
|
# The specified resource not found
|
||||||
|
LOG.warning(_("_del_ofc_item(): NotFound item "
|
||||||
|
"(resource=%(resource)s, id=%(id)s) "),
|
||||||
|
{'resource': resource, 'id': quantum_id})
|
||||||
|
|
||||||
|
|
||||||
|
def get_portinfo(session, id):
|
||||||
try:
|
try:
|
||||||
return (session.query(nmodels.PortInfo).
|
return (session.query(nmodels.PortInfo).
|
||||||
filter_by(id=id).
|
filter_by(id=id).
|
||||||
@ -97,8 +179,8 @@ def get_portinfo(id):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def add_portinfo(id, datapath_id='', port_no=0, vlan_id=OFP_VLAN_NONE, mac=''):
|
def add_portinfo(session, id, datapath_id='', port_no=0,
|
||||||
session = db.get_session()
|
vlan_id=OFP_VLAN_NONE, mac=''):
|
||||||
try:
|
try:
|
||||||
portinfo = nmodels.PortInfo(id=id, datapath_id=datapath_id,
|
portinfo = nmodels.PortInfo(id=id, datapath_id=datapath_id,
|
||||||
port_no=port_no, vlan_id=vlan_id, mac=mac)
|
port_no=port_no, vlan_id=vlan_id, mac=mac)
|
||||||
@ -110,12 +192,9 @@ def add_portinfo(id, datapath_id='', port_no=0, vlan_id=OFP_VLAN_NONE, mac=''):
|
|||||||
return portinfo
|
return portinfo
|
||||||
|
|
||||||
|
|
||||||
def del_portinfo(id):
|
def del_portinfo(session, id):
|
||||||
session = db.get_session()
|
|
||||||
try:
|
try:
|
||||||
portinfo = (session.query(nmodels.PortInfo).
|
portinfo = session.query(nmodels.PortInfo).filter_by(id=id).one()
|
||||||
filter_by(id=id).
|
|
||||||
one())
|
|
||||||
session.delete(portinfo)
|
session.delete(portinfo)
|
||||||
session.flush()
|
session.flush()
|
||||||
except sa.orm.exc.NoResultFound:
|
except sa.orm.exc.NoResultFound:
|
||||||
|
@ -21,6 +21,38 @@ from quantum.db import model_base
|
|||||||
from quantum.db import models_v2
|
from quantum.db import models_v2
|
||||||
|
|
||||||
|
|
||||||
|
"""New mapping tables"""
|
||||||
|
|
||||||
|
|
||||||
|
class OFCId(object):
|
||||||
|
"""Resource ID on OpenFlow Controller"""
|
||||||
|
ofc_id = sa.Column(sa.String(255), unique=True, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class QuantumId(object):
|
||||||
|
"""Logical ID on Quantum"""
|
||||||
|
quantum_id = sa.Column(sa.String(36), primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
|
class OFCTenantMapping(model_base.BASEV2, QuantumId, OFCId):
|
||||||
|
"""Represents a Tenant on OpenFlow Network/Controller."""
|
||||||
|
|
||||||
|
|
||||||
|
class OFCNetworkMapping(model_base.BASEV2, QuantumId, OFCId):
|
||||||
|
"""Represents a Network on OpenFlow Network/Controller."""
|
||||||
|
|
||||||
|
|
||||||
|
class OFCPortMapping(model_base.BASEV2, QuantumId, OFCId):
|
||||||
|
"""Represents a Port on OpenFlow Network/Controller."""
|
||||||
|
|
||||||
|
|
||||||
|
class OFCFilterMapping(model_base.BASEV2, QuantumId, OFCId):
|
||||||
|
"""Represents a Filter on OpenFlow Network/Controller."""
|
||||||
|
|
||||||
|
|
||||||
|
"""Old mapping tables"""
|
||||||
|
|
||||||
|
|
||||||
class HasQuantumId(object):
|
class HasQuantumId(object):
|
||||||
"""Logical ID on Quantum"""
|
"""Logical ID on Quantum"""
|
||||||
quantum_id = sa.Column(sa.String(36), nullable=False)
|
quantum_id = sa.Column(sa.String(36), nullable=False)
|
||||||
|
@ -26,7 +26,9 @@ DRIVER_LIST = {
|
|||||||
'trema_port': DRIVER_PATH % "trema.TremaPortBaseDriver",
|
'trema_port': DRIVER_PATH % "trema.TremaPortBaseDriver",
|
||||||
'trema_portmac': DRIVER_PATH % "trema.TremaPortMACBaseDriver",
|
'trema_portmac': DRIVER_PATH % "trema.TremaPortMACBaseDriver",
|
||||||
'trema_mac': DRIVER_PATH % "trema.TremaMACBaseDriver",
|
'trema_mac': DRIVER_PATH % "trema.TremaMACBaseDriver",
|
||||||
'pfc': DRIVER_PATH % "pfc.PFCDriver"}
|
'pfc': DRIVER_PATH % "pfc.PFCV4Driver",
|
||||||
|
'pfc_v3': DRIVER_PATH % "pfc.PFCV3Driver",
|
||||||
|
'pfc_v4': DRIVER_PATH % "pfc.PFCV4Driver"}
|
||||||
|
|
||||||
|
|
||||||
def get_driver(driver_name):
|
def get_driver(driver_name):
|
||||||
|
@ -14,20 +14,24 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
# @author: Ryota MIBU
|
# @author: Ryota MIBU
|
||||||
|
# @author: Akihiro MOTOKI
|
||||||
|
|
||||||
|
import re
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from quantum.plugins.nec.db import api as ndb
|
||||||
from quantum.plugins.nec.common import ofc_client
|
from quantum.plugins.nec.common import ofc_client
|
||||||
from quantum.plugins.nec import ofc_driver_base
|
from quantum.plugins.nec import ofc_driver_base
|
||||||
|
|
||||||
|
|
||||||
TENANTS_PATH = "/tenants"
|
class PFCDriverBase(ofc_driver_base.OFCDriverBase):
|
||||||
TENANT_PATH = "/tenants/%s"
|
"""Base Class for PDC Drivers
|
||||||
NETWORKS_PATH = "/tenants/%s/networks"
|
|
||||||
NETWORK_PATH = "/tenants/%s/networks/%s"
|
|
||||||
PORTS_PATH = "/tenants/%s/networks/%s/ports"
|
|
||||||
PORT_PATH = "/tenants/%s/networks/%s/ports/%s"
|
|
||||||
|
|
||||||
|
PFCDriverBase provides methods to handle PFC resources through REST API.
|
||||||
|
This uses ofc resource path instead of ofc resource ID.
|
||||||
|
|
||||||
class PFCDriver(ofc_driver_base.OFCDriverBase):
|
The class implements the API for PFC V4.0 or later.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, conf_ofc):
|
def __init__(self, conf_ofc):
|
||||||
self.client = ofc_client.OFCClient(host=conf_ofc.host,
|
self.client = ofc_client.OFCClient(host=conf_ofc.host,
|
||||||
@ -40,62 +44,107 @@ class PFCDriver(ofc_driver_base.OFCDriverBase):
|
|||||||
def filter_supported(cls):
|
def filter_supported(cls):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_tenant(self, description, tenant_id=None):
|
def _generate_pfc_str(self, raw_str):
|
||||||
body = {'description': description}
|
"""Generate PFC acceptable String"""
|
||||||
if tenant_id:
|
return re.sub(r'[^0-9a-zA-Z]', '_', raw_str)
|
||||||
body.update({'id': tenant_id})
|
|
||||||
res = self.client.post(TENANTS_PATH, body=body)
|
|
||||||
ofc_tenant_id = res['id']
|
|
||||||
return ofc_tenant_id
|
|
||||||
|
|
||||||
def update_tenant(self, ofc_tenant_id, description):
|
def _generate_pfc_id(self, id_str):
|
||||||
path = TENANT_PATH % ofc_tenant_id
|
"""Generate ID on PFC
|
||||||
body = {'description': description}
|
|
||||||
res = self.client.put(path, body=body)
|
Currently, PFC ID must be less than 32.
|
||||||
|
Shorten UUID string length from 36 to 31 by follows:
|
||||||
|
* delete UUID Version and hyphen (see RFC4122)
|
||||||
|
* ensure str length
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# openstack.common.uuidutils.is_uuid_like() returns
|
||||||
|
# False for KeyStone tenant_id, so uuid.UUID is used
|
||||||
|
# directly here to accept tenant_id as UUID string
|
||||||
|
uuid_str = str(uuid.UUID(id_str)).replace('-', '')
|
||||||
|
uuid_no_version = uuid_str[:12] + uuid_str[13:]
|
||||||
|
return uuid_no_version[:31]
|
||||||
|
except:
|
||||||
|
return self._generate_pfc_str(id_str)[:31]
|
||||||
|
|
||||||
|
def _generate_pfc_description(self, desc):
|
||||||
|
"""Generate Description on PFC
|
||||||
|
|
||||||
|
Currently, PFC Description must be less than 128.
|
||||||
|
"""
|
||||||
|
return self._generate_pfc_str(desc)[:127]
|
||||||
|
|
||||||
|
def create_tenant(self, description, tenant_id=None):
|
||||||
|
ofc_tenant_id = self._generate_pfc_id(tenant_id)
|
||||||
|
body = {'id': ofc_tenant_id}
|
||||||
|
res = self.client.post('/tenants', body=body)
|
||||||
|
return '/tenants/' + ofc_tenant_id
|
||||||
|
|
||||||
def delete_tenant(self, ofc_tenant_id):
|
def delete_tenant(self, ofc_tenant_id):
|
||||||
path = TENANT_PATH % ofc_tenant_id
|
return self.client.delete(ofc_tenant_id)
|
||||||
return self.client.delete(path)
|
|
||||||
|
|
||||||
def create_network(self, ofc_tenant_id, description, network_id=None):
|
def create_network(self, ofc_tenant_id, description, network_id=None):
|
||||||
path = NETWORKS_PATH % ofc_tenant_id
|
path = "%s/networks" % ofc_tenant_id
|
||||||
body = {'description': description}
|
pfc_desc = self._generate_pfc_description(description)
|
||||||
if network_id:
|
body = {'description': pfc_desc}
|
||||||
body.update({'id': network_id})
|
|
||||||
res = self.client.post(path, body=body)
|
res = self.client.post(path, body=body)
|
||||||
ofc_network_id = res['id']
|
ofc_network_id = res['id']
|
||||||
return ofc_network_id
|
return path + '/' + ofc_network_id
|
||||||
|
|
||||||
def update_network(self, ofc_tenant_id, ofc_network_id, description):
|
def delete_network(self, ofc_network_id):
|
||||||
path = NETWORK_PATH % (ofc_tenant_id, ofc_network_id)
|
return self.client.delete(ofc_network_id)
|
||||||
body = {'description': description}
|
|
||||||
return self.client.put(path, body=body)
|
|
||||||
|
|
||||||
def delete_network(self, ofc_tenant_id, ofc_network_id):
|
def create_port(self, ofc_network_id, portinfo,
|
||||||
path = NETWORK_PATH % (ofc_tenant_id, ofc_network_id)
|
|
||||||
return self.client.delete(path)
|
|
||||||
|
|
||||||
def create_port(self, ofc_tenant_id, ofc_network_id, portinfo,
|
|
||||||
port_id=None):
|
port_id=None):
|
||||||
path = PORTS_PATH % (ofc_tenant_id, ofc_network_id)
|
path = "%s/ports" % ofc_network_id
|
||||||
body = {'datapath_id': portinfo.datapath_id,
|
body = {'datapath_id': portinfo.datapath_id,
|
||||||
'port': str(portinfo.port_no),
|
'port': str(portinfo.port_no),
|
||||||
'vid': str(portinfo.vlan_id)}
|
'vid': str(portinfo.vlan_id)}
|
||||||
if port_id:
|
|
||||||
body.update({'id': port_id})
|
|
||||||
res = self.client.post(path, body=body)
|
res = self.client.post(path, body=body)
|
||||||
ofc_port_id = res['id']
|
ofc_port_id = res['id']
|
||||||
return ofc_port_id
|
return path + '/' + ofc_port_id
|
||||||
|
|
||||||
def update_port(self, ofc_tenant_id, ofc_network_id, portinfo, port_id):
|
def delete_port(self, ofc_port_id):
|
||||||
path = PORT_PATH % (ofc_tenant_id, ofc_network_id, ofc_port_id)
|
return self.client.delete(ofc_port_id)
|
||||||
body = {'datapath_id': portinfo.datapath_id,
|
|
||||||
'port': str(portinfo.port_no),
|
|
||||||
'vid': str(portinfo.vlan_id)}
|
|
||||||
res = self.client.put(path, body=body)
|
|
||||||
ofc_port_id = res['id']
|
|
||||||
return ofc_port_id
|
|
||||||
|
|
||||||
def delete_port(self, ofc_tenant_id, ofc_network_id, ofc_port_id):
|
def convert_ofc_tenant_id(self, context, ofc_tenant_id):
|
||||||
path = PORT_PATH % (ofc_tenant_id, ofc_network_id, ofc_port_id)
|
# If ofc_tenant_id starts with '/', it is already new-style
|
||||||
return self.client.delete(path)
|
if ofc_tenant_id[0] == '/':
|
||||||
|
return ofc_tenant_id
|
||||||
|
return '/tenants/%s' % ofc_tenant_id
|
||||||
|
|
||||||
|
def convert_ofc_network_id(self, context, ofc_network_id, tenant_id):
|
||||||
|
# If ofc_network_id starts with '/', it is already new-style
|
||||||
|
if ofc_network_id[0] == '/':
|
||||||
|
return ofc_network_id
|
||||||
|
|
||||||
|
ofc_tenant_id = ndb.get_ofc_id_lookup_both(
|
||||||
|
context.session, 'ofc_tenant', tenant_id)
|
||||||
|
ofc_tenant_id = self.convert_ofc_tenant_id(context, ofc_tenant_id)
|
||||||
|
params = dict(tenant=ofc_tenant_id, network=ofc_network_id)
|
||||||
|
return '%(tenant)s/networks/%(network)s' % params
|
||||||
|
|
||||||
|
def convert_ofc_port_id(self, context, ofc_port_id, tenant_id, network_id):
|
||||||
|
# If ofc_port_id starts with '/', it is already new-style
|
||||||
|
if ofc_port_id[0] == '/':
|
||||||
|
return ofc_port_id
|
||||||
|
|
||||||
|
ofc_network_id = ndb.get_ofc_id_lookup_both(
|
||||||
|
context.session, 'ofc_network', network_id)
|
||||||
|
ofc_network_id = self.convert_ofc_network_id(
|
||||||
|
context, ofc_network_id, tenant_id)
|
||||||
|
params = dict(network=ofc_network_id, port=ofc_port_id)
|
||||||
|
return '%(network)s/ports/%(port)s' % params
|
||||||
|
|
||||||
|
|
||||||
|
class PFCV3Driver(PFCDriverBase):
|
||||||
|
|
||||||
|
def create_tenant(self, description, tenant_id):
|
||||||
|
ofc_tenant_id = self._generate_pfc_id(tenant_id)
|
||||||
|
return "/tenants/" + ofc_tenant_id
|
||||||
|
|
||||||
|
def delete_tenant(self, ofc_tenant_id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PFCV4Driver(PFCDriverBase):
|
||||||
|
pass
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
# @author: Ryota MIBU
|
# @author: Ryota MIBU
|
||||||
|
# @author: Akihiro MOTOKI
|
||||||
|
|
||||||
from quantum.openstack.common import uuidutils
|
from quantum.openstack.common import uuidutils
|
||||||
|
from quantum.plugins.nec.db import api as ndb
|
||||||
from quantum.plugins.nec.common import ofc_client
|
from quantum.plugins.nec.common import ofc_client
|
||||||
from quantum.plugins.nec import ofc_driver_base
|
from quantum.plugins.nec import ofc_driver_base
|
||||||
|
|
||||||
@ -30,8 +32,17 @@ class TremaDriverBase(ofc_driver_base.OFCDriverBase):
|
|||||||
self.client = ofc_client.OFCClient(host=conf_ofc.host,
|
self.client = ofc_client.OFCClient(host=conf_ofc.host,
|
||||||
port=conf_ofc.port)
|
port=conf_ofc.port)
|
||||||
|
|
||||||
|
def _get_network_id(self, ofc_network_id):
|
||||||
|
# ofc_network_id : /networks/<network-id>
|
||||||
|
return ofc_network_id.split('/')[2]
|
||||||
|
|
||||||
|
def _get_tenant_id(self, tenant_id):
|
||||||
|
# Trema does not use tenant_id, but it returns
|
||||||
|
# /tenants/<tenant_id> format to keep consistency with PFC driver.
|
||||||
|
return '/tenants/' + tenant_id
|
||||||
|
|
||||||
def create_tenant(self, description, tenant_id=None):
|
def create_tenant(self, description, tenant_id=None):
|
||||||
return tenant_id or uuidutils.generate_uuid()
|
return self._get_tenant_id(tenant_id or uuidutils.generate_uuid())
|
||||||
|
|
||||||
def update_tenant(self, ofc_tenant_id, description):
|
def update_tenant(self, ofc_tenant_id, description):
|
||||||
pass
|
pass
|
||||||
@ -43,25 +54,28 @@ class TremaDriverBase(ofc_driver_base.OFCDriverBase):
|
|||||||
ofc_network_id = network_id or uuidutils.generate_uuid()
|
ofc_network_id = network_id or uuidutils.generate_uuid()
|
||||||
body = {'id': ofc_network_id, 'description': description}
|
body = {'id': ofc_network_id, 'description': description}
|
||||||
self.client.post(self.networks_path, body=body)
|
self.client.post(self.networks_path, body=body)
|
||||||
return ofc_network_id
|
return self.network_path % ofc_network_id
|
||||||
|
|
||||||
def update_network(self, ofc_tenant_id, ofc_network_id, description):
|
def delete_network(self, ofc_network_id):
|
||||||
path = self.network_path % ofc_network_id
|
return self.client.delete(ofc_network_id)
|
||||||
body = {'description': description}
|
|
||||||
return self.client.put(path, body=body)
|
|
||||||
|
|
||||||
def delete_network(self, ofc_tenant_id, ofc_network_id):
|
def convert_ofc_tenant_id(self, context, ofc_tenant_id):
|
||||||
path = self.network_path % ofc_network_id
|
# If ofc_network_id starts with '/', it is already new-style
|
||||||
return self.client.delete(path)
|
if ofc_tenant_id[0] == '/':
|
||||||
|
return ofc_tenant_id
|
||||||
|
return self._get_tenant_id(ofc_tenant_id)
|
||||||
|
|
||||||
def update_port(self, ofc_tenant_id, ofc_network_id, ofc_port_id,
|
def convert_ofc_network_id(self, context, ofc_network_id, tenant_id):
|
||||||
portinfo):
|
# If ofc_network_id starts with '/', it is already new-style
|
||||||
self.delete_port(ofc_tenant_id, ofc_network_id, ofc_port_id)
|
if ofc_network_id[0] == '/':
|
||||||
self.create_port(ofc_tenant_id, ofc_network_id, portinfo, ofc_port_id)
|
return ofc_network_id
|
||||||
|
# Trema sliceable switch does not use tenant_id,
|
||||||
|
# so we can convert ofc_network_id from old id only
|
||||||
|
return self.network_path % ofc_network_id
|
||||||
|
|
||||||
|
|
||||||
class TremaFilterDriver(object):
|
class TremaFilterDriver(object):
|
||||||
"""Trema (Sliceable Switch) PacketFilter Driver"""
|
"""Trema (Sliceable Switch) PacketFilter Driver Mixin"""
|
||||||
filters_path = "/filters"
|
filters_path = "/filters"
|
||||||
filter_path = "/filters/%s"
|
filter_path = "/filters/%s"
|
||||||
|
|
||||||
@ -69,7 +83,7 @@ class TremaFilterDriver(object):
|
|||||||
def filter_supported(cls):
|
def filter_supported(cls):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def create_filter(self, ofc_tenant_id, ofc_network_id, filter_dict,
|
def create_filter(self, ofc_network_id, filter_dict,
|
||||||
portinfo=None, filter_id=None):
|
portinfo=None, filter_id=None):
|
||||||
if filter_dict['action'].upper() in ["ACCEPT", "ALLOW"]:
|
if filter_dict['action'].upper() in ["ACCEPT", "ALLOW"]:
|
||||||
ofc_action = "ALLOW"
|
ofc_action = "ALLOW"
|
||||||
@ -77,7 +91,7 @@ class TremaFilterDriver(object):
|
|||||||
ofc_action = "DENY"
|
ofc_action = "DENY"
|
||||||
|
|
||||||
body = {'priority': filter_dict['priority'],
|
body = {'priority': filter_dict['priority'],
|
||||||
'slice': ofc_network_id,
|
'slice': self._get_network_id(ofc_network_id),
|
||||||
'action': ofc_action}
|
'action': ofc_action}
|
||||||
ofp_wildcards = ["dl_vlan", "dl_vlan_pcp", "nw_tos"]
|
ofp_wildcards = ["dl_vlan", "dl_vlan_pcp", "nw_tos"]
|
||||||
|
|
||||||
@ -147,11 +161,16 @@ class TremaFilterDriver(object):
|
|||||||
body['ofp_wildcards'] = ','.join(ofp_wildcards)
|
body['ofp_wildcards'] = ','.join(ofp_wildcards)
|
||||||
|
|
||||||
self.client.post(self.filters_path, body=body)
|
self.client.post(self.filters_path, body=body)
|
||||||
return ofc_filter_id
|
return self.filter_path % ofc_filter_id
|
||||||
|
|
||||||
def delete_filter(self, ofc_tenant_id, ofc_network_id, ofc_filter_id):
|
def delete_filter(self, ofc_filter_id):
|
||||||
path = self.filter_path % ofc_filter_id
|
return self.client.delete(ofc_filter_id)
|
||||||
return self.client.delete(path)
|
|
||||||
|
def convert_ofc_filter_id(self, context, ofc_filter_id):
|
||||||
|
# If ofc_filter_id starts with '/', it is already new-style
|
||||||
|
if ofc_filter_id[0] == '/':
|
||||||
|
return ofc_filter_id
|
||||||
|
return self.filter_path % ofc_filter_id
|
||||||
|
|
||||||
|
|
||||||
class TremaPortBaseDriver(TremaDriverBase, TremaFilterDriver):
|
class TremaPortBaseDriver(TremaDriverBase, TremaFilterDriver):
|
||||||
@ -160,23 +179,36 @@ class TremaPortBaseDriver(TremaDriverBase, TremaFilterDriver):
|
|||||||
TremaPortBaseDriver uses port base binding.
|
TremaPortBaseDriver uses port base binding.
|
||||||
Ports are identified by datapath_id, port_no and vlan_id.
|
Ports are identified by datapath_id, port_no and vlan_id.
|
||||||
"""
|
"""
|
||||||
ports_path = "/networks/%s/ports"
|
ports_path = "%(network)s/ports"
|
||||||
port_path = "/networks/%s/ports/%s"
|
port_path = "%(network)s/ports/%(port)s"
|
||||||
|
|
||||||
def create_port(self, ofc_tenant_id, ofc_network_id, portinfo,
|
def create_port(self, ofc_network_id, portinfo,
|
||||||
port_id=None):
|
port_id=None):
|
||||||
ofc_port_id = port_id or uuidutils.generate_uuid()
|
ofc_port_id = port_id or uuidutils.generate_uuid()
|
||||||
path = self.ports_path % ofc_network_id
|
path = self.ports_path % {'network': ofc_network_id}
|
||||||
body = {'id': ofc_port_id,
|
body = {'id': ofc_port_id,
|
||||||
'datapath_id': portinfo.datapath_id,
|
'datapath_id': portinfo.datapath_id,
|
||||||
'port': str(portinfo.port_no),
|
'port': str(portinfo.port_no),
|
||||||
'vid': str(portinfo.vlan_id)}
|
'vid': str(portinfo.vlan_id)}
|
||||||
self.client.post(path, body=body)
|
self.client.post(path, body=body)
|
||||||
return ofc_port_id
|
return self.port_path % {'network': ofc_network_id,
|
||||||
|
'port': ofc_port_id}
|
||||||
|
|
||||||
def delete_port(self, ofc_tenant_id, ofc_network_id, ofc_port_id):
|
def delete_port(self, ofc_port_id):
|
||||||
path = self.port_path % (ofc_network_id, ofc_port_id)
|
return self.client.delete(ofc_port_id)
|
||||||
return self.client.delete(path)
|
|
||||||
|
def convert_ofc_port_id(self, context, ofc_port_id,
|
||||||
|
tenant_id, network_id):
|
||||||
|
# If ofc_port_id starts with '/', it is already new-style
|
||||||
|
if ofc_port_id[0] == '/':
|
||||||
|
return ofc_port_id
|
||||||
|
|
||||||
|
ofc_network_id = ndb.get_ofc_id_lookup_both(
|
||||||
|
context.session, 'ofc_network', network_id)
|
||||||
|
ofc_network_id = self.convert_ofc_network_id(
|
||||||
|
context, ofc_network_id, tenant_id)
|
||||||
|
return self.port_path % {'network': ofc_network_id,
|
||||||
|
'port': ofc_port_id}
|
||||||
|
|
||||||
|
|
||||||
class TremaPortMACBaseDriver(TremaDriverBase, TremaFilterDriver):
|
class TremaPortMACBaseDriver(TremaDriverBase, TremaFilterDriver):
|
||||||
@ -185,40 +217,54 @@ class TremaPortMACBaseDriver(TremaDriverBase, TremaFilterDriver):
|
|||||||
TremaPortBaseDriver uses port-mac base binding.
|
TremaPortBaseDriver uses port-mac base binding.
|
||||||
Ports are identified by datapath_id, port_no, vlan_id and mac.
|
Ports are identified by datapath_id, port_no, vlan_id and mac.
|
||||||
"""
|
"""
|
||||||
ports_path = "/networks/%s/ports"
|
ports_path = "%(network)s/ports"
|
||||||
port_path = "/networks/%s/ports/%s"
|
port_path = "%(network)s/ports/%(port)s"
|
||||||
attachments_path = "/networks/%s/ports/%s/attachments"
|
attachments_path = "%(network)s/ports/%(port)s/attachments"
|
||||||
attachment_path = "/networks/%s/ports/%s/attachments/%s"
|
attachment_path = "%(network)s/ports/%(port)s/attachments/%(attachment)s"
|
||||||
|
|
||||||
def create_port(self, ofc_tenant_id, ofc_network_id, portinfo,
|
def create_port(self, ofc_network_id, portinfo, port_id=None):
|
||||||
port_id=None):
|
|
||||||
#NOTE: This Driver create slices with Port-MAC Based bindings on Trema
|
#NOTE: This Driver create slices with Port-MAC Based bindings on Trema
|
||||||
# Sliceable. It's REST API requires Port Based binding before you
|
# Sliceable. It's REST API requires Port Based binding before you
|
||||||
# define Port-MAC Based binding.
|
# define Port-MAC Based binding.
|
||||||
ofc_port_id = port_id or uuidutils.generate_uuid()
|
ofc_port_id = port_id or uuidutils.generate_uuid()
|
||||||
dummy_port_id = "dummy-%s" % ofc_port_id
|
dummy_port_id = "dummy-%s" % ofc_port_id
|
||||||
|
|
||||||
path = self.ports_path % ofc_network_id
|
path = self.ports_path % {'network': ofc_network_id}
|
||||||
body = {'id': dummy_port_id,
|
body = {'id': dummy_port_id,
|
||||||
'datapath_id': portinfo.datapath_id,
|
'datapath_id': portinfo.datapath_id,
|
||||||
'port': str(portinfo.port_no),
|
'port': str(portinfo.port_no),
|
||||||
'vid': str(portinfo.vlan_id)}
|
'vid': str(portinfo.vlan_id)}
|
||||||
self.client.post(path, body=body)
|
self.client.post(path, body=body)
|
||||||
|
|
||||||
path = self.attachments_path % (ofc_network_id, dummy_port_id)
|
path = self.attachments_path % {'network': ofc_network_id,
|
||||||
|
'port': dummy_port_id}
|
||||||
body = {'id': ofc_port_id, 'mac': portinfo.mac}
|
body = {'id': ofc_port_id, 'mac': portinfo.mac}
|
||||||
self.client.post(path, body=body)
|
self.client.post(path, body=body)
|
||||||
|
|
||||||
path = self.port_path % (ofc_network_id, dummy_port_id)
|
path = self.port_path % {'network': ofc_network_id,
|
||||||
|
'port': dummy_port_id}
|
||||||
self.client.delete(path)
|
self.client.delete(path)
|
||||||
|
|
||||||
return ofc_port_id
|
return self.attachment_path % {'network': ofc_network_id,
|
||||||
|
'port': dummy_port_id,
|
||||||
|
'attachment': ofc_port_id}
|
||||||
|
|
||||||
def delete_port(self, ofc_tenant_id, ofc_network_id, ofc_port_id):
|
def delete_port(self, ofc_port_id):
|
||||||
dummy_port_id = "dummy-%s" % ofc_port_id
|
return self.client.delete(ofc_port_id)
|
||||||
path = self.attachment_path % (ofc_network_id, dummy_port_id,
|
|
||||||
ofc_port_id)
|
def convert_ofc_port_id(self, context, ofc_port_id, tenant_id, network_id):
|
||||||
return self.client.delete(path)
|
# If ofc_port_id starts with '/', it is already new-style
|
||||||
|
if ofc_port_id[0] == '/':
|
||||||
|
return ofc_port_id
|
||||||
|
|
||||||
|
ofc_network_id = ndb.get_ofc_id_lookup_both(
|
||||||
|
context.session, 'ofc_network', network_id)
|
||||||
|
ofc_network_id = self.convert_ofc_network_id(
|
||||||
|
context, ofc_network_id, tenant_id)
|
||||||
|
dummy_port_id = 'dummy-%s' % ofc_port_id
|
||||||
|
return self.attachment_path % {'network': ofc_network_id,
|
||||||
|
'port': dummy_port_id,
|
||||||
|
'attachment': ofc_port_id}
|
||||||
|
|
||||||
|
|
||||||
class TremaMACBaseDriver(TremaDriverBase):
|
class TremaMACBaseDriver(TremaDriverBase):
|
||||||
@ -227,21 +273,32 @@ class TremaMACBaseDriver(TremaDriverBase):
|
|||||||
TremaPortBaseDriver uses mac base binding.
|
TremaPortBaseDriver uses mac base binding.
|
||||||
Ports are identified by mac.
|
Ports are identified by mac.
|
||||||
"""
|
"""
|
||||||
attachments_path = "/networks/%s/attachments"
|
attachments_path = "%(network)s/attachments"
|
||||||
attachment_path = "/networks/%s/attachments/%s"
|
attachment_path = "%(network)s/attachments/%(attachment)s"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def filter_supported(cls):
|
def filter_supported(cls):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_port(self, ofc_tenant_id, ofc_network_id, portinfo,
|
def create_port(self, ofc_network_id, portinfo, port_id=None):
|
||||||
port_id=None):
|
|
||||||
ofc_port_id = port_id or uuidutils.generate_uuid()
|
ofc_port_id = port_id or uuidutils.generate_uuid()
|
||||||
path = self.attachments_path % ofc_network_id
|
path = self.attachments_path % {'network': ofc_network_id}
|
||||||
body = {'id': ofc_port_id, 'mac': portinfo.mac}
|
body = {'id': ofc_port_id, 'mac': portinfo.mac}
|
||||||
self.client.post(path, body=body)
|
self.client.post(path, body=body)
|
||||||
return ofc_port_id
|
return self.attachment_path % {'network': ofc_network_id,
|
||||||
|
'attachment': ofc_port_id}
|
||||||
|
|
||||||
def delete_port(self, ofc_tenant_id, ofc_network_id, ofc_port_id):
|
def delete_port(self, ofc_port_id):
|
||||||
path = self.attachment_path % (ofc_network_id, ofc_port_id)
|
return self.client.delete(ofc_port_id)
|
||||||
return self.client.delete(path)
|
|
||||||
|
def convert_ofc_port_id(self, context, ofc_port_id, tenant_id, network_id):
|
||||||
|
# If ofc_port_id starts with '/', it is already new-style
|
||||||
|
if ofc_port_id[0] == '/':
|
||||||
|
return ofc_port_id
|
||||||
|
|
||||||
|
ofc_network_id = ndb.get_ofc_id_lookup_both(
|
||||||
|
context.session, 'ofc_network', network_id)
|
||||||
|
ofc_network_id = self.convert_ofc_network_id(
|
||||||
|
context, ofc_network_id, tenant_id)
|
||||||
|
return self.attachment_path % {'network': ofc_network_id,
|
||||||
|
'attachment': ofc_port_id}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
# @author: Ryota MIBU
|
# @author: Ryota MIBU
|
||||||
|
# @author: Akihiro MOTOKI
|
||||||
|
|
||||||
from quantum.agent import securitygroups_rpc as sg_rpc
|
from quantum.agent import securitygroups_rpc as sg_rpc
|
||||||
from quantum.common import constants as q_const
|
from quantum.common import constants as q_const
|
||||||
@ -141,7 +142,7 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
LOG.debug(_("activate_port_if_ready(): skip, "
|
LOG.debug(_("activate_port_if_ready(): skip, "
|
||||||
"network.admin_state_up is False."))
|
"network.admin_state_up is False."))
|
||||||
port_status = OperationalStatus.DOWN
|
port_status = OperationalStatus.DOWN
|
||||||
elif not ndb.get_portinfo(port['id']):
|
elif not ndb.get_portinfo(context.session, port['id']):
|
||||||
LOG.debug(_("activate_port_if_ready(): skip, "
|
LOG.debug(_("activate_port_if_ready(): skip, "
|
||||||
"no portinfo for this port."))
|
"no portinfo for this port."))
|
||||||
port_status = OperationalStatus.DOWN
|
port_status = OperationalStatus.DOWN
|
||||||
@ -160,14 +161,12 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
in_port=port)
|
in_port=port)
|
||||||
|
|
||||||
if port_status in [OperationalStatus.ACTIVE]:
|
if port_status in [OperationalStatus.ACTIVE]:
|
||||||
if self.ofc.exists_ofc_port(port['id']):
|
if self.ofc.exists_ofc_port(context, port['id']):
|
||||||
LOG.debug(_("activate_port_if_ready(): skip, "
|
LOG.debug(_("activate_port_if_ready(): skip, "
|
||||||
"ofc_port already exists."))
|
"ofc_port already exists."))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self.ofc.create_ofc_port(port['tenant_id'],
|
self.ofc.create_ofc_port(context, port['id'], port)
|
||||||
port['network_id'],
|
|
||||||
port['id'])
|
|
||||||
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
||||||
reason = _("create_ofc_port() failed due to %s") % exc
|
reason = _("create_ofc_port() failed due to %s") % exc
|
||||||
LOG.error(reason)
|
LOG.error(reason)
|
||||||
@ -183,11 +182,9 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
Deactivate port and packet_filters associated with the port.
|
Deactivate port and packet_filters associated with the port.
|
||||||
"""
|
"""
|
||||||
port_status = OperationalStatus.DOWN
|
port_status = OperationalStatus.DOWN
|
||||||
if self.ofc.exists_ofc_port(port['id']):
|
if self.ofc.exists_ofc_port(context, port['id']):
|
||||||
try:
|
try:
|
||||||
self.ofc.delete_ofc_port(port['tenant_id'],
|
self.ofc.delete_ofc_port(context, port['id'], port)
|
||||||
port['network_id'],
|
|
||||||
port['id'])
|
|
||||||
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
||||||
reason = _("delete_ofc_port() failed due to %s") % exc
|
reason = _("delete_ofc_port() failed due to %s") % exc
|
||||||
LOG.error(reason)
|
LOG.error(reason)
|
||||||
@ -228,10 +225,10 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
OperationalStatus.BUILD)
|
OperationalStatus.BUILD)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not self.ofc.exists_ofc_tenant(new_net['tenant_id']):
|
if not self.ofc.exists_ofc_tenant(context, new_net['tenant_id']):
|
||||||
self.ofc.create_ofc_tenant(new_net['tenant_id'])
|
self.ofc.create_ofc_tenant(context, new_net['tenant_id'])
|
||||||
self.ofc.create_ofc_network(new_net['tenant_id'], new_net['id'],
|
self.ofc.create_ofc_network(context, new_net['tenant_id'],
|
||||||
new_net['name'])
|
new_net['id'], new_net['name'])
|
||||||
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
||||||
reason = _("create_network() failed due to %s") % exc
|
reason = _("create_network() failed due to %s") % exc
|
||||||
LOG.error(reason)
|
LOG.error(reason)
|
||||||
@ -250,7 +247,8 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
or deactivate ports and packetfilters associated with the network.
|
or deactivate ports and packetfilters associated with the network.
|
||||||
"""
|
"""
|
||||||
LOG.debug(_("NECPluginV2.update_network() called, "
|
LOG.debug(_("NECPluginV2.update_network() called, "
|
||||||
"id=%(id)s network=%(network)s ."), locals())
|
"id=%(id)s network=%(network)s ."),
|
||||||
|
{'id': id, 'network': network})
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
old_net = super(NECPluginV2, self).get_network(context, id)
|
old_net = super(NECPluginV2, self).get_network(context, id)
|
||||||
@ -311,7 +309,8 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
|
|
||||||
super(NECPluginV2, self).delete_network(context, id)
|
super(NECPluginV2, self).delete_network(context, id)
|
||||||
try:
|
try:
|
||||||
self.ofc.delete_ofc_network(tenant_id, id)
|
# 'net' parameter is required to lookup old OFC mapping
|
||||||
|
self.ofc.delete_ofc_network(context, id, net)
|
||||||
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
||||||
reason = _("delete_network() failed due to %s") % exc
|
reason = _("delete_network() failed due to %s") % exc
|
||||||
# NOTE: The OFC configuration of this network could be remained
|
# NOTE: The OFC configuration of this network could be remained
|
||||||
@ -329,7 +328,7 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
nets = super(NECPluginV2, self).get_networks(context, filters=filters)
|
nets = super(NECPluginV2, self).get_networks(context, filters=filters)
|
||||||
if len(nets) == 0:
|
if len(nets) == 0:
|
||||||
try:
|
try:
|
||||||
self.ofc.delete_ofc_tenant(tenant_id)
|
self.ofc.delete_ofc_tenant(context, tenant_id)
|
||||||
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
||||||
reason = _("delete_ofc_tenant() failed due to %s") % exc
|
reason = _("delete_ofc_tenant() failed due to %s") % exc
|
||||||
LOG.warn(reason)
|
LOG.warn(reason)
|
||||||
@ -384,7 +383,8 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
or deactivate the port and packetfilters associated with it.
|
or deactivate the port and packetfilters associated with it.
|
||||||
"""
|
"""
|
||||||
LOG.debug(_("NECPluginV2.update_port() called, "
|
LOG.debug(_("NECPluginV2.update_port() called, "
|
||||||
"id=%(id)s port=%(port)s ."), locals())
|
"id=%(id)s port=%(port)s ."),
|
||||||
|
{'id': id, 'port': port})
|
||||||
need_port_update_notify = False
|
need_port_update_notify = False
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
old_port = super(NECPluginV2, self).get_port(context, id)
|
old_port = super(NECPluginV2, self).get_port(context, id)
|
||||||
@ -486,20 +486,19 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
|
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
|
||||||
"invalid in_port_id."))
|
"invalid in_port_id."))
|
||||||
pf_status = OperationalStatus.DOWN
|
pf_status = OperationalStatus.DOWN
|
||||||
elif in_port_id and not ndb.get_portinfo(in_port_id):
|
elif in_port_id and not ndb.get_portinfo(context.session, in_port_id):
|
||||||
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
|
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
|
||||||
"no portinfo for in_port."))
|
"no portinfo for in_port."))
|
||||||
pf_status = OperationalStatus.DOWN
|
pf_status = OperationalStatus.DOWN
|
||||||
|
|
||||||
if pf_status in [OperationalStatus.ACTIVE]:
|
if pf_status in [OperationalStatus.ACTIVE]:
|
||||||
if self.ofc.exists_ofc_packet_filter(packet_filter['id']):
|
if self.ofc.exists_ofc_packet_filter(context, packet_filter['id']):
|
||||||
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
|
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
|
||||||
"ofc_packet_filter already exists."))
|
"ofc_packet_filter already exists."))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
(self.ofc.
|
(self.ofc.
|
||||||
create_ofc_packet_filter(packet_filter['tenant_id'],
|
create_ofc_packet_filter(context,
|
||||||
packet_filter['network_id'],
|
|
||||||
packet_filter['id'],
|
packet_filter['id'],
|
||||||
packet_filter))
|
packet_filter))
|
||||||
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
||||||
@ -515,14 +514,12 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
def _deactivate_packet_filter(self, context, packet_filter):
|
def _deactivate_packet_filter(self, context, packet_filter):
|
||||||
"""Deactivate packet_filter by deleting filter from OFC if exixts."""
|
"""Deactivate packet_filter by deleting filter from OFC if exixts."""
|
||||||
pf_status = OperationalStatus.DOWN
|
pf_status = OperationalStatus.DOWN
|
||||||
if not self.ofc.exists_ofc_packet_filter(packet_filter['id']):
|
if not self.ofc.exists_ofc_packet_filter(context, packet_filter['id']):
|
||||||
LOG.debug(_("_deactivate_packet_filter(): skip, "
|
LOG.debug(_("_deactivate_packet_filter(): skip, "
|
||||||
"ofc_packet_filter does not exist."))
|
"ofc_packet_filter does not exist."))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self.ofc.delete_ofc_packet_filter(packet_filter['tenant_id'],
|
self.ofc.delete_ofc_packet_filter(context, packet_filter['id'])
|
||||||
packet_filter['network_id'],
|
|
||||||
packet_filter['id'])
|
|
||||||
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
|
||||||
reason = _("delete_ofc_packet_filter() failed due to "
|
reason = _("delete_ofc_packet_filter() failed due to "
|
||||||
"%s") % exc
|
"%s") % exc
|
||||||
@ -553,7 +550,7 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
"""
|
"""
|
||||||
LOG.debug(_("NECPluginV2.update_packet_filter() called, "
|
LOG.debug(_("NECPluginV2.update_packet_filter() called, "
|
||||||
"id=%(id)s packet_filter=%(packet_filter)s ."),
|
"id=%(id)s packet_filter=%(packet_filter)s ."),
|
||||||
locals())
|
{'id': id, 'packet_filter': packet_filter})
|
||||||
old_pf = super(NECPluginV2, self).get_packet_filter(context, id)
|
old_pf = super(NECPluginV2, self).get_packet_filter(context, id)
|
||||||
new_pf = super(NECPluginV2, self).update_packet_filter(context, id,
|
new_pf = super(NECPluginV2, self).update_packet_filter(context, id,
|
||||||
packet_filter)
|
packet_filter)
|
||||||
@ -655,17 +652,18 @@ class NECPluginV2RPCCallbacks(object):
|
|||||||
"kwargs=%s ."), kwargs)
|
"kwargs=%s ."), kwargs)
|
||||||
topic = kwargs['topic']
|
topic = kwargs['topic']
|
||||||
datapath_id = kwargs['datapath_id']
|
datapath_id = kwargs['datapath_id']
|
||||||
|
session = rpc_context.session
|
||||||
for p in kwargs.get('port_added', []):
|
for p in kwargs.get('port_added', []):
|
||||||
id = p['id']
|
id = p['id']
|
||||||
port = self.plugin.get_port(rpc_context, id)
|
port = self.plugin.get_port(rpc_context, id)
|
||||||
if port and ndb.get_portinfo(id):
|
if port and ndb.get_portinfo(session, id):
|
||||||
ndb.del_portinfo(id)
|
ndb.del_portinfo(session, id)
|
||||||
self.plugin.deactivate_port(rpc_context, port)
|
self.plugin.deactivate_port(rpc_context, port)
|
||||||
ndb.add_portinfo(id, datapath_id, p['port_no'],
|
ndb.add_portinfo(session, id, datapath_id, p['port_no'],
|
||||||
mac=p.get('mac', ''))
|
mac=p.get('mac', ''))
|
||||||
self.plugin.activate_port_if_ready(rpc_context, port)
|
self.plugin.activate_port_if_ready(rpc_context, port)
|
||||||
for id in kwargs.get('port_removed', []):
|
for id in kwargs.get('port_removed', []):
|
||||||
port = self.plugin.get_port(rpc_context, id)
|
port = self.plugin.get_port(rpc_context, id)
|
||||||
if port and ndb.get_portinfo(id):
|
if port and ndb.get_portinfo(session, id):
|
||||||
ndb.del_portinfo(id)
|
ndb.del_portinfo(session, id)
|
||||||
self.plugin.deactivate_port(rpc_context, port)
|
self.plugin.deactivate_port(rpc_context, port)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
# @author: Ryota MIBU
|
# @author: Ryota MIBU
|
||||||
|
# @author: Akihiro MOTOKI
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
@ -53,22 +54,17 @@ class OFCDriverBase(object):
|
|||||||
|
|
||||||
:param ofc_tenant_id: a OFC tenant ID in which a new network belongs.
|
:param ofc_tenant_id: a OFC tenant ID in which a new network belongs.
|
||||||
:param description: A description of this network.
|
:param description: A description of this network.
|
||||||
:param network_id: A hint of a OFC network ID.
|
:param network_id: A hint of an ID of OFC network.
|
||||||
:returns: ID of the network created at OpenFlow Controller.
|
:returns: ID of the network created at OpenFlow Controller.
|
||||||
|
ID returned must be unique in the OpenFlow Controller.
|
||||||
|
If a network is identified in conjunction with other information
|
||||||
|
such as a tenant ID, such information should be included in the ID.
|
||||||
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update_network(self, ofc_tenant_id, ofc_network_id, description):
|
def delete_network(self, ofc_network_id):
|
||||||
"""Update description of specified network.
|
|
||||||
|
|
||||||
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def delete_network(self, ofc_tenant_id, ofc_network_id):
|
|
||||||
"""Delete a netwrok at OpenFlow Controller.
|
"""Delete a netwrok at OpenFlow Controller.
|
||||||
|
|
||||||
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
||||||
@ -76,9 +72,9 @@ class OFCDriverBase(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def create_port(self, ofc_tenant_id, ofc_network_id, portinfo,
|
def create_port(self, ofc_network_id, portinfo,
|
||||||
port_id=None):
|
port_id=None):
|
||||||
"""Create a new port on specified tenant and network at OFC.
|
"""Create a new port on specified network at OFC.
|
||||||
|
|
||||||
:param ofc_network_id: a OFC tenant ID in which a new port belongs.
|
:param ofc_network_id: a OFC tenant ID in which a new port belongs.
|
||||||
:param portinfo: An OpenFlow information of this port.
|
:param portinfo: An OpenFlow information of this port.
|
||||||
@ -87,7 +83,11 @@ class OFCDriverBase(object):
|
|||||||
'vlan_id': VLAN ID that a port tagging.
|
'vlan_id': VLAN ID that a port tagging.
|
||||||
'mac': Mac address.
|
'mac': Mac address.
|
||||||
}
|
}
|
||||||
:param port_id: A hint of a OFC port ID.
|
:param port_id: A hint of an ID of OFC port.
|
||||||
|
ID returned must be unique in the OpenFlow Controller.
|
||||||
|
|
||||||
|
If a port is identified in combination with a network or
|
||||||
|
a tenant, such information should be included in the ID.
|
||||||
|
|
||||||
:returns: ID of the port created at OpenFlow Controller.
|
:returns: ID of the port created at OpenFlow Controller.
|
||||||
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
||||||
@ -95,9 +95,41 @@ class OFCDriverBase(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def delete_port(self, ofc_tenant_id, ofc_network_id, ofc_port_id):
|
def delete_port(self, ofc_port_id):
|
||||||
"""Delete a port at OpenFlow Controller.
|
"""Delete a port at OpenFlow Controller.
|
||||||
|
|
||||||
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
:raises: quantum.plugin.nec.common.exceptions.OFCException
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def convert_ofc_tenant_id(self, context, ofc_tenant_id):
|
||||||
|
"""Convert old-style ofc tenand id to new-style one.
|
||||||
|
|
||||||
|
:param context: quantum context object
|
||||||
|
:param ofc_tenant_id: ofc_tenant_id to be converted
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def convert_ofc_network_id(self, context, ofc_network_id,
|
||||||
|
tenant_id):
|
||||||
|
"""Convert old-style ofc network id to new-style one.
|
||||||
|
|
||||||
|
:param context: quantum context object
|
||||||
|
:param ofc_network_id: ofc_network_id to be converted
|
||||||
|
:param tenant_id: quantum tenant_id of the network
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def convert_ofc_port_id(self, context, ofc_port_id,
|
||||||
|
tenant_id, network_id):
|
||||||
|
"""Convert old-style ofc port id to new-style one.
|
||||||
|
|
||||||
|
:param context: quantum context object
|
||||||
|
:param ofc_port_id: ofc_port_id to be converted
|
||||||
|
:param tenant_id: quantum tenant_id of the port
|
||||||
|
:param network_id: quantum network_id of the port
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
# @author: Ryota MIBU
|
# @author: Ryota MIBU
|
||||||
|
# @author: Akihiro MOTOKI
|
||||||
|
|
||||||
from quantum.plugins.nec.common import config
|
from quantum.plugins.nec.common import config
|
||||||
from quantum.plugins.nec.common import exceptions as nexc
|
from quantum.plugins.nec.common import exceptions as nexc
|
||||||
from quantum.plugins.nec.db import api as ndb
|
from quantum.plugins.nec.db import api as ndb
|
||||||
from quantum.plugins.nec.db import models as nmodels
|
|
||||||
from quantum.plugins.nec import drivers
|
from quantum.plugins.nec import drivers
|
||||||
|
|
||||||
|
|
||||||
@ -31,121 +31,106 @@ class OFCManager(object):
|
|||||||
OFC is identified by a switch ID 'datapath_id' and a port number 'port_no'
|
OFC is identified by a switch ID 'datapath_id' and a port number 'port_no'
|
||||||
of the switch. An ID named as 'ofc_*' is used to identify resource on OFC.
|
of the switch. An ID named as 'ofc_*' is used to identify resource on OFC.
|
||||||
"""
|
"""
|
||||||
resource_map = {'ofc_tenant': nmodels.OFCTenant,
|
|
||||||
'ofc_network': nmodels.OFCNetwork,
|
|
||||||
'ofc_port': nmodels.OFCPort,
|
|
||||||
'ofc_packet_filter': nmodels.OFCFilter}
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.driver = drivers.get_driver(config.OFC.driver)(config.OFC)
|
self.driver = drivers.get_driver(config.OFC.driver)(config.OFC)
|
||||||
|
|
||||||
def _get_ofc_id(self, resource, quantum_id):
|
def _get_ofc_id(self, context, resource, quantum_id):
|
||||||
model = self.resource_map[resource]
|
return ndb.get_ofc_id_lookup_both(context.session,
|
||||||
ofc_item = ndb.find_ofc_item(model, quantum_id)
|
resource, quantum_id)
|
||||||
if not ofc_item:
|
|
||||||
reason = _("NotFound %(resource)s for "
|
|
||||||
"quantum_id=%(quantum_id)s.") % locals()
|
|
||||||
raise nexc.OFCConsistencyBroken(reason=reason)
|
|
||||||
return ofc_item.id
|
|
||||||
|
|
||||||
def _exists_ofc_item(self, resource, quantum_id):
|
def _exists_ofc_item(self, context, resource, quantum_id):
|
||||||
model = self.resource_map[resource]
|
return ndb.exists_ofc_item_lookup_both(context.session,
|
||||||
if ndb.find_ofc_item(model, quantum_id):
|
resource, quantum_id)
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Tenant
|
def _add_ofc_item(self, context, resource, quantum_id, ofc_id):
|
||||||
|
# Ensure a new item is added to the new mapping table
|
||||||
|
ndb.add_ofc_item(context.session, resource, quantum_id, ofc_id)
|
||||||
|
|
||||||
def create_ofc_tenant(self, tenant_id):
|
def _del_ofc_item(self, context, resource, quantum_id):
|
||||||
|
ndb.del_ofc_item_lookup_both(context.session, resource, quantum_id)
|
||||||
|
|
||||||
|
def create_ofc_tenant(self, context, tenant_id):
|
||||||
desc = "ID=%s at OpenStack." % tenant_id
|
desc = "ID=%s at OpenStack." % tenant_id
|
||||||
ofc_tenant_id = self.driver.create_tenant(desc, tenant_id)
|
ofc_tenant_id = self.driver.create_tenant(desc, tenant_id)
|
||||||
ndb.add_ofc_item(nmodels.OFCTenant, ofc_tenant_id, tenant_id)
|
self._add_ofc_item(context, "ofc_tenant", tenant_id, ofc_tenant_id)
|
||||||
|
|
||||||
def exists_ofc_tenant(self, tenant_id):
|
def exists_ofc_tenant(self, context, tenant_id):
|
||||||
return self._exists_ofc_item("ofc_tenant", tenant_id)
|
return self._exists_ofc_item(context, "ofc_tenant", tenant_id)
|
||||||
|
|
||||||
def delete_ofc_tenant(self, tenant_id):
|
def delete_ofc_tenant(self, context, tenant_id):
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
ofc_tenant_id = self._get_ofc_id(context, "ofc_tenant", tenant_id)
|
||||||
|
ofc_tenant_id = self.driver.convert_ofc_tenant_id(
|
||||||
|
context, ofc_tenant_id)
|
||||||
|
|
||||||
self.driver.delete_tenant(ofc_tenant_id)
|
self.driver.delete_tenant(ofc_tenant_id)
|
||||||
ndb.del_ofc_item(nmodels.OFCTenant, ofc_tenant_id)
|
self._del_ofc_item(context, "ofc_tenant", tenant_id)
|
||||||
|
|
||||||
# Network
|
def create_ofc_network(self, context, tenant_id, network_id,
|
||||||
|
network_name=None):
|
||||||
def create_ofc_network(self, tenant_id, network_id, network_name=None):
|
ofc_tenant_id = self._get_ofc_id(context, "ofc_tenant", tenant_id)
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
ofc_tenant_id = self.driver.convert_ofc_tenant_id(
|
||||||
|
context, ofc_tenant_id)
|
||||||
|
|
||||||
desc = "ID=%s Name=%s at Quantum." % (network_id, network_name)
|
desc = "ID=%s Name=%s at Quantum." % (network_id, network_name)
|
||||||
ofc_net_id = self.driver.create_network(ofc_tenant_id, desc,
|
ofc_net_id = self.driver.create_network(ofc_tenant_id, desc,
|
||||||
network_id)
|
network_id)
|
||||||
ndb.add_ofc_item(nmodels.OFCNetwork, ofc_net_id, network_id)
|
self._add_ofc_item(context, "ofc_network", network_id, ofc_net_id)
|
||||||
|
|
||||||
def update_ofc_network(self, tenant_id, network_id, network_name):
|
def exists_ofc_network(self, context, network_id):
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
return self._exists_ofc_item(context, "ofc_network", network_id)
|
||||||
ofc_net_id = self._get_ofc_id("ofc_network", network_id)
|
|
||||||
|
|
||||||
desc = "ID=%s Name=%s at Quantum." % (network_id, network_name)
|
def delete_ofc_network(self, context, network_id, network):
|
||||||
self.driver.update_network(ofc_tenant_id, ofc_net_id, desc)
|
ofc_net_id = self._get_ofc_id(context, "ofc_network", network_id)
|
||||||
|
ofc_net_id = self.driver.convert_ofc_network_id(
|
||||||
|
context, ofc_net_id, network['tenant_id'])
|
||||||
|
self.driver.delete_network(ofc_net_id)
|
||||||
|
self._del_ofc_item(context, "ofc_network", network_id)
|
||||||
|
|
||||||
def exists_ofc_network(self, network_id):
|
def create_ofc_port(self, context, port_id, port):
|
||||||
return self._exists_ofc_item("ofc_network", network_id)
|
ofc_net_id = self._get_ofc_id(context, "ofc_network",
|
||||||
|
port['network_id'])
|
||||||
def delete_ofc_network(self, tenant_id, network_id):
|
ofc_net_id = self.driver.convert_ofc_network_id(
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
context, ofc_net_id, port['tenant_id'])
|
||||||
ofc_net_id = self._get_ofc_id("ofc_network", network_id)
|
portinfo = ndb.get_portinfo(context.session, port_id)
|
||||||
|
|
||||||
self.driver.delete_network(ofc_tenant_id, ofc_net_id)
|
|
||||||
ndb.del_ofc_item(nmodels.OFCNetwork, ofc_net_id)
|
|
||||||
|
|
||||||
# Port
|
|
||||||
|
|
||||||
def create_ofc_port(self, tenant_id, network_id, port_id):
|
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
|
||||||
ofc_net_id = self._get_ofc_id("ofc_network", network_id)
|
|
||||||
portinfo = ndb.get_portinfo(port_id)
|
|
||||||
if not portinfo:
|
if not portinfo:
|
||||||
raise nexc.PortInfoNotFound(id=port_id)
|
raise nexc.PortInfoNotFound(id=port_id)
|
||||||
|
|
||||||
ofc_port_id = self.driver.create_port(ofc_tenant_id, ofc_net_id,
|
ofc_port_id = self.driver.create_port(ofc_net_id, portinfo, port_id)
|
||||||
portinfo, port_id)
|
self._add_ofc_item(context, "ofc_port", port_id, ofc_port_id)
|
||||||
ndb.add_ofc_item(nmodels.OFCPort, ofc_port_id, port_id)
|
|
||||||
|
|
||||||
def exists_ofc_port(self, port_id):
|
def exists_ofc_port(self, context, port_id):
|
||||||
return self._exists_ofc_item("ofc_port", port_id)
|
return self._exists_ofc_item(context, "ofc_port", port_id)
|
||||||
|
|
||||||
def delete_ofc_port(self, tenant_id, network_id, port_id):
|
def delete_ofc_port(self, context, port_id, port):
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
ofc_port_id = self._get_ofc_id(context, "ofc_port", port_id)
|
||||||
ofc_net_id = self._get_ofc_id("ofc_network", network_id)
|
ofc_port_id = self.driver.convert_ofc_port_id(
|
||||||
ofc_port_id = self._get_ofc_id("ofc_port", port_id)
|
context, ofc_port_id, port['tenant_id'], port['network_id'])
|
||||||
|
self.driver.delete_port(ofc_port_id)
|
||||||
|
self._del_ofc_item(context, "ofc_port", port_id)
|
||||||
|
|
||||||
self.driver.delete_port(ofc_tenant_id, ofc_net_id, ofc_port_id)
|
def create_ofc_packet_filter(self, context, filter_id, filter_dict):
|
||||||
ndb.del_ofc_item(nmodels.OFCPort, ofc_port_id)
|
ofc_net_id = self._get_ofc_id(context, "ofc_network",
|
||||||
|
filter_dict['network_id'])
|
||||||
# PacketFilter
|
ofc_net_id = self.driver.convert_ofc_network_id(
|
||||||
|
context, ofc_net_id, filter_dict['tenant_id'])
|
||||||
def create_ofc_packet_filter(self, tenant_id, network_id, filter_id,
|
|
||||||
filter_dict):
|
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
|
||||||
ofc_net_id = self._get_ofc_id("ofc_network", network_id)
|
|
||||||
in_port_id = filter_dict.get('in_port')
|
in_port_id = filter_dict.get('in_port')
|
||||||
portinfo = None
|
portinfo = None
|
||||||
if in_port_id:
|
if in_port_id:
|
||||||
portinfo = ndb.get_portinfo(in_port_id)
|
portinfo = ndb.get_portinfo(context.session, in_port_id)
|
||||||
if not portinfo:
|
if not portinfo:
|
||||||
raise nexc.PortInfoNotFound(id=in_port_id)
|
raise nexc.PortInfoNotFound(id=in_port_id)
|
||||||
|
|
||||||
ofc_pf_id = self.driver.create_filter(ofc_tenant_id, ofc_net_id,
|
ofc_pf_id = self.driver.create_filter(ofc_net_id,
|
||||||
filter_dict, portinfo, filter_id)
|
filter_dict, portinfo, filter_id)
|
||||||
ndb.add_ofc_item(nmodels.OFCFilter, ofc_pf_id, filter_id)
|
self._add_ofc_item(context, "ofc_packet_filter", filter_id, ofc_pf_id)
|
||||||
|
|
||||||
def exists_ofc_packet_filter(self, filter_id):
|
def exists_ofc_packet_filter(self, context, filter_id):
|
||||||
return self._exists_ofc_item("ofc_packet_filter", filter_id)
|
return self._exists_ofc_item(context, "ofc_packet_filter", filter_id)
|
||||||
|
|
||||||
def delete_ofc_packet_filter(self, tenant_id, network_id, filter_id):
|
def delete_ofc_packet_filter(self, context, filter_id):
|
||||||
ofc_tenant_id = self._get_ofc_id("ofc_tenant", tenant_id)
|
ofc_pf_id = self._get_ofc_id(context, "ofc_packet_filter", filter_id)
|
||||||
ofc_net_id = self._get_ofc_id("ofc_network", network_id)
|
ofc_pf_id = self.driver.convert_ofc_filter_id(context, ofc_pf_id)
|
||||||
ofc_pf_id = self._get_ofc_id("ofc_packet_filter", filter_id)
|
|
||||||
|
|
||||||
res = self.driver.delete_filter(ofc_tenant_id, ofc_net_id, ofc_pf_id)
|
res = self.driver.delete_filter(ofc_pf_id)
|
||||||
ndb.del_ofc_item(nmodels.OFCFilter, ofc_pf_id)
|
self._del_ofc_item(context, "ofc_packet_filter", filter_id)
|
||||||
|
@ -32,25 +32,37 @@ class StubOFCDriver(ofc_driver_base.OFCDriverBase):
|
|||||||
def create_network(self, ofc_tenant_id, description, network_id=None):
|
def create_network(self, ofc_tenant_id, description, network_id=None):
|
||||||
return "ofc-" + network_id[:-4]
|
return "ofc-" + network_id[:-4]
|
||||||
|
|
||||||
def update_network(self, ofc_tenant_id, ofc_network_id, description):
|
def update_network(self, ofc_network_id, description):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def delete_network(self, ofc_tenant_id, ofc_network_id):
|
def delete_network(self, ofc_network_id):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_port(self, ofc_tenant_id, ofc_network_id, info, port_id=None):
|
def create_port(self, ofc_network_id, info, port_id=None):
|
||||||
return "ofc-" + port_id[:-4]
|
return "ofc-" + port_id[:-4]
|
||||||
|
|
||||||
def delete_port(self, ofc_tenant_id, ofc_network_id, ofc_port_id):
|
def delete_port(self, ofc_port_id):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def filter_supported(cls):
|
def filter_supported(cls):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def create_filter(self, ofc_tenant_id, ofc_network_id, filter_dict,
|
def create_filter(self, ofc_network_id, filter_dict,
|
||||||
portinfo=None, filter_id=None):
|
portinfo=None, filter_id=None):
|
||||||
return "ofc-" + filter_id[:-4]
|
return "ofc-" + filter_id[:-4]
|
||||||
|
|
||||||
def delete_filter(self, ofc_tenant_id, ofc_network_id, ofc_filter_id):
|
def delete_filter(self, ofc_filter_id):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def convert_ofc_tenant_id(self, context, ofc_tenant_id):
|
||||||
|
return ofc_tenant_id
|
||||||
|
|
||||||
|
def convert_ofc_network_id(self, context, ofc_network_id, tenant_id):
|
||||||
|
return ofc_network_id
|
||||||
|
|
||||||
|
def convert_ofc_port_id(self, context, ofc_port_id, tenant_id, network_id):
|
||||||
|
return ofc_port_id
|
||||||
|
|
||||||
|
def convert_ofc_filter_id(self, context, ofc_filter_id):
|
||||||
|
return ofc_filter_id
|
||||||
|
@ -19,17 +19,19 @@ import random
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from quantum.openstack.common import uuidutils
|
from quantum.openstack.common import uuidutils
|
||||||
|
from quantum.db import api as db_api
|
||||||
from quantum.plugins.nec.common import exceptions as nexc
|
from quantum.plugins.nec.common import exceptions as nexc
|
||||||
from quantum.plugins.nec.db import api as ndb
|
from quantum.plugins.nec.db import api as ndb
|
||||||
from quantum.plugins.nec.db import models as nmodels
|
from quantum.plugins.nec.db import models as nmodels
|
||||||
|
|
||||||
|
|
||||||
class NECPluginV2DBTest(unittest.TestCase):
|
class NECPluginV2DBTestBase(object):
|
||||||
"""Class conisting of NECPluginV2 DB unit tests"""
|
"""Class conisting of NECPluginV2 DB unit tests"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Setup for tests"""
|
"""Setup for tests"""
|
||||||
ndb.initialize()
|
ndb.initialize()
|
||||||
|
self.session = db_api.get_session()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Tear Down"""
|
"""Tear Down"""
|
||||||
@ -42,53 +44,6 @@ class NECPluginV2DBTest(unittest.TestCase):
|
|||||||
none = uuidutils.generate_uuid()
|
none = uuidutils.generate_uuid()
|
||||||
return ofc_id, quantum_id, none
|
return ofc_id, quantum_id, none
|
||||||
|
|
||||||
def testa_add_ofc_item(self):
|
|
||||||
"""test add OFC item"""
|
|
||||||
o, q, n = self.get_ofc_item_random_params()
|
|
||||||
tenant = ndb.add_ofc_item(nmodels.OFCTenant, o, q)
|
|
||||||
self.assertEqual(tenant.id, o)
|
|
||||||
self.assertEqual(tenant.quantum_id, q)
|
|
||||||
|
|
||||||
exception_raised = False
|
|
||||||
try:
|
|
||||||
ndb.add_ofc_item(nmodels.OFCTenant, o, q)
|
|
||||||
except nexc.NECDBException:
|
|
||||||
exception_raised = True
|
|
||||||
self.assertTrue(exception_raised)
|
|
||||||
|
|
||||||
def testb_get_ofc_item(self):
|
|
||||||
"""test get OFC item"""
|
|
||||||
o, q, n = self.get_ofc_item_random_params()
|
|
||||||
ndb.add_ofc_item(nmodels.OFCTenant, o, q)
|
|
||||||
tenant = ndb.get_ofc_item(nmodels.OFCTenant, o)
|
|
||||||
self.assertEqual(tenant.id, o)
|
|
||||||
self.assertEqual(tenant.quantum_id, q)
|
|
||||||
|
|
||||||
tenant_none = ndb.get_ofc_item(nmodels.OFCTenant, n)
|
|
||||||
self.assertEqual(None, tenant_none)
|
|
||||||
|
|
||||||
def testc_find_ofc_item(self):
|
|
||||||
"""test find OFC item"""
|
|
||||||
o, q, n = self.get_ofc_item_random_params()
|
|
||||||
ndb.add_ofc_item(nmodels.OFCTenant, o, q)
|
|
||||||
tenant = ndb.find_ofc_item(nmodels.OFCTenant, q)
|
|
||||||
self.assertEqual(tenant.id, o)
|
|
||||||
self.assertEqual(tenant.quantum_id, q)
|
|
||||||
|
|
||||||
tenant_none = ndb.find_ofc_item(nmodels.OFCTenant, n)
|
|
||||||
self.assertEqual(None, tenant_none)
|
|
||||||
|
|
||||||
def testc_del_ofc_item(self):
|
|
||||||
"""test delete OFC item"""
|
|
||||||
o, q, n = self.get_ofc_item_random_params()
|
|
||||||
ndb.add_ofc_item(nmodels.OFCTenant, o, q)
|
|
||||||
ndb.del_ofc_item(nmodels.OFCTenant, o)
|
|
||||||
|
|
||||||
tenant_none = ndb.get_ofc_item(nmodels.OFCTenant, q)
|
|
||||||
self.assertEqual(None, tenant_none)
|
|
||||||
tenant_none = ndb.find_ofc_item(nmodels.OFCTenant, q)
|
|
||||||
self.assertEqual(None, tenant_none)
|
|
||||||
|
|
||||||
def get_portinfo_random_params(self):
|
def get_portinfo_random_params(self):
|
||||||
"""create random parameters for portinfo test"""
|
"""create random parameters for portinfo test"""
|
||||||
port_id = uuidutils.generate_uuid()
|
port_id = uuidutils.generate_uuid()
|
||||||
@ -99,10 +54,80 @@ class NECPluginV2DBTest(unittest.TestCase):
|
|||||||
none = uuidutils.generate_uuid()
|
none = uuidutils.generate_uuid()
|
||||||
return port_id, datapath_id, port_no, vlan_id, mac, none
|
return port_id, datapath_id, port_no, vlan_id, mac, none
|
||||||
|
|
||||||
|
|
||||||
|
class NECPluginV2DBTest(NECPluginV2DBTestBase,
|
||||||
|
unittest.TestCase):
|
||||||
|
|
||||||
|
def testa_add_ofc_item(self):
|
||||||
|
"""test add OFC item"""
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
tenant = ndb.add_ofc_item(self.session, 'ofc_tenant', q, o)
|
||||||
|
self.assertEqual(tenant.ofc_id, o)
|
||||||
|
self.assertEqual(tenant.quantum_id, q)
|
||||||
|
|
||||||
|
self.assertRaises(nexc.NECDBException,
|
||||||
|
ndb.add_ofc_item,
|
||||||
|
self.session, 'ofc_tenant', q, o)
|
||||||
|
|
||||||
|
def testb_get_ofc_item(self):
|
||||||
|
"""test get OFC item"""
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o)
|
||||||
|
tenant = ndb.get_ofc_item(self.session, 'ofc_tenant', q)
|
||||||
|
self.assertEqual(tenant.ofc_id, o)
|
||||||
|
self.assertEqual(tenant.quantum_id, q)
|
||||||
|
|
||||||
|
tenant_none = ndb.get_ofc_item(self.session, 'ofc_tenant', n)
|
||||||
|
self.assertEqual(None, tenant_none)
|
||||||
|
|
||||||
|
def testb_get_ofc_id(self):
|
||||||
|
"""test get OFC d"""
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o)
|
||||||
|
tenant_id = ndb.get_ofc_id(self.session, 'ofc_tenant', q)
|
||||||
|
self.assertEqual(tenant_id, o)
|
||||||
|
|
||||||
|
tenant_none = ndb.get_ofc_item(self.session, 'ofc_tenant', n)
|
||||||
|
self.assertEqual(None, tenant_none)
|
||||||
|
|
||||||
|
def testb_exists_ofc_item(self):
|
||||||
|
"""test get OFC d"""
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o)
|
||||||
|
ret = ndb.exists_ofc_item(self.session, 'ofc_tenant', q)
|
||||||
|
self.assertTrue(ret)
|
||||||
|
|
||||||
|
tenant_none = ndb.get_ofc_item(self.session, 'ofc_tenant', n)
|
||||||
|
self.assertEqual(None, tenant_none)
|
||||||
|
|
||||||
|
def testc_find_ofc_item(self):
|
||||||
|
"""test find OFC item"""
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o)
|
||||||
|
tenant = ndb.find_ofc_item(self.session, 'ofc_tenant', o)
|
||||||
|
self.assertEqual(tenant.ofc_id, o)
|
||||||
|
self.assertEqual(tenant.quantum_id, q)
|
||||||
|
|
||||||
|
tenant_none = ndb.find_ofc_item(self.session, 'ofc_tenant', n)
|
||||||
|
self.assertEqual(None, tenant_none)
|
||||||
|
|
||||||
|
def testc_del_ofc_item(self):
|
||||||
|
"""test delete OFC item"""
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o)
|
||||||
|
ndb.del_ofc_item(self.session, 'ofc_tenant', q)
|
||||||
|
|
||||||
|
tenant_none = ndb.get_ofc_item(self.session,
|
||||||
|
'ofc_tenant', q)
|
||||||
|
self.assertEqual(None, tenant_none)
|
||||||
|
tenant_none = ndb.find_ofc_item(self.session,
|
||||||
|
'ofc_tenant', o)
|
||||||
|
self.assertEqual(None, tenant_none)
|
||||||
|
|
||||||
def testd_add_portinfo(self):
|
def testd_add_portinfo(self):
|
||||||
"""test add portinfo"""
|
"""test add portinfo"""
|
||||||
i, d, p, v, m, n = self.get_portinfo_random_params()
|
i, d, p, v, m, n = self.get_portinfo_random_params()
|
||||||
portinfo = ndb.add_portinfo(i, d, p, v, m)
|
portinfo = ndb.add_portinfo(self.session, i, d, p, v, m)
|
||||||
self.assertEqual(portinfo.id, i)
|
self.assertEqual(portinfo.id, i)
|
||||||
self.assertEqual(portinfo.datapath_id, d)
|
self.assertEqual(portinfo.datapath_id, d)
|
||||||
self.assertEqual(portinfo.port_no, p)
|
self.assertEqual(portinfo.port_no, p)
|
||||||
@ -111,7 +136,7 @@ class NECPluginV2DBTest(unittest.TestCase):
|
|||||||
|
|
||||||
exception_raised = False
|
exception_raised = False
|
||||||
try:
|
try:
|
||||||
ndb.add_portinfo(i, d, p, v, m)
|
ndb.add_portinfo(self.session, i, d, p, v, m)
|
||||||
except nexc.NECDBException:
|
except nexc.NECDBException:
|
||||||
exception_raised = True
|
exception_raised = True
|
||||||
self.assertTrue(exception_raised)
|
self.assertTrue(exception_raised)
|
||||||
@ -119,23 +144,131 @@ class NECPluginV2DBTest(unittest.TestCase):
|
|||||||
def teste_get_portinfo(self):
|
def teste_get_portinfo(self):
|
||||||
"""test get portinfo"""
|
"""test get portinfo"""
|
||||||
i, d, p, v, m, n = self.get_portinfo_random_params()
|
i, d, p, v, m, n = self.get_portinfo_random_params()
|
||||||
ndb.add_portinfo(i, d, p, v, m)
|
ndb.add_portinfo(self.session, i, d, p, v, m)
|
||||||
portinfo = ndb.get_portinfo(i)
|
portinfo = ndb.get_portinfo(self.session, i)
|
||||||
self.assertEqual(portinfo.id, i)
|
self.assertEqual(portinfo.id, i)
|
||||||
self.assertEqual(portinfo.datapath_id, d)
|
self.assertEqual(portinfo.datapath_id, d)
|
||||||
self.assertEqual(portinfo.port_no, p)
|
self.assertEqual(portinfo.port_no, p)
|
||||||
self.assertEqual(portinfo.vlan_id, v)
|
self.assertEqual(portinfo.vlan_id, v)
|
||||||
self.assertEqual(portinfo.mac, m)
|
self.assertEqual(portinfo.mac, m)
|
||||||
|
|
||||||
portinfo_none = ndb.get_portinfo(n)
|
portinfo_none = ndb.get_portinfo(self.session, n)
|
||||||
self.assertEqual(None, portinfo_none)
|
self.assertEqual(None, portinfo_none)
|
||||||
|
|
||||||
def testf_del_portinfo(self):
|
def testf_del_portinfo(self):
|
||||||
"""test delete portinfo"""
|
"""test delete portinfo"""
|
||||||
i, d, p, v, m, n = self.get_portinfo_random_params()
|
i, d, p, v, m, n = self.get_portinfo_random_params()
|
||||||
ndb.add_portinfo(i, d, p, v, m)
|
ndb.add_portinfo(self.session, i, d, p, v, m)
|
||||||
portinfo = ndb.get_portinfo(i)
|
portinfo = ndb.get_portinfo(self.session, i)
|
||||||
self.assertEqual(portinfo.id, i)
|
self.assertEqual(portinfo.id, i)
|
||||||
ndb.del_portinfo(i)
|
ndb.del_portinfo(self.session, i)
|
||||||
portinfo_none = ndb.get_portinfo(i)
|
portinfo_none = ndb.get_portinfo(self.session, i)
|
||||||
self.assertEqual(None, portinfo_none)
|
self.assertEqual(None, portinfo_none)
|
||||||
|
|
||||||
|
|
||||||
|
class NECPluginV2DBOldMappingTest(NECPluginV2DBTestBase,
|
||||||
|
unittest.TestCase):
|
||||||
|
"""Test related to old ID mapping"""
|
||||||
|
|
||||||
|
# Mapping Table mode
|
||||||
|
OLD = True
|
||||||
|
NEW = False
|
||||||
|
|
||||||
|
def test_add_ofc_item_new(self):
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ret = ndb.add_ofc_item(self.session, 'ofc_tenant', q, o, self.NEW)
|
||||||
|
self.assertEqual(ret.ofc_id, o)
|
||||||
|
self.assertEqual(ret.quantum_id, q)
|
||||||
|
|
||||||
|
ret = ndb.get_ofc_item(self.session, 'ofc_tenant', q, self.NEW)
|
||||||
|
self.assertEqual(ret.ofc_id, o)
|
||||||
|
self.assertEqual(ret.quantum_id, q)
|
||||||
|
ret = ndb.get_ofc_item(self.session, 'ofc_tenant', q, self.OLD)
|
||||||
|
self.assertEqual(ret, None)
|
||||||
|
|
||||||
|
def test_add_ofc_item_old(self):
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ret = ndb.add_ofc_item(self.session, 'ofc_tenant', q, o, self.OLD)
|
||||||
|
self.assertEqual(ret.id, o)
|
||||||
|
self.assertEqual(ret.quantum_id, q)
|
||||||
|
|
||||||
|
ret = ndb.get_ofc_item(self.session, 'ofc_tenant', q, self.NEW)
|
||||||
|
self.assertEqual(ret, None)
|
||||||
|
ret = ndb.get_ofc_item(self.session, 'ofc_tenant', q, self.OLD)
|
||||||
|
self.assertEqual(ret.id, o)
|
||||||
|
self.assertEqual(ret.quantum_id, q)
|
||||||
|
|
||||||
|
def _check_new_old_item(self, method, q_id, exp_new, exp_old):
|
||||||
|
ret = method(self.session, 'ofc_tenant', q_id, self.NEW)
|
||||||
|
self.assertEqual(ret, exp_new)
|
||||||
|
ret = method(self.session, 'ofc_tenant', q_id, self.OLD)
|
||||||
|
self.assertEqual(ret, exp_old)
|
||||||
|
|
||||||
|
def test_get_ofc_id_new(self):
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o, self.NEW)
|
||||||
|
self._check_new_old_item(ndb.get_ofc_id, q, o, None)
|
||||||
|
ret = ndb.get_ofc_id_lookup_both(self.session, 'ofc_tenant', q)
|
||||||
|
self.assertEqual(ret, o)
|
||||||
|
|
||||||
|
def test_get_ofc_id_old(self):
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o, self.OLD)
|
||||||
|
self._check_new_old_item(ndb.get_ofc_id, q, None, o)
|
||||||
|
ret = ndb.get_ofc_id_lookup_both(self.session, 'ofc_tenant', q)
|
||||||
|
self.assertEqual(ret, o)
|
||||||
|
|
||||||
|
def _check_exists_ofc_item(self, mode, exp_new, exp_old):
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
self._check_new_old_item(ndb.exists_ofc_item, q, False, False)
|
||||||
|
self.assertFalse(ndb.exists_ofc_item_lookup_both(
|
||||||
|
self.session, 'ofc_tenant', q))
|
||||||
|
|
||||||
|
ndb.add_ofc_item(self.session, 'ofc_tenant', q, o, mode)
|
||||||
|
self._check_new_old_item(ndb.exists_ofc_item, q, exp_new, exp_old)
|
||||||
|
self.assertTrue(ndb.exists_ofc_item_lookup_both(
|
||||||
|
self.session, 'ofc_tenant', q))
|
||||||
|
|
||||||
|
ndb.del_ofc_item(self.session, 'ofc_tenant', q, mode)
|
||||||
|
self._check_new_old_item(ndb.exists_ofc_item, q, False, False)
|
||||||
|
self.assertFalse(ndb.exists_ofc_item_lookup_both(
|
||||||
|
self.session, 'ofc_tenant', q))
|
||||||
|
|
||||||
|
def test_exists_ofc_item_new(self):
|
||||||
|
self._check_exists_ofc_item(self.NEW, True, False)
|
||||||
|
|
||||||
|
def test_exists_ofc_item_old(self):
|
||||||
|
self._check_exists_ofc_item(self.OLD, False, True)
|
||||||
|
|
||||||
|
def _check_delete_ofc_item(self, mode, detect_mode=False):
|
||||||
|
o, q, n = self.get_ofc_item_random_params()
|
||||||
|
ret = ndb.add_ofc_item(self.session, 'ofc_tenant', q, o, mode)
|
||||||
|
ofc_id = ret.ofc_id if mode == self.NEW else ret.id
|
||||||
|
self.assertEqual(ofc_id, o)
|
||||||
|
self.assertEqual(ret.quantum_id, q)
|
||||||
|
ret = ndb.get_ofc_item(self.session, 'ofc_tenant', q, mode)
|
||||||
|
ofc_id = ret.ofc_id if mode == self.NEW else ret.id
|
||||||
|
self.assertEqual(ofc_id, o)
|
||||||
|
self.assertEqual(ret.quantum_id, q)
|
||||||
|
|
||||||
|
if detect_mode:
|
||||||
|
ndb.del_ofc_item_lookup_both(self.session, 'ofc_tenant', q)
|
||||||
|
else:
|
||||||
|
ndb.del_ofc_item(self.session, 'ofc_tenant', q, mode)
|
||||||
|
|
||||||
|
ret = ndb.get_ofc_item(self.session, 'ofc_tenant', q, self.NEW)
|
||||||
|
self.assertEqual(ret, None)
|
||||||
|
ret = ndb.get_ofc_item(self.session, 'ofc_tenant', q, self.OLD)
|
||||||
|
self.assertEqual(ret, None)
|
||||||
|
|
||||||
|
def test_delete_ofc_item_new(self):
|
||||||
|
self._check_delete_ofc_item(self.NEW)
|
||||||
|
|
||||||
|
def test_delete_ofc_item_old(self):
|
||||||
|
self._check_delete_ofc_item(self.OLD)
|
||||||
|
|
||||||
|
def test_delete_ofc_item_with_auto_detect_new(self):
|
||||||
|
self._check_delete_ofc_item(self.NEW, detect_mode=True)
|
||||||
|
|
||||||
|
def test_delete_ofc_item_old_auto_detect_new(self):
|
||||||
|
self._check_delete_ofc_item(self.OLD, detect_mode=True)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from quantum import context
|
||||||
from quantum.openstack.common import uuidutils
|
from quantum.openstack.common import uuidutils
|
||||||
from quantum.plugins.nec.common import config
|
from quantum.plugins.nec.common import config
|
||||||
from quantum.plugins.nec.db import api as ndb
|
from quantum.plugins.nec.db import api as ndb
|
||||||
@ -24,7 +25,7 @@ from quantum.plugins.nec.db import models as nmodels
|
|||||||
from quantum.plugins.nec import ofc_manager
|
from quantum.plugins.nec import ofc_manager
|
||||||
|
|
||||||
|
|
||||||
class OFCManagerTest(unittest.TestCase):
|
class OFCManagerTestBase(object):
|
||||||
"""Class conisting of OFCManager unit tests"""
|
"""Class conisting of OFCManager unit tests"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -32,6 +33,7 @@ class OFCManagerTest(unittest.TestCase):
|
|||||||
config.CONF.set_override('driver', driver, 'OFC')
|
config.CONF.set_override('driver', driver, 'OFC')
|
||||||
ndb.initialize()
|
ndb.initialize()
|
||||||
self.ofc = ofc_manager.OFCManager()
|
self.ofc = ofc_manager.OFCManager()
|
||||||
|
self.ctx = context.get_admin_context()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
ndb.clear_db()
|
ndb.clear_db()
|
||||||
@ -45,116 +47,230 @@ class OFCManagerTest(unittest.TestCase):
|
|||||||
none = uuidutils.generate_uuid()
|
none = uuidutils.generate_uuid()
|
||||||
return tenant, network, port, _filter, none
|
return tenant, network, port, _filter, none
|
||||||
|
|
||||||
|
|
||||||
|
class OFCManagerTest(OFCManagerTestBase, unittest.TestCase):
|
||||||
def testa_create_ofc_tenant(self):
|
def testa_create_ofc_tenant(self):
|
||||||
"""test create ofc_tenant"""
|
"""test create ofc_tenant"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCTenant, t))
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session, 'ofc_tenant', t))
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCTenant, t))
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session, 'ofc_tenant', t))
|
||||||
tenant = ndb.find_ofc_item(nmodels.OFCTenant, t)
|
tenant = ndb.get_ofc_item(self.ctx.session, 'ofc_tenant', t)
|
||||||
self.assertEqual(tenant.id, "ofc-" + t[:-4])
|
self.assertEqual(tenant.ofc_id, "ofc-" + t[:-4])
|
||||||
|
|
||||||
def testb_exists_ofc_tenant(self):
|
def testb_exists_ofc_tenant(self):
|
||||||
"""test exists_ofc_tenant"""
|
"""test exists_ofc_tenant"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.assertFalse(self.ofc.exists_ofc_tenant(t))
|
self.assertFalse(self.ofc.exists_ofc_tenant(self.ctx, t))
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.assertTrue(self.ofc.exists_ofc_tenant(t))
|
self.assertTrue(self.ofc.exists_ofc_tenant(self.ctx, t))
|
||||||
|
|
||||||
def testc_delete_ofc_tenant(self):
|
def testc_delete_ofc_tenant(self):
|
||||||
"""test delete ofc_tenant"""
|
"""test delete ofc_tenant"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCTenant, t))
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session, 'ofc_tenant', t))
|
||||||
self.ofc.delete_ofc_tenant(t)
|
self.ofc.delete_ofc_tenant(self.ctx, t)
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCTenant, t))
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session, 'ofc_tenant', t))
|
||||||
|
|
||||||
def testd_create_ofc_network(self):
|
def testd_create_ofc_network(self):
|
||||||
"""test create ofc_network"""
|
"""test create ofc_network"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCNetwork, n))
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session, 'ofc_network', n))
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCNetwork, n))
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session, 'ofc_network', n))
|
||||||
network = ndb.find_ofc_item(nmodels.OFCNetwork, n)
|
network = ndb.get_ofc_item(self.ctx.session, 'ofc_network', n)
|
||||||
self.assertEqual(network.id, "ofc-" + n[:-4])
|
self.assertEqual(network.ofc_id, "ofc-" + n[:-4])
|
||||||
|
|
||||||
def teste_exists_ofc_network(self):
|
def teste_exists_ofc_network(self):
|
||||||
"""test exists_ofc_network"""
|
"""test exists_ofc_network"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.assertFalse(self.ofc.exists_ofc_network(n))
|
self.assertFalse(self.ofc.exists_ofc_network(self.ctx, n))
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
self.assertTrue(self.ofc.exists_ofc_network(n))
|
self.assertTrue(self.ofc.exists_ofc_network(self.ctx, n))
|
||||||
|
|
||||||
def testf_delete_ofc_network(self):
|
def testf_delete_ofc_network(self):
|
||||||
"""test delete ofc_network"""
|
"""test delete ofc_network"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCNetwork, n))
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session, 'ofc_network', n))
|
||||||
self.ofc.delete_ofc_network(t, n)
|
self.ofc.delete_ofc_network(self.ctx, n, {'tenant_id': t})
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCNetwork, n))
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session, 'ofc_network', n))
|
||||||
|
|
||||||
def testg_create_ofc_port(self):
|
def testg_create_ofc_port(self):
|
||||||
"""test create ofc_port"""
|
"""test create ofc_port"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
ndb.add_portinfo(p, "0xabc", 1, 65535, "00:11:22:33:44:55")
|
ndb.add_portinfo(self.ctx.session, p, "0xabc", 1, 65535,
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCPort, p))
|
"00:11:22:33:44:55")
|
||||||
self.ofc.create_ofc_port(t, n, p)
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session, 'ofc_port', p))
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCPort, p))
|
port = {'tenant_id': t, 'network_id': n}
|
||||||
port = ndb.find_ofc_item(nmodels.OFCPort, p)
|
self.ofc.create_ofc_port(self.ctx, p, port)
|
||||||
self.assertEqual(port.id, "ofc-" + p[:-4])
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session, 'ofc_port', p))
|
||||||
|
port = ndb.get_ofc_item(self.ctx.session, 'ofc_port', p)
|
||||||
|
self.assertEqual(port.ofc_id, "ofc-" + p[:-4])
|
||||||
|
|
||||||
def testh_exists_ofc_port(self):
|
def testh_exists_ofc_port(self):
|
||||||
"""test exists_ofc_port"""
|
"""test exists_ofc_port"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
ndb.add_portinfo(p, "0xabc", 2, 65535, "00:12:22:33:44:55")
|
ndb.add_portinfo(self.ctx.session, p, "0xabc", 2, 65535,
|
||||||
self.assertFalse(self.ofc.exists_ofc_port(p))
|
"00:12:22:33:44:55")
|
||||||
self.ofc.create_ofc_port(t, n, p)
|
self.assertFalse(self.ofc.exists_ofc_port(self.ctx, p))
|
||||||
self.assertTrue(self.ofc.exists_ofc_port(p))
|
port = {'tenant_id': t, 'network_id': n}
|
||||||
|
self.ofc.create_ofc_port(self.ctx, p, port)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_port(self.ctx, p))
|
||||||
|
|
||||||
def testi_delete_ofc_port(self):
|
def testi_delete_ofc_port(self):
|
||||||
"""test delete ofc_port"""
|
"""test delete ofc_port"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
ndb.add_portinfo(p, "0xabc", 3, 65535, "00:13:22:33:44:55")
|
ndb.add_portinfo(self.ctx.session, p, "0xabc", 3, 65535,
|
||||||
self.ofc.create_ofc_port(t, n, p)
|
"00:13:22:33:44:55")
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCPort, p))
|
port = {'tenant_id': t, 'network_id': n}
|
||||||
self.ofc.delete_ofc_port(t, n, p)
|
self.ofc.create_ofc_port(self.ctx, p, port)
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCPort, p))
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session, 'ofc_port', p))
|
||||||
|
self.ofc.delete_ofc_port(self.ctx, p, port)
|
||||||
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session, 'ofc_port', p))
|
||||||
|
|
||||||
def testj_create_ofc_packet_filter(self):
|
def testj_create_ofc_packet_filter(self):
|
||||||
"""test create ofc_filter"""
|
"""test create ofc_filter"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCFilter, f))
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session,
|
||||||
self.ofc.create_ofc_packet_filter(t, n, f, {})
|
'ofc_packet_filter', f))
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCFilter, f))
|
pf = {'tenant_id': t, 'network_id': n}
|
||||||
_filter = ndb.find_ofc_item(nmodels.OFCFilter, f)
|
self.ofc.create_ofc_packet_filter(self.ctx, f, pf)
|
||||||
self.assertEqual(_filter.id, "ofc-" + f[:-4])
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session,
|
||||||
|
'ofc_packet_filter', f))
|
||||||
|
_filter = ndb.get_ofc_item(self.ctx.session, 'ofc_packet_filter', f)
|
||||||
|
self.assertEqual(_filter.ofc_id, "ofc-" + f[:-4])
|
||||||
|
|
||||||
def testk_exists_ofc_packet_filter(self):
|
def testk_exists_ofc_packet_filter(self):
|
||||||
"""test exists_ofc_packet_filter"""
|
"""test exists_ofc_packet_filter"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
self.assertFalse(self.ofc.exists_ofc_packet_filter(f))
|
self.assertFalse(self.ofc.exists_ofc_packet_filter(self.ctx, f))
|
||||||
self.ofc.create_ofc_packet_filter(t, n, f, {})
|
pf = {'tenant_id': t, 'network_id': n}
|
||||||
self.assertTrue(self.ofc.exists_ofc_packet_filter(f))
|
self.ofc.create_ofc_packet_filter(self.ctx, f, pf)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_packet_filter(self.ctx, f))
|
||||||
|
|
||||||
def testl_delete_ofc_packet_filter(self):
|
def testl_delete_ofc_packet_filter(self):
|
||||||
"""test delete ofc_filter"""
|
"""test delete ofc_filter"""
|
||||||
t, n, p, f, none = self.get_random_params()
|
t, n, p, f, none = self.get_random_params()
|
||||||
self.ofc.create_ofc_tenant(t)
|
self.ofc.create_ofc_tenant(self.ctx, t)
|
||||||
self.ofc.create_ofc_network(t, n)
|
self.ofc.create_ofc_network(self.ctx, t, n)
|
||||||
self.ofc.create_ofc_packet_filter(t, n, f, {})
|
pf = {'tenant_id': t, 'network_id': n}
|
||||||
self.assertTrue(ndb.find_ofc_item(nmodels.OFCFilter, f))
|
self.ofc.create_ofc_packet_filter(self.ctx, f, pf)
|
||||||
self.ofc.delete_ofc_packet_filter(t, n, f)
|
self.assertTrue(ndb.get_ofc_item(self.ctx.session,
|
||||||
self.assertFalse(ndb.find_ofc_item(nmodels.OFCFilter, f))
|
'ofc_packet_filter', f))
|
||||||
|
self.ofc.delete_ofc_packet_filter(self.ctx, f)
|
||||||
|
self.assertFalse(ndb.get_ofc_item(self.ctx.session,
|
||||||
|
'ofc_packet_filter', f))
|
||||||
|
|
||||||
|
|
||||||
|
class OFCManagerTestWithOldMapping(OFCManagerTestBase, unittest.TestCase):
|
||||||
|
|
||||||
|
def test_exists_ofc_tenant(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_tenant(self.ctx, t))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_tenant', t, ofc_t, old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_tenant(self.ctx, t))
|
||||||
|
|
||||||
|
def test_delete_ofc_tenant(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_tenant(self.ctx, t))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_tenant', t, ofc_t, old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_tenant(self.ctx, t))
|
||||||
|
|
||||||
|
self.ofc.delete_ofc_tenant(self.ctx, t)
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_tenant(self.ctx, t))
|
||||||
|
|
||||||
|
def test_exists_ofc_network(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_network(self.ctx, n))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_network', n, ofc_n, old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_network(self.ctx, n))
|
||||||
|
|
||||||
|
def test_delete_ofc_network(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_network(self.ctx, n))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_network', n, ofc_n, old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_network(self.ctx, n))
|
||||||
|
|
||||||
|
net = {'tenant_id': t}
|
||||||
|
self.ofc.delete_ofc_network(self.ctx, n, net)
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_network(self.ctx, n))
|
||||||
|
|
||||||
|
def test_exists_ofc_port(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_port(self.ctx, p))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_port', p, ofc_p, old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_port(self.ctx, p))
|
||||||
|
|
||||||
|
def test_delete_ofc_port(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_port(self.ctx, p))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_port', p, ofc_p, old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_port(self.ctx, p))
|
||||||
|
|
||||||
|
port = {'tenant_id': t, 'network_id': n}
|
||||||
|
self.ofc.delete_ofc_port(self.ctx, p, port)
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_port(self.ctx, p))
|
||||||
|
|
||||||
|
def test_exists_ofc_packet_filter(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_packet_filter(self.ctx, f))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_packet_filter', f, ofc_f,
|
||||||
|
old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_packet_filter(self.ctx, f))
|
||||||
|
|
||||||
|
def test_delete_ofc_packet_filter(self):
|
||||||
|
t, n, p, f, none = self.get_random_params()
|
||||||
|
ofc_t, ofc_n, ofc_p, ofc_f, ofc_none = self.get_random_params()
|
||||||
|
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_packet_filter(self.ctx, f))
|
||||||
|
|
||||||
|
session = self.ctx.session
|
||||||
|
ndb.add_ofc_item(session, 'ofc_packet_filter', f, ofc_f,
|
||||||
|
old_style=True)
|
||||||
|
self.assertTrue(self.ofc.exists_ofc_packet_filter(self.ctx, f))
|
||||||
|
|
||||||
|
self.ofc.delete_ofc_packet_filter(self.ctx, f)
|
||||||
|
self.assertFalse(self.ofc.exists_ofc_packet_filter(self.ctx, f))
|
||||||
|
@ -15,11 +15,16 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
# @author: Ryota MIBU
|
# @author: Ryota MIBU
|
||||||
|
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
import mox
|
import mox
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from quantum import context
|
||||||
from quantum.openstack.common import uuidutils
|
from quantum.openstack.common import uuidutils
|
||||||
from quantum.plugins.nec.common import ofc_client as ofc
|
from quantum.plugins.nec.common import ofc_client as ofc
|
||||||
|
from quantum.plugins.nec.db import api as ndb
|
||||||
from quantum.plugins.nec.db import models as nmodels
|
from quantum.plugins.nec.db import models as nmodels
|
||||||
from quantum.plugins.nec import drivers
|
from quantum.plugins.nec import drivers
|
||||||
|
|
||||||
@ -38,11 +43,13 @@ def _ofc(id):
|
|||||||
return "ofc-%s" % id
|
return "ofc-%s" % id
|
||||||
|
|
||||||
|
|
||||||
class PFCDriverTestBase(unittest.TestCase):
|
class PFCDriverTestBase():
|
||||||
|
|
||||||
|
driver = 'quantum.plugins.nec.drivers.pfc.PFCDriverBase'
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.mox = mox.Mox()
|
self.mox = mox.Mox()
|
||||||
self.driver = drivers.get_driver("pfc")(TestConfig)
|
self.driver = drivers.get_driver(self.driver)(TestConfig)
|
||||||
self.mox.StubOutWithMock(ofc.OFCClient, 'do_request')
|
self.mox.StubOutWithMock(ofc.OFCClient, 'do_request')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@ -58,31 +65,40 @@ class PFCDriverTestBase(unittest.TestCase):
|
|||||||
mac="11:22:33:44:55:66")
|
mac="11:22:33:44:55:66")
|
||||||
return tenant_id, network_id, portinfo
|
return tenant_id, network_id, portinfo
|
||||||
|
|
||||||
def testa_create_tenant(self):
|
def _generate_ofc_tenant_id(self, tenant_id):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
fields = tenant_id.split('-')
|
||||||
description = "desc of %s" % t
|
# Strip 1st character (UUID version) of 3rd field
|
||||||
|
fields[2] = fields[2][1:]
|
||||||
|
return ''.join(fields)
|
||||||
|
|
||||||
|
def get_ofc_description(self, desc):
|
||||||
|
"""OFC description consists of [A-Za-z0-9_]."""
|
||||||
|
return desc.replace('-', '_').replace(' ', '_')
|
||||||
|
|
||||||
|
def _create_tenant(self, t, ofc_t, post_id=False, post_desc=False):
|
||||||
|
tenant_path = '/tenants/%s' % ofc_t
|
||||||
path = "/tenants"
|
path = "/tenants"
|
||||||
body = {'id': t, 'description': description}
|
description = "desc of %s" % t
|
||||||
tenant = {'id': _ofc(t)}
|
body = {}
|
||||||
ofc.OFCClient.do_request("POST", path, body=body).AndReturn(tenant)
|
if post_desc:
|
||||||
|
ofc_description = self.get_ofc_description(description)
|
||||||
|
body['description'] = ofc_description
|
||||||
|
if post_id:
|
||||||
|
body['id'] = ofc_t
|
||||||
|
ofc.OFCClient.do_request("POST", path, body=body)
|
||||||
|
else:
|
||||||
|
ofc.OFCClient.do_request("POST", path, body=body).\
|
||||||
|
AndReturn({'id': ofc_t})
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
ret = self.driver.create_tenant(description, t)
|
ret = self.driver.create_tenant(description, t)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
self.assertEqual(ret, _ofc(t))
|
self.assertEqual(ret, tenant_path)
|
||||||
|
|
||||||
def testb_update_tenant(self):
|
def testa_create_tenant(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
description = "new desc of %s" % t
|
ofc_t = self._generate_ofc_tenant_id(t)
|
||||||
|
self._create_tenant(t, ofc_t, post_id=True)
|
||||||
path = "/tenants/%s" % _ofc(t)
|
|
||||||
body = {'description': description}
|
|
||||||
ofc.OFCClient.do_request("PUT", path, body=body)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
self.driver.update_tenant(_ofc(t), description)
|
|
||||||
self.mox.VerifyAll()
|
|
||||||
|
|
||||||
def testc_delete_tenant(self):
|
def testc_delete_tenant(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
@ -91,68 +107,252 @@ class PFCDriverTestBase(unittest.TestCase):
|
|||||||
ofc.OFCClient.do_request("DELETE", path)
|
ofc.OFCClient.do_request("DELETE", path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_tenant(_ofc(t))
|
self.driver.delete_tenant(path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
def testd_create_network(self):
|
def testd_create_network(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
description = "desc of %s" % n
|
description = "desc of %s" % n
|
||||||
|
ofc_description = self.get_ofc_description(description)
|
||||||
|
|
||||||
path = "/tenants/%s/networks" % _ofc(t)
|
tenant_path = "/tenants/%s" % _ofc(t)
|
||||||
body = {'id': n, 'description': description}
|
post_path = "%s/networks" % tenant_path
|
||||||
|
body = {'description': ofc_description}
|
||||||
network = {'id': _ofc(n)}
|
network = {'id': _ofc(n)}
|
||||||
ofc.OFCClient.do_request("POST", path, body=body).AndReturn(network)
|
ofc.OFCClient.do_request("POST", post_path, body=body).\
|
||||||
|
AndReturn(network)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
ret = self.driver.create_network(_ofc(t), description, n)
|
ret = self.driver.create_network(tenant_path, description, n)
|
||||||
self.mox.VerifyAll()
|
|
||||||
self.assertEqual(ret, _ofc(n))
|
|
||||||
|
|
||||||
def teste_update_network(self):
|
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
|
||||||
description = "desc of %s" % n
|
|
||||||
|
|
||||||
path = "/tenants/%s/networks/%s" % (_ofc(t), _ofc(n))
|
|
||||||
body = {'description': description}
|
|
||||||
ofc.OFCClient.do_request("PUT", path, body=body)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
self.driver.update_network(_ofc(t), _ofc(n), description)
|
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
net_path = "/tenants/%s/networks/%s" % (_ofc(t), _ofc(n))
|
||||||
|
self.assertEqual(ret, net_path)
|
||||||
|
|
||||||
def testf_delete_network(self):
|
def testf_delete_network(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
path = "/tenants/%s/networks/%s" % (_ofc(t), _ofc(n))
|
net_path = "/tenants/%s/networks/%s" % (_ofc(t), _ofc(n))
|
||||||
ofc.OFCClient.do_request("DELETE", path)
|
ofc.OFCClient.do_request("DELETE", net_path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_network(_ofc(t), _ofc(n))
|
self.driver.delete_network(net_path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
def testg_create_port(self):
|
def testg_create_port(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
path = "/tenants/%s/networks/%s/ports" % (_ofc(t), _ofc(n))
|
net_path = "/tenants/%s/networks/%s" % (_ofc(t), _ofc(n))
|
||||||
body = {'id': p.id,
|
post_path = "%s/ports" % net_path
|
||||||
'datapath_id': p.datapath_id,
|
port_path = "/tenants/%s/networks/%s/ports/%s" % (_ofc(t), _ofc(n),
|
||||||
|
_ofc(p.id))
|
||||||
|
body = {'datapath_id': p.datapath_id,
|
||||||
'port': str(p.port_no),
|
'port': str(p.port_no),
|
||||||
'vid': str(p.vlan_id)}
|
'vid': str(p.vlan_id)}
|
||||||
port = {'id': _ofc(p.id)}
|
port = {'id': _ofc(p.id)}
|
||||||
ofc.OFCClient.do_request("POST", path, body=body).AndReturn(port)
|
ofc.OFCClient.do_request("POST", post_path, body=body).AndReturn(port)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
ret = self.driver.create_port(_ofc(t), _ofc(n), p, p.id)
|
ret = self.driver.create_port(net_path, p, p.id)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
self.assertEqual(ret, _ofc(p.id))
|
self.assertEqual(ret, port_path)
|
||||||
|
|
||||||
def testh_delete_port(self):
|
def testh_delete_port(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
path = "/tenants/%s/networks/%s/ports/%s" % (_ofc(t), _ofc(n),
|
port_path = "/tenants/%s/networks/%s/ports/%s" % (_ofc(t), _ofc(n),
|
||||||
_ofc(p.id))
|
_ofc(p.id))
|
||||||
ofc.OFCClient.do_request("DELETE", path)
|
ofc.OFCClient.do_request("DELETE", port_path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_port(_ofc(t), _ofc(n), _ofc(p.id))
|
self.driver.delete_port(port_path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
|
class PFCDriverBaseTest(PFCDriverTestBase, unittest.TestCase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PFCV3DriverTest(PFCDriverTestBase, unittest.TestCase):
|
||||||
|
driver = 'pfc_v3'
|
||||||
|
|
||||||
|
def testa_create_tenant(self):
|
||||||
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.create_tenant('dummy_desc', t)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
ofc_t_path = "/tenants/" + self._generate_ofc_tenant_id(t)
|
||||||
|
self.assertEqual(ofc_t_path, ret)
|
||||||
|
|
||||||
|
def testc_delete_tenant(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PFCV4DriverTest(PFCDriverTestBase, unittest.TestCase):
|
||||||
|
driver = 'pfc_v4'
|
||||||
|
|
||||||
|
|
||||||
|
class PFCDriverStringTest(unittest.TestCase):
|
||||||
|
|
||||||
|
driver = 'quantum.plugins.nec.drivers.pfc.PFCDriverBase'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.driver = drivers.get_driver(self.driver)(TestConfig)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_generate_pfc_id_uuid(self):
|
||||||
|
id_str = uuidutils.generate_uuid()
|
||||||
|
exp_str = (id_str[:14] + id_str[15:]).replace('-', '')[:31]
|
||||||
|
|
||||||
|
ret_str = self.driver._generate_pfc_id(id_str)
|
||||||
|
self.assertEqual(exp_str, ret_str)
|
||||||
|
|
||||||
|
def test_generate_pfc_id_uuid_no_hyphen(self):
|
||||||
|
# Keystone tenant_id style uuid
|
||||||
|
id_str = uuidutils.generate_uuid()
|
||||||
|
id_no_hyphen = id_str.replace('-', '')
|
||||||
|
exp_str = (id_str[:14] + id_str[15:]).replace('-', '')[:31]
|
||||||
|
|
||||||
|
ret_str = self.driver._generate_pfc_id(id_no_hyphen)
|
||||||
|
self.assertEqual(exp_str, ret_str)
|
||||||
|
|
||||||
|
def test_generate_pfc_id_string(self):
|
||||||
|
id_str = uuidutils.generate_uuid() + 'x'
|
||||||
|
exp_str = id_str[:31].replace('-', '_')
|
||||||
|
|
||||||
|
ret_str = self.driver._generate_pfc_id(id_str)
|
||||||
|
self.assertEqual(exp_str, ret_str)
|
||||||
|
|
||||||
|
def test_generate_pfc_desc(self):
|
||||||
|
random_list = [random.choice(string.printable) for x in range(128)]
|
||||||
|
random_str = ''.join(random_list)
|
||||||
|
|
||||||
|
accept_letters = string.letters + string.digits
|
||||||
|
exp_list = [x if x in accept_letters else '_' for x in random_list]
|
||||||
|
exp_str = ''.join(exp_list)[:127]
|
||||||
|
|
||||||
|
ret_str = self.driver._generate_pfc_description(random_str)
|
||||||
|
self.assertEqual(exp_str, ret_str)
|
||||||
|
|
||||||
|
|
||||||
|
class PFCIdConvertTest(unittest.TestCase):
|
||||||
|
driver = 'quantum.plugins.nec.drivers.pfc.PFCDriverBase'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.mox = mox.Mox()
|
||||||
|
self.driver = drivers.get_driver(self.driver)(TestConfig)
|
||||||
|
self.ctx = self.mox.CreateMock(context.Context)
|
||||||
|
self.ctx.session = "session"
|
||||||
|
self.mox.StubOutWithMock(ndb, 'get_ofc_id_lookup_both')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.mox.UnsetStubs()
|
||||||
|
|
||||||
|
def generate_random_ids(self, count=1):
|
||||||
|
if count == 1:
|
||||||
|
return uuidutils.generate_uuid()
|
||||||
|
else:
|
||||||
|
return [uuidutils.generate_uuid() for _ in xrange(count)]
|
||||||
|
|
||||||
|
def test_convert_tenant_id(self):
|
||||||
|
ofc_t_id = self.generate_random_ids(1)
|
||||||
|
print ofc_t_id
|
||||||
|
ret = self.driver.convert_ofc_tenant_id(self.ctx, ofc_t_id)
|
||||||
|
self.assertEqual(ret, '/tenants/%s' % ofc_t_id)
|
||||||
|
|
||||||
|
def test_convert_tenant_id_noconv(self):
|
||||||
|
ofc_t_id = '/tenants/%s' % self.generate_random_ids(1)
|
||||||
|
ret = self.driver.convert_ofc_tenant_id(self.ctx, ofc_t_id)
|
||||||
|
self.assertEqual(ret, ofc_t_id)
|
||||||
|
|
||||||
|
def test_convert_network_id(self):
|
||||||
|
t_id, ofc_t_id, ofc_n_id = self.generate_random_ids(3)
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_tenant', t_id).AndReturn(ofc_t_id)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_network_id(self.ctx, ofc_n_id, t_id)
|
||||||
|
self.assertEqual(ret, ('/tenants/%(tenant)s/networks/%(network)s' %
|
||||||
|
{'tenant': ofc_t_id, 'network': ofc_n_id}))
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_convert_network_id_with_new_tenant_id(self):
|
||||||
|
t_id, ofc_t_id, ofc_n_id = self.generate_random_ids(3)
|
||||||
|
ofc_t_path = '/tenants/%s' % ofc_t_id
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_tenant', t_id).AndReturn(ofc_t_path)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_network_id(self.ctx, ofc_n_id, t_id)
|
||||||
|
self.assertEqual(ret, ('/tenants/%(tenant)s/networks/%(network)s' %
|
||||||
|
{'tenant': ofc_t_id, 'network': ofc_n_id}))
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_convert_network_id_noconv(self):
|
||||||
|
t_id = 'dummy'
|
||||||
|
ofc_t_id, ofc_n_id = self.generate_random_ids(2)
|
||||||
|
ofc_n_id = ('/tenants/%(tenant)s/networks/%(network)s' %
|
||||||
|
{'tenant': ofc_t_id, 'network': ofc_n_id})
|
||||||
|
ret = self.driver.convert_ofc_network_id(self.ctx, ofc_n_id, t_id)
|
||||||
|
self.assertEqual(ret, ofc_n_id)
|
||||||
|
|
||||||
|
def test_convert_port_id(self):
|
||||||
|
t_id, n_id = self.generate_random_ids(2)
|
||||||
|
ofc_t_id, ofc_n_id, ofc_p_id = self.generate_random_ids(3)
|
||||||
|
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_network', n_id).AndReturn(ofc_n_id)
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_tenant', t_id).AndReturn(ofc_t_id)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_port_id(self.ctx, ofc_p_id, t_id, n_id)
|
||||||
|
exp = ('/tenants/%(tenant)s/networks/%(network)s/ports/%(port)s' %
|
||||||
|
{'tenant': ofc_t_id, 'network': ofc_n_id, 'port': ofc_p_id})
|
||||||
|
self.assertEqual(ret, exp)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_convert_port_id_with_new_tenant_id(self):
|
||||||
|
t_id, n_id = self.generate_random_ids(2)
|
||||||
|
ofc_t_id, ofc_n_id, ofc_p_id = self.generate_random_ids(3)
|
||||||
|
|
||||||
|
ofc_t_path = '/tenants/%s' % ofc_t_id
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_network', n_id).AndReturn(ofc_n_id)
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_tenant', t_id).AndReturn(ofc_t_path)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_port_id(self.ctx, ofc_p_id, t_id, n_id)
|
||||||
|
exp = ('/tenants/%(tenant)s/networks/%(network)s/ports/%(port)s' %
|
||||||
|
{'tenant': ofc_t_id, 'network': ofc_n_id, 'port': ofc_p_id})
|
||||||
|
self.assertEqual(ret, exp)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_convert_port_id_with_new_network_id(self):
|
||||||
|
t_id, n_id = self.generate_random_ids(2)
|
||||||
|
ofc_t_id, ofc_n_id, ofc_p_id = self.generate_random_ids(3)
|
||||||
|
|
||||||
|
ofc_n_path = ('/tenants/%(tenant)s/networks/%(network)s' %
|
||||||
|
{'tenant': ofc_t_id, 'network': ofc_n_id})
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_network', n_id).AndReturn(ofc_n_path)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_port_id(self.ctx, ofc_p_id, t_id, n_id)
|
||||||
|
exp = ('/tenants/%(tenant)s/networks/%(network)s/ports/%(port)s' %
|
||||||
|
{'tenant': ofc_t_id, 'network': ofc_n_id, 'port': ofc_p_id})
|
||||||
|
self.assertEqual(ret, exp)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_convert_port_id_noconv(self):
|
||||||
|
t_id = n_id = 'dummy'
|
||||||
|
ofc_t_id, ofc_n_id, ofc_p_id = self.generate_random_ids(3)
|
||||||
|
ofc_p_id = ('/tenants/%(tenant)s/networs/%(network)s/ports/%(port)s'
|
||||||
|
% {'tenant': ofc_t_id, 'network': ofc_n_id,
|
||||||
|
'port': ofc_p_id})
|
||||||
|
ret = self.driver.convert_ofc_port_id(self.ctx, ofc_p_id, t_id, n_id)
|
||||||
|
self.assertEqual(ret, ofc_p_id)
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
import mox
|
import mox
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from quantum import context
|
||||||
from quantum.openstack.common import uuidutils
|
from quantum.openstack.common import uuidutils
|
||||||
from quantum.plugins.nec.common import ofc_client
|
from quantum.plugins.nec.common import ofc_client
|
||||||
|
from quantum.plugins.nec.db import api as ndb
|
||||||
from quantum.plugins.nec.db import models as nmodels
|
from quantum.plugins.nec.db import models as nmodels
|
||||||
from quantum.plugins.nec import drivers
|
from quantum.plugins.nec import drivers
|
||||||
|
|
||||||
@ -63,27 +65,18 @@ class TremaDriverNetworkTestBase(TremaDriverTestBase):
|
|||||||
ofc_client.OFCClient.do_request("POST", "/networks", body=body)
|
ofc_client.OFCClient.do_request("POST", "/networks", body=body)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.create_network(t, description, n)
|
ret = self.driver.create_network(t, description, n)
|
||||||
self.mox.VerifyAll()
|
|
||||||
|
|
||||||
def testb_update_network(self):
|
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
|
||||||
description = "desc of %s" % n
|
|
||||||
|
|
||||||
body = {'description': description}
|
|
||||||
ofc_client.OFCClient.do_request("PUT", "/networks/%s" % n, body=body)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
self.driver.update_network(t, n, description)
|
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
self.assertEqual(ret, '/networks/%s' % n)
|
||||||
|
|
||||||
def testc_delete_network(self):
|
def testc_delete_network(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
ofc_client.OFCClient.do_request("DELETE", "/networks/%s" % n)
|
net_path = "/networks/%s" % n
|
||||||
|
ofc_client.OFCClient.do_request("DELETE", net_path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_network(t, n)
|
self.driver.delete_network(net_path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
@ -92,8 +85,9 @@ class TremaPortBaseDriverTest(TremaDriverNetworkTestBase, unittest.TestCase):
|
|||||||
driver_name = "trema_port"
|
driver_name = "trema_port"
|
||||||
|
|
||||||
def testd_create_port(self):
|
def testd_create_port(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
_t, n, p = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
|
net_path = "/networks/%s" % n
|
||||||
body = {'id': p.id,
|
body = {'id': p.id,
|
||||||
'datapath_id': p.datapath_id,
|
'datapath_id': p.datapath_id,
|
||||||
'port': str(p.port_no),
|
'port': str(p.port_no),
|
||||||
@ -102,17 +96,18 @@ class TremaPortBaseDriverTest(TremaDriverNetworkTestBase, unittest.TestCase):
|
|||||||
"/networks/%s/ports" % n, body=body)
|
"/networks/%s/ports" % n, body=body)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.create_port(t, n, p, p.id)
|
ret = self.driver.create_port(net_path, p, p.id)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
self.assertEqual(ret, '/networks/%s/ports/%s' % (n, p.id))
|
||||||
|
|
||||||
def testd_delete_port(self):
|
def testd_delete_port(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
ofc_client.OFCClient.do_request("DELETE",
|
p_path = "/networks/%s/ports/%s" % (n, p.id)
|
||||||
"/networks/%s/ports/%s" % (n, p.id))
|
ofc_client.OFCClient.do_request("DELETE", p_path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_port(t, n, p.id)
|
self.driver.delete_port(p_path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
@ -125,6 +120,7 @@ class TremaPortMACBaseDriverTest(TremaDriverNetworkTestBase,
|
|||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
dummy_port = "dummy-%s" % p.id
|
dummy_port = "dummy-%s" % p.id
|
||||||
|
|
||||||
|
net_path = "/networks/%s" % n
|
||||||
path_1 = "/networks/%s/ports" % n
|
path_1 = "/networks/%s/ports" % n
|
||||||
body_1 = {'id': dummy_port,
|
body_1 = {'id': dummy_port,
|
||||||
'datapath_id': p.datapath_id,
|
'datapath_id': p.datapath_id,
|
||||||
@ -138,8 +134,11 @@ class TremaPortMACBaseDriverTest(TremaDriverNetworkTestBase,
|
|||||||
ofc_client.OFCClient.do_request("DELETE", path_3)
|
ofc_client.OFCClient.do_request("DELETE", path_3)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.create_port(t, n, p, p.id)
|
ret = self.driver.create_port(net_path, p, p.id)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
port_path = "/networks/%s/ports/%s/attachments/%s" % (n, dummy_port,
|
||||||
|
p.id)
|
||||||
|
self.assertEqual(ret, port_path)
|
||||||
|
|
||||||
def testd_delete_port(self):
|
def testd_delete_port(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
@ -149,7 +148,7 @@ class TremaPortMACBaseDriverTest(TremaDriverNetworkTestBase,
|
|||||||
ofc_client.OFCClient.do_request("DELETE", path)
|
ofc_client.OFCClient.do_request("DELETE", path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_port(t, n, p.id)
|
self.driver.delete_port(path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
@ -160,13 +159,15 @@ class TremaMACBaseDriverTest(TremaDriverNetworkTestBase, unittest.TestCase):
|
|||||||
def testd_create_port(self):
|
def testd_create_port(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
|
net_path = "/networks/%s" % n
|
||||||
path = "/networks/%s/attachments" % n
|
path = "/networks/%s/attachments" % n
|
||||||
body = {'id': p.id, 'mac': p.mac}
|
body = {'id': p.id, 'mac': p.mac}
|
||||||
ofc_client.OFCClient.do_request("POST", path, body=body)
|
ofc_client.OFCClient.do_request("POST", path, body=body)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.create_port(t, n, p, p.id)
|
ret = self.driver.create_port(net_path, p, p.id)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
self.assertEqual(ret, '/networks/%s/attachments/%s' % (n, p.id))
|
||||||
|
|
||||||
def testd_delete_port(self):
|
def testd_delete_port(self):
|
||||||
t, n, p = self.get_ofc_item_random_params()
|
t, n, p = self.get_ofc_item_random_params()
|
||||||
@ -175,7 +176,7 @@ class TremaMACBaseDriverTest(TremaDriverNetworkTestBase, unittest.TestCase):
|
|||||||
ofc_client.OFCClient.do_request("DELETE", path)
|
ofc_client.OFCClient.do_request("DELETE", path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_port(t, n, p.id)
|
self.driver.delete_port(path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
@ -208,6 +209,7 @@ class TremaFilterDriverTest(TremaDriverTestBase, unittest.TestCase):
|
|||||||
def testa_create_filter(self):
|
def testa_create_filter(self):
|
||||||
t, n, p, f = self.get_ofc_item_random_params()
|
t, n, p, f = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
|
net_path = "/networks/%s" % n
|
||||||
ofp_wildcards = 'dl_vlan,dl_vlan_pcp,nw_tos,dl_dst,' + \
|
ofp_wildcards = 'dl_vlan,dl_vlan_pcp,nw_tos,dl_dst,' + \
|
||||||
'nw_src:32,nw_dst:32,tp_src,tp_dst'
|
'nw_src:32,nw_dst:32,tp_src,tp_dst'
|
||||||
body = {'id': f.id,
|
body = {'id': f.id,
|
||||||
@ -223,14 +225,162 @@ class TremaFilterDriverTest(TremaDriverTestBase, unittest.TestCase):
|
|||||||
ofc_client.OFCClient.do_request("POST", "/filters", body=body)
|
ofc_client.OFCClient.do_request("POST", "/filters", body=body)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.create_filter(t, n, f, p, f.id)
|
ret = self.driver.create_filter(net_path, f, p, f.id)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
self.assertEqual(ret, '/filters/%s' % f.id)
|
||||||
|
|
||||||
def testb_delete_filter(self):
|
def testb_delete_filter(self):
|
||||||
t, n, p, f = self.get_ofc_item_random_params()
|
t, n, p, f = self.get_ofc_item_random_params()
|
||||||
|
|
||||||
ofc_client.OFCClient.do_request("DELETE", "/filters/%s" % f.id)
|
f_path = "/filters/%s" % f.id
|
||||||
|
ofc_client.OFCClient.do_request("DELETE", f_path)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.driver.delete_filter(t, n, f.id)
|
self.driver.delete_filter(f_path)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_ids(count=1):
|
||||||
|
if count == 1:
|
||||||
|
return uuidutils.generate_uuid()
|
||||||
|
else:
|
||||||
|
return [uuidutils.generate_uuid() for i in xrange(count)]
|
||||||
|
|
||||||
|
|
||||||
|
class TremaIdConvertTest(unittest.TestCase):
|
||||||
|
driver_name = 'trema'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.driver = drivers.get_driver(self.driver_name)(TestConfig)
|
||||||
|
self.mox = mox.Mox()
|
||||||
|
self.ctx = self.mox.CreateMock(context.Context)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.mox.UnsetStubs()
|
||||||
|
|
||||||
|
def test_convert_tenant_id(self):
|
||||||
|
ofc_t_id = generate_random_ids(1)
|
||||||
|
ret = self.driver.convert_ofc_tenant_id(self.ctx, ofc_t_id)
|
||||||
|
self.assertEqual(ret, '/tenants/%s' % ofc_t_id)
|
||||||
|
|
||||||
|
def test_convert_tenant_id_noconv(self):
|
||||||
|
ofc_t_id = '/tenants/%s' % generate_random_ids(1)
|
||||||
|
ret = self.driver.convert_ofc_tenant_id(self.ctx, ofc_t_id)
|
||||||
|
self.assertEqual(ret, ofc_t_id)
|
||||||
|
|
||||||
|
def test_convert_network_id(self):
|
||||||
|
t_id, ofc_t_id, ofc_n_id = generate_random_ids(3)
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_network_id(self.ctx, ofc_n_id, t_id)
|
||||||
|
self.assertEqual(ret, ('/networks/%s' % ofc_n_id))
|
||||||
|
|
||||||
|
def test_convert_network_id_noconv(self):
|
||||||
|
t_id = 'dummy'
|
||||||
|
ofc_t_id, ofc_n_id = generate_random_ids(2)
|
||||||
|
ofc_n_id = '/networks/%s' % ofc_n_id
|
||||||
|
ret = self.driver.convert_ofc_network_id(self.ctx, ofc_n_id, t_id)
|
||||||
|
|
||||||
|
def test_convert_filter_id(self):
|
||||||
|
ofc_f_id = generate_random_ids(1)
|
||||||
|
ret = self.driver.convert_ofc_filter_id(self.ctx, ofc_f_id)
|
||||||
|
self.assertEqual(ret, '/filters/%s' % ofc_f_id)
|
||||||
|
|
||||||
|
def test_convert_filter_id_noconv(self):
|
||||||
|
ofc_f_id = '/filters/%s' % generate_random_ids(1)
|
||||||
|
ret = self.driver.convert_ofc_filter_id(self.ctx, ofc_f_id)
|
||||||
|
self.assertEqual(ret, ofc_f_id)
|
||||||
|
|
||||||
|
|
||||||
|
class TremaIdConvertTestBase(object):
|
||||||
|
def setUp(self):
|
||||||
|
self.mox = mox.Mox()
|
||||||
|
self.driver = drivers.get_driver(self.driver_name)(TestConfig)
|
||||||
|
self.ctx = self.mox.CreateMock(context.Context)
|
||||||
|
self.ctx.session = "session"
|
||||||
|
self.mox.StubOutWithMock(ndb, 'get_ofc_id_lookup_both')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.mox.UnsetStubs()
|
||||||
|
|
||||||
|
def _test_convert_port_id(self, port_path_template):
|
||||||
|
t_id, n_id = generate_random_ids(2)
|
||||||
|
ofc_n_id, ofc_p_id = generate_random_ids(2)
|
||||||
|
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_network', n_id).AndReturn(ofc_n_id)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_port_id(self.ctx, ofc_p_id, t_id, n_id)
|
||||||
|
exp = port_path_template % {'network': ofc_n_id, 'port': ofc_p_id}
|
||||||
|
self.assertEqual(ret, exp)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def _test_convert_port_id_with_new_network_id(self, port_path_template):
|
||||||
|
t_id, n_id = generate_random_ids(2)
|
||||||
|
ofc_n_id, ofc_p_id = generate_random_ids(2)
|
||||||
|
|
||||||
|
ofc_n_path = '/networks/%s' % ofc_n_id
|
||||||
|
ndb.get_ofc_id_lookup_both(
|
||||||
|
self.ctx.session, 'ofc_network', n_id).AndReturn(ofc_n_path)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret = self.driver.convert_ofc_port_id(self.ctx, ofc_p_id, t_id, n_id)
|
||||||
|
exp = port_path_template % {'network': ofc_n_id, 'port': ofc_p_id}
|
||||||
|
print 'exp=', exp
|
||||||
|
print 'ret=', ret
|
||||||
|
self.assertEqual(ret, exp)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def _test_convert_port_id_noconv(self, port_path_template):
|
||||||
|
t_id = n_id = 'dummy'
|
||||||
|
ofc_n_id, ofc_p_id = generate_random_ids(2)
|
||||||
|
ofc_p_id = port_path_template % {'network': ofc_n_id, 'port': ofc_p_id}
|
||||||
|
ret = self.driver.convert_ofc_port_id(self.ctx, ofc_p_id, t_id, n_id)
|
||||||
|
self.assertEqual(ret, ofc_p_id)
|
||||||
|
|
||||||
|
|
||||||
|
class TremaIdConvertPortBaseTest(TremaIdConvertTestBase, unittest.TestCase):
|
||||||
|
driver_name = "trema_port"
|
||||||
|
|
||||||
|
def test_convert_port_id(self):
|
||||||
|
self._test_convert_port_id('/networks/%(network)s/ports/%(port)s')
|
||||||
|
|
||||||
|
def test_convert_port_id_with_new_network_id(self):
|
||||||
|
self._test_convert_port_id_with_new_network_id(
|
||||||
|
'/networks/%(network)s/ports/%(port)s')
|
||||||
|
|
||||||
|
def test_convert_port_id_noconv(self):
|
||||||
|
self._test_convert_port_id_noconv(
|
||||||
|
'/networs/%(network)s/ports/%(port)s')
|
||||||
|
|
||||||
|
|
||||||
|
class TremaIdConvertPortMACBaseTest(TremaIdConvertTestBase, unittest.TestCase):
|
||||||
|
driver_name = "trema_portmac"
|
||||||
|
|
||||||
|
def test_convert_port_id(self):
|
||||||
|
self._test_convert_port_id(
|
||||||
|
'/networks/%(network)s/ports/dummy-%(port)s/attachments/%(port)s')
|
||||||
|
|
||||||
|
def test_convert_port_id_with_new_network_id(self):
|
||||||
|
self._test_convert_port_id_with_new_network_id(
|
||||||
|
'/networks/%(network)s/ports/dummy-%(port)s/attachments/%(port)s')
|
||||||
|
|
||||||
|
def test_convert_port_id_noconv(self):
|
||||||
|
self._test_convert_port_id_noconv(
|
||||||
|
'/networs/%(network)s/ports/dummy-%(port)s/attachments/%(port)s')
|
||||||
|
|
||||||
|
|
||||||
|
class TremaIdConvertMACBaseTest(TremaIdConvertTestBase, unittest.TestCase):
|
||||||
|
driver_name = "trema_mac"
|
||||||
|
|
||||||
|
def test_convert_port_id(self):
|
||||||
|
self._test_convert_port_id(
|
||||||
|
'/networks/%(network)s/attachments/%(port)s')
|
||||||
|
|
||||||
|
def test_convert_port_id_with_new_network_id(self):
|
||||||
|
self._test_convert_port_id_with_new_network_id(
|
||||||
|
'/networks/%(network)s/attachments/%(port)s')
|
||||||
|
|
||||||
|
def test_convert_port_id_noconv(self):
|
||||||
|
self._test_convert_port_id_noconv(
|
||||||
|
'/networs/%(network)s/attachments/%(port)s')
|
||||||
|
Loading…
Reference in New Issue
Block a user