Reset API naming scheme for VMware NSX plugin

Introduce new naming scheme, whilst preserving
backward compatibility for the extensions affected.

Deprecated extensions will be removed from Juno.

Partial-implements blueprint: nicira-plugin-renaming

Change-Id: Icd68e5db04aa008ac31994ae0cb5c1b7f2551303
This commit is contained in:
armando-migliaccio 2014-01-23 16:23:26 -08:00
parent 898e001442
commit f58df68fa0
14 changed files with 506 additions and 445 deletions

View File

@ -68,13 +68,13 @@ from neutron.plugins.nicira.common import securitygroups as nvp_sec
from neutron.plugins.nicira.common import sync
from neutron.plugins.nicira.dbexts import distributedrouter as dist_rtr
from neutron.plugins.nicira.dbexts import maclearning as mac_db
from neutron.plugins.nicira.dbexts import networkgw_db
from neutron.plugins.nicira.dbexts import nicira_db
from neutron.plugins.nicira.dbexts import nicira_networkgw_db as networkgw_db
from neutron.plugins.nicira.dbexts import qos_db
from neutron.plugins.nicira import dhcpmeta_modes
from neutron.plugins.nicira.extensions import maclearning as mac_ext
from neutron.plugins.nicira.extensions import nvp_networkgw as networkgw
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
from neutron.plugins.nicira.extensions import networkgw
from neutron.plugins.nicira.extensions import qos
from neutron.plugins.nicira.nsxlib import l2gateway as l2gwlib
from neutron.plugins.nicira.nsxlib import queue as queuelib
from neutron.plugins.nicira.nsxlib import router as routerlib
@ -134,6 +134,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
"nvp-qos",
"port-security",
"provider",
"qos-queue",
"quotas",
"external-net",
"router",
@ -418,7 +419,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
port_data['fixed_ips'],
port_data[psec.PORTSECURITY],
port_data[ext_sg.SECURITYGROUPS],
port_data.get(ext_qos.QUEUE),
port_data.get(qos.QUEUE),
port_data.get(mac_ext.MAC_LEARNING),
port_data.get(addr_pair.ADDRESS_PAIRS))
@ -995,7 +996,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# DB Operations for setting the network as external
self._process_l3_create(context, new_net, net_data)
# Process QoS queue extension
net_queue_id = net_data.get(ext_qos.QUEUE)
net_queue_id = net_data.get(qos.QUEUE)
if net_queue_id:
# Raises if not found
self.get_qos_queue(context, net_queue_id)
@ -1112,7 +1113,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
if psec.PORTSECURITY in network['network']:
self._process_network_port_security_update(
context, network['network'], net)
net_queue_id = network['network'].get(ext_qos.QUEUE)
net_queue_id = network['network'].get(qos.QUEUE)
if net_queue_id:
self._delete_network_queue_mapping(context, id)
self._process_network_queue_mapping(context, net, net_queue_id)
@ -1294,8 +1295,8 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
if nsx_port_id:
try:
switchlib.update_port(
self.cluster,
nsx_switch_id, nsx_port_id, id, tenant_id,
self.cluster, nsx_switch_id, nsx_port_id,
id, tenant_id,
ret_port['name'],
ret_port['device_id'],
ret_port['admin_state_up'],
@ -1303,7 +1304,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
ret_port['fixed_ips'],
ret_port[psec.PORTSECURITY],
ret_port[ext_sg.SECURITYGROUPS],
ret_port[ext_qos.QUEUE],
ret_port[qos.QUEUE],
ret_port.get(mac_ext.MAC_LEARNING),
ret_port.get(addr_pair.ADDRESS_PAIRS))
@ -2225,7 +2226,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
queues = self._get_port_queue_bindings(context, filters)
if queues:
if raise_in_use:
raise ext_qos.QueueInUseByPort()
raise qos.QueueInUseByPort()
else:
return
queuelib.delete_lqueue(self.cluster, queue_id)

View File

@ -30,7 +30,7 @@ from neutron.db import model_base
from neutron.db import models_v2
from neutron.openstack.common import log as logging
from neutron.openstack.common import uuidutils
from neutron.plugins.nicira.extensions import nvp_networkgw
from neutron.plugins.nicira.extensions import networkgw
LOG = logging.getLogger(__name__)
@ -129,9 +129,9 @@ class NetworkGateway(model_base.BASEV2, models_v2.HasId,
network_connections = orm.relationship(NetworkConnection, lazy='joined')
class NetworkGatewayMixin(nvp_networkgw.NetworkGatewayPluginBase):
class NetworkGatewayMixin(networkgw.NetworkGatewayPluginBase):
resource = nvp_networkgw.RESOURCE_NAME.replace('-', '_')
resource = networkgw.RESOURCE_NAME.replace('-', '_')
def _get_network_gateway(self, context, gw_id):
try:

View File

@ -20,8 +20,8 @@ from sqlalchemy.orm import exc
import neutron.db.api as db
from neutron.openstack.common.db import exception as d_exc
from neutron.openstack.common import log as logging
from neutron.plugins.nicira.dbexts import networkgw_db
from neutron.plugins.nicira.dbexts import nicira_models
from neutron.plugins.nicira.dbexts import nicira_networkgw_db
LOG = logging.getLogger(__name__)
@ -136,13 +136,13 @@ def delete_neutron_nsx_router_mapping(session, neutron_id):
def unset_default_network_gateways(session):
with session.begin(subtransactions=True):
session.query(nicira_networkgw_db.NetworkGateway).update(
{nicira_networkgw_db.NetworkGateway.default: False})
session.query(networkgw_db.NetworkGateway).update(
{networkgw_db.NetworkGateway.default: False})
def set_default_network_gateway(session, gw_id):
with session.begin(subtransactions=True):
gw = (session.query(nicira_networkgw_db.NetworkGateway).
gw = (session.query(networkgw_db.NetworkGateway).
filter_by(id=gw_id).one())
gw['default'] = True

View File

@ -25,7 +25,7 @@ from neutron.db import model_base
from neutron.db import models_v2
from neutron.openstack.common import log
from neutron.openstack.common import uuidutils
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
from neutron.plugins.nicira.extensions import qos
LOG = log.getLogger(__name__)
@ -73,7 +73,7 @@ class NetworkQueueMapping(model_base.BASEV2):
cascade='delete', lazy='joined'))
class NVPQoSDbMixin(ext_qos.QueuePluginBase):
class NVPQoSDbMixin(qos.QueuePluginBase):
"""Mixin class to add queues."""
def create_qos_queue(self, context, qos_queue):
@ -98,7 +98,7 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
try:
return self._get_by_id(context, QoSQueue, queue_id)
except exc.NoResultFound:
raise ext_qos.QueueNotFound(id=queue_id)
raise qos.QueueNotFound(id=queue_id)
def get_qos_queues(self, context, filters=None, fields=None):
return self._get_collection(context, QoSQueue,
@ -111,7 +111,7 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
context.session.delete(qos_queue)
def _process_port_queue_mapping(self, context, port_data, queue_id):
port_data[ext_qos.QUEUE] = queue_id
port_data[qos.QUEUE] = queue_id
if not queue_id:
return
with context.session.begin(subtransactions=True):
@ -136,7 +136,7 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
context.session.delete(binding)
def _process_network_queue_mapping(self, context, net_data, queue_id):
net_data[ext_qos.QUEUE] = queue_id
net_data[qos.QUEUE] = queue_id
if not queue_id:
return
with context.session.begin(subtransactions=True):
@ -159,7 +159,7 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
def _extend_dict_qos_queue(self, obj_res, obj_db):
queue_mapping = obj_db['qos_queue']
if queue_mapping:
obj_res[ext_qos.QUEUE] = queue_mapping.get('queue_id')
obj_res[qos.QUEUE] = queue_mapping.get('queue_id')
return obj_res
def _extend_port_dict_qos_queue(self, port_res, port_db):
@ -265,8 +265,8 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
# create the queue
tenant_id = self._get_tenant_id_for_create(context, port)
if port.get(ext_qos.RXTX_FACTOR) and queue_to_create.get('max'):
queue_to_create['max'] *= int(port[ext_qos.RXTX_FACTOR])
if port.get(qos.RXTX_FACTOR) and queue_to_create.get('max'):
queue_to_create['max'] *= int(port[qos.RXTX_FACTOR])
queue = {'qos_queue': {'name': queue_to_create.get('name'),
'min': queue_to_create.get('min'),
'max': queue_to_create.get('max'),
@ -280,9 +280,9 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
if qos_queue.get('default'):
if context.is_admin:
if self.get_qos_queues(context, filters={'default': [True]}):
raise ext_qos.DefaultQueueAlreadyExists()
raise qos.DefaultQueueAlreadyExists()
else:
raise ext_qos.DefaultQueueCreateNotAdmin()
raise qos.DefaultQueueCreateNotAdmin()
if qos_queue.get('qos_marking') == 'trusted':
dscp = qos_queue.pop('dscp')
LOG.info(_("DSCP value (%s) will be ignored with 'trusted' "
@ -291,4 +291,4 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
min = qos_queue.get('min')
# Max can be None
if max and min > max:
raise ext_qos.QueueMinGreaterMax()
raise qos.QueueMinGreaterMax()

View File

@ -1,18 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Nicira, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# @author: Aaron Rosen, Nicira Networks, Inc.

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 Nicira Networks, Inc. All rights reserved.
# Copyright 2013 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -48,7 +48,7 @@ class Distributedrouter(object):
@classmethod
def get_description(cls):
return "Enables configuration of NSX Distributed routers"
return "Enables configuration of NSX Distributed routers."
@classmethod
def get_namespace(cls):

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 Nicira Networks, Inc. All rights reserved.
# Copyright 2013 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -43,7 +43,7 @@ class Maclearning(object):
@classmethod
def get_description(cls):
return "Provides mac learning capabilities"
return "Provides MAC learning capabilities."
@classmethod
def get_namespace(cls):

View File

@ -0,0 +1,189 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 VMware. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from abc import abstractmethod
from oslo.config import cfg
from neutron.api import extensions
from neutron.api.v2 import attributes
from neutron.api.v2 import base
from neutron import manager
from neutron import quota
RESOURCE_NAME = "network_gateway"
# Use dash for alias and collection name
EXT_ALIAS = RESOURCE_NAME.replace('_', '-')
COLLECTION_NAME = "%ss" % EXT_ALIAS
DEVICE_ID_ATTR = 'id'
IFACE_NAME_ATTR = 'interface_name'
# Attribute Map for Network Gateway Resource
# TODO(salvatore-orlando): add admin state as other neutron resources
RESOURCE_ATTRIBUTE_MAP = {
COLLECTION_NAME: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'default': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'devices': {'allow_post': True, 'allow_put': False,
'validate': {'type:device_list': None},
'is_visible': True},
'ports': {'allow_post': False, 'allow_put': False,
'default': [],
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True}
}
}
def _validate_device_list(data, valid_values=None):
"""Validate the list of service definitions."""
if not data:
# Devices must be provided
msg = _("Cannot create a gateway with an empty device list")
return msg
try:
for device in data:
key_specs = {DEVICE_ID_ATTR:
{'type:regex': attributes.UUID_PATTERN,
'required': True},
IFACE_NAME_ATTR:
{'type:string': None,
'required': False}}
err_msg = attributes._validate_dict(
device, key_specs=key_specs)
if err_msg:
return err_msg
unexpected_keys = [key for key in device if key not in key_specs]
if unexpected_keys:
err_msg = (_("Unexpected keys found in device description:%s")
% ",".join(unexpected_keys))
return err_msg
except TypeError:
return (_("%s: provided data are not iterable") %
_validate_device_list.__name__)
nw_gw_quota_opts = [
cfg.IntOpt('quota_network_gateway',
default=5,
help=_('Number of network gateways allowed per tenant, '
'-1 for unlimited'))
]
cfg.CONF.register_opts(nw_gw_quota_opts, 'QUOTAS')
attributes.validators['type:device_list'] = _validate_device_list
class Networkgw(object):
"""API extension for Layer-2 Gateway support.
The Layer-2 gateway feature allows for connecting neutron networks
with external networks at the layer-2 level. No assumption is made on
the location of the external network, which might not even be directly
reachable from the hosts where the VMs are deployed.
This is achieved by instantiating 'network gateways', and then connecting
Neutron network to them.
"""
@classmethod
def get_name(cls):
return "Network Gateway"
@classmethod
def get_alias(cls):
return EXT_ALIAS
@classmethod
def get_description(cls):
return "Connects Neutron networks with external networks at layer 2."
@classmethod
def get_namespace(cls):
return "http://docs.openstack.org/ext/network-gateway/api/v1.0"
@classmethod
def get_updated(cls):
return "2014-01-01T00:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
plugin = manager.NeutronManager.get_plugin()
params = RESOURCE_ATTRIBUTE_MAP.get(COLLECTION_NAME, dict())
member_actions = {'connect_network': 'PUT',
'disconnect_network': 'PUT'}
# register quotas for network gateways
quota.QUOTAS.register_resource_by_name(RESOURCE_NAME)
collection_name = COLLECTION_NAME.replace('_', '-')
controller = base.create_resource(collection_name,
RESOURCE_NAME,
plugin, params,
member_actions=member_actions)
return [extensions.ResourceExtension(COLLECTION_NAME,
controller,
member_actions=member_actions)]
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class NetworkGatewayPluginBase(object):
@abstractmethod
def create_network_gateway(self, context, network_gateway):
pass
@abstractmethod
def update_network_gateway(self, context, id, network_gateway):
pass
@abstractmethod
def get_network_gateway(self, context, id, fields=None):
pass
@abstractmethod
def delete_network_gateway(self, context, id):
pass
@abstractmethod
def get_network_gateways(self, context, filters=None, fields=None):
pass
@abstractmethod
def connect_network(self, context, network_gateway_id,
network_mapping_info):
pass
@abstractmethod
def disconnect_network(self, context, network_gateway_id,
network_mapping_info):
pass

View File

@ -1,6 +1,7 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 VMware. All rights reserved.
# Copyright 2013 VMware, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -14,101 +15,14 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# @author: Salvatore Orlando, VMware
# TODO(armando-migliaccio): This is deprecated in Icehouse, and
# to be removed in Juno.
from abc import abstractmethod
from oslo.config import cfg
from neutron.api import extensions
from neutron.api.v2 import attributes
from neutron.api.v2 import base
from neutron import manager
from neutron import quota
from neutron.plugins.nicira.extensions import networkgw
RESOURCE_NAME = "network_gateway"
# Use dash for alias and collection name
EXT_ALIAS = RESOURCE_NAME.replace('_', '-')
COLLECTION_NAME = "%ss" % EXT_ALIAS
DEVICE_ID_ATTR = 'id'
IFACE_NAME_ATTR = 'interface_name'
# Attribute Map for Network Gateway Resource
# TODO(salvatore-orlando): add admin state as other neutron resources
RESOURCE_ATTRIBUTE_MAP = {
COLLECTION_NAME: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'default': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'devices': {'allow_post': True, 'allow_put': False,
'validate': {'type:device_list': None},
'is_visible': True},
'ports': {'allow_post': False, 'allow_put': False,
'default': [],
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True}
}
}
def _validate_device_list(data, valid_values=None):
"""Validate the list of service definitions."""
if not data:
# Devices must be provided
msg = _("Cannot create a gateway with an empty device list")
return msg
try:
for device in data:
key_specs = {DEVICE_ID_ATTR:
{'type:regex': attributes.UUID_PATTERN,
'required': True},
IFACE_NAME_ATTR:
{'type:string': None,
'required': False}}
err_msg = attributes._validate_dict(
device, key_specs=key_specs)
if err_msg:
return err_msg
unexpected_keys = [key for key in device if key not in key_specs]
if unexpected_keys:
err_msg = (_("Unexpected keys found in device description:%s")
% ",".join(unexpected_keys))
return err_msg
except TypeError:
return (_("%s: provided data are not iterable") %
_validate_device_list.__name__)
nw_gw_quota_opts = [
cfg.IntOpt('quota_network_gateway',
default=5,
help=_('Number of network gateways allowed per tenant, '
'-1 for unlimited'))
]
cfg.CONF.register_opts(nw_gw_quota_opts, 'QUOTAS')
attributes.validators['type:device_list'] = _validate_device_list
class Nvp_networkgw(object):
"""API extension for Layer-2 Gateway support.
The Layer-2 gateway feature allows for connecting neutron networks
with external networks at the layer-2 level. No assumption is made on
the location of the external network, which might not even be directly
reachable from the hosts where the VMs are deployed.
This is achieved by instantiating 'network gateways', and then connecting
Neutron network to them.
"""
class Nvp_networkgw(networkgw.Networkgw):
"""(Deprecated) API extension for Layer-2 Gateway support."""
@classmethod
def get_name(cls):
@ -116,75 +30,13 @@ class Nvp_networkgw(object):
@classmethod
def get_alias(cls):
return EXT_ALIAS
return "network-gateway"
@classmethod
def get_description(cls):
return "Connects Neutron networks with external networks at layer 2"
return ("Connects Neutron networks with external "
"networks at layer 2 (deprecated).")
@classmethod
def get_namespace(cls):
return "http://docs.openstack.org/ext/neutron/network-gateway/api/v1.0"
@classmethod
def get_updated(cls):
return "2012-11-30T10:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
plugin = manager.NeutronManager.get_plugin()
params = RESOURCE_ATTRIBUTE_MAP.get(COLLECTION_NAME, dict())
member_actions = {'connect_network': 'PUT',
'disconnect_network': 'PUT'}
# register quotas for network gateways
quota.QUOTAS.register_resource_by_name(RESOURCE_NAME)
collection_name = COLLECTION_NAME.replace('_', '-')
controller = base.create_resource(collection_name,
RESOURCE_NAME,
plugin, params,
member_actions=member_actions)
return [extensions.ResourceExtension(COLLECTION_NAME,
controller,
member_actions=member_actions)]
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class NetworkGatewayPluginBase(object):
@abstractmethod
def create_network_gateway(self, context, network_gateway):
pass
@abstractmethod
def update_network_gateway(self, context, id, network_gateway):
pass
@abstractmethod
def get_network_gateway(self, context, id, fields=None):
pass
@abstractmethod
def delete_network_gateway(self, context, id):
pass
@abstractmethod
def get_network_gateways(self, context, filters=None, fields=None):
pass
@abstractmethod
def connect_network(self, context, network_gateway_id,
network_mapping_info):
pass
@abstractmethod
def disconnect_network(self, context, network_gateway_id,
network_mapping_info):
pass

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Nicira, Inc.
# Copyright 2013 VMware, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -15,150 +15,14 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# @author: Aaron Rosen, Nicira Networks, Inc.
# TODO(armando-migliaccio): This is deprecated in Icehouse, and
# to be removed in Juno.
from neutron.plugins.nicira.extensions import qos
from abc import abstractmethod
from neutron.api import extensions
from neutron.api.v2 import attributes as attr
from neutron.api.v2 import base
from neutron.common import exceptions as qexception
from neutron import manager
# For policy.json/Auth
qos_queue_create = "create_qos_queue"
qos_queue_delete = "delete_qos_queue"
qos_queue_get = "get_qos_queue"
qos_queue_list = "get_qos_queues"
class DefaultQueueCreateNotAdmin(qexception.InUse):
message = _("Need to be admin in order to create queue called default")
class DefaultQueueAlreadyExists(qexception.InUse):
message = _("Default queue already exists.")
class QueueInvalidDscp(qexception.InvalidInput):
message = _("Invalid value for dscp %(data)s must be integer value"
" between 0 and 63.")
class QueueMinGreaterMax(qexception.InvalidInput):
message = _("Invalid bandwidth rate, min greater than max.")
class QueueInvalidBandwidth(qexception.InvalidInput):
message = _("Invalid bandwidth rate, %(data)s must be a non negative"
" integer.")
class QueueNotFound(qexception.NotFound):
message = _("Queue %(id)s does not exist")
class QueueInUseByPort(qexception.InUse):
message = _("Unable to delete queue attached to port.")
class QueuePortBindingNotFound(qexception.NotFound):
message = _("Port is not associated with lqueue")
def convert_to_unsigned_int_or_none(val):
if val is None:
return
try:
val = int(val)
if val < 0:
raise ValueError
except (ValueError, TypeError):
msg = _("'%s' must be a non negative integer.") % val
raise qexception.InvalidInput(error_message=msg)
return val
def convert_to_unsigned_int_or_none_max_63(val):
val = convert_to_unsigned_int_or_none(val)
if val > 63:
raise QueueInvalidDscp(data=val)
return val
# As per NVP API, if a queue is trusted, DSCP must be omitted; if a queue is
# untrusted, DSCP must be specified. Whichever default values we choose for
# the tuple (qos_marking, dscp), there will be at least one combination of a
# request with conflicting values: for instance, with the following default:
#
# qos_marking = 'untrusted', dscp = '0'
#
# requests with qos_marking = 'trusted' and a default dscp will fail. Since
# it is convoluted to ask the admin to specify a None value for dscp when
# qos_marking is 'trusted', it is best to ignore the dscp value, regardless
# of whether it has been specified or not. This preserves the chosen default
# and keeps backward compatibility with the API. A warning will be logged, as
# the server is overriding a potentially conflicting request from the admin
RESOURCE_ATTRIBUTE_MAP = {
'qos_queues': {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'default': {'allow_post': True, 'allow_put': False,
'convert_to': attr.convert_to_boolean,
'is_visible': True, 'default': False},
'name': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'min': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none},
'max': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': None,
'convert_to': convert_to_unsigned_int_or_none},
'qos_marking': {'allow_post': True, 'allow_put': False,
'validate': {'type:values': ['untrusted', 'trusted']},
'default': 'untrusted', 'is_visible': True},
'dscp': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none_max_63},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'validate': {'type:string': None},
'is_visible': True},
},
}
QUEUE = 'queue_id'
RXTX_FACTOR = 'rxtx_factor'
EXTENDED_ATTRIBUTES_2_0 = {
'ports': {
RXTX_FACTOR: {'allow_post': True,
# FIXME(arosen): the nvp plugin currently does not
# implement updating rxtx factor on port.
'allow_put': True,
'is_visible': False,
'default': 1,
'enforce_policy': True,
'convert_to': convert_to_unsigned_int_or_none},
QUEUE: {'allow_post': False,
'allow_put': False,
'is_visible': True,
'default': False,
'enforce_policy': True}},
'networks': {QUEUE: {'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': False,
'enforce_policy': True}}
}
class Nvp_qos(object):
"""Port Queue extension."""
class Nvp_qos(qos.Qos):
"""(Deprecated) Port Queue extension."""
@classmethod
def get_name(cls):
@ -170,55 +34,8 @@ class Nvp_qos(object):
@classmethod
def get_description(cls):
return "NVP QoS extension."
return "NVP QoS extension (deprecated)."
@classmethod
def get_namespace(cls):
return "http://docs.openstack.org/ext/nvp-qos/api/v2.0"
@classmethod
def get_updated(cls):
return "2012-10-05T10:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
exts = []
plugin = manager.NeutronManager.get_plugin()
resource_name = 'qos_queue'
collection_name = resource_name.replace('_', '-') + "s"
params = RESOURCE_ATTRIBUTE_MAP.get(resource_name + "s", dict())
controller = base.create_resource(collection_name,
resource_name,
plugin, params, allow_bulk=False)
ex = extensions.ResourceExtension(collection_name,
controller)
exts.append(ex)
return exts
def get_extended_resources(self, version):
if version == "2.0":
return dict(EXTENDED_ATTRIBUTES_2_0.items() +
RESOURCE_ATTRIBUTE_MAP.items())
else:
return {}
class QueuePluginBase(object):
@abstractmethod
def create_qos_queue(self, context, queue):
pass
@abstractmethod
def delete_qos_queue(self, context, id):
pass
@abstractmethod
def get_qos_queue(self, context, id, fields=None):
pass
@abstractmethod
def get_qos_queues(self, context, filters=None, fields=None):
pass

View File

@ -0,0 +1,222 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 VMware, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from abc import abstractmethod
from neutron.api import extensions
from neutron.api.v2 import attributes as attr
from neutron.api.v2 import base
from neutron.common import exceptions as qexception
from neutron import manager
# For policy.json/Auth
qos_queue_create = "create_qos_queue"
qos_queue_delete = "delete_qos_queue"
qos_queue_get = "get_qos_queue"
qos_queue_list = "get_qos_queues"
class DefaultQueueCreateNotAdmin(qexception.InUse):
message = _("Need to be admin in order to create queue called default")
class DefaultQueueAlreadyExists(qexception.InUse):
message = _("Default queue already exists.")
class QueueInvalidDscp(qexception.InvalidInput):
message = _("Invalid value for dscp %(data)s must be integer value"
" between 0 and 63.")
class QueueMinGreaterMax(qexception.InvalidInput):
message = _("Invalid bandwidth rate, min greater than max.")
class QueueInvalidBandwidth(qexception.InvalidInput):
message = _("Invalid bandwidth rate, %(data)s must be a non negative"
" integer.")
class QueueNotFound(qexception.NotFound):
message = _("Queue %(id)s does not exist")
class QueueInUseByPort(qexception.InUse):
message = _("Unable to delete queue attached to port.")
class QueuePortBindingNotFound(qexception.NotFound):
message = _("Port is not associated with lqueue")
def convert_to_unsigned_int_or_none(val):
if val is None:
return
try:
val = int(val)
if val < 0:
raise ValueError
except (ValueError, TypeError):
msg = _("'%s' must be a non negative integer.") % val
raise qexception.InvalidInput(error_message=msg)
return val
def convert_to_unsigned_int_or_none_max_63(val):
val = convert_to_unsigned_int_or_none(val)
if val > 63:
raise QueueInvalidDscp(data=val)
return val
# As per NSX API, if a queue is trusted, DSCP must be omitted; if a queue is
# untrusted, DSCP must be specified. Whichever default values we choose for
# the tuple (qos_marking, dscp), there will be at least one combination of a
# request with conflicting values: for instance, with the following default:
#
# qos_marking = 'untrusted', dscp = '0'
#
# requests with qos_marking = 'trusted' and a default dscp will fail. Since
# it is convoluted to ask the admin to specify a None value for dscp when
# qos_marking is 'trusted', it is best to ignore the dscp value, regardless
# of whether it has been specified or not. This preserves the chosen default
# and keeps backward compatibility with the API. A warning will be logged, as
# the server is overriding a potentially conflicting request from the admin
RESOURCE_ATTRIBUTE_MAP = {
'qos_queues': {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'default': {'allow_post': True, 'allow_put': False,
'convert_to': attr.convert_to_boolean,
'is_visible': True, 'default': False},
'name': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'min': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none},
'max': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': None,
'convert_to': convert_to_unsigned_int_or_none},
'qos_marking': {'allow_post': True, 'allow_put': False,
'validate': {'type:values': ['untrusted', 'trusted']},
'default': 'untrusted', 'is_visible': True},
'dscp': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none_max_63},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'validate': {'type:string': None},
'is_visible': True},
},
}
QUEUE = 'queue_id'
RXTX_FACTOR = 'rxtx_factor'
EXTENDED_ATTRIBUTES_2_0 = {
'ports': {
RXTX_FACTOR: {'allow_post': True,
# FIXME(arosen): the plugin currently does not
# implement updating rxtx factor on port.
'allow_put': True,
'is_visible': False,
'default': 1,
'enforce_policy': True,
'convert_to': convert_to_unsigned_int_or_none},
QUEUE: {'allow_post': False,
'allow_put': False,
'is_visible': True,
'default': False,
'enforce_policy': True}},
'networks': {QUEUE: {'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': False,
'enforce_policy': True}}
}
class Qos(object):
"""Port Queue extension."""
@classmethod
def get_name(cls):
return "QoS Queue"
@classmethod
def get_alias(cls):
return "qos-queue"
@classmethod
def get_description(cls):
return "NSX QoS extension."
@classmethod
def get_namespace(cls):
return "http://docs.openstack.org/ext/qos-queue/api/v2.0"
@classmethod
def get_updated(cls):
return "2014-01-01T00:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
exts = []
plugin = manager.NeutronManager.get_plugin()
resource_name = 'qos_queue'
collection_name = resource_name.replace('_', '-') + "s"
params = RESOURCE_ATTRIBUTE_MAP.get(resource_name + "s", dict())
controller = base.create_resource(collection_name,
resource_name,
plugin, params, allow_bulk=False)
ex = extensions.ResourceExtension(collection_name,
controller)
exts.append(ex)
return exts
def get_extended_resources(self, version):
if version == "2.0":
return dict(EXTENDED_ATTRIBUTES_2_0.items() +
RESOURCE_ATTRIBUTE_MAP.items())
else:
return {}
class QueuePluginBase(object):
@abstractmethod
def create_qos_queue(self, context, queue):
pass
@abstractmethod
def delete_qos_queue(self, context, id):
pass
@abstractmethod
def get_qos_queue(self, context, id, fields=None):
pass
@abstractmethod
def get_qos_queues(self, context, filters=None, fields=None):
pass

View File

@ -14,8 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# @author: Kaiwei Fan, VMware, Inc
from neutron.api import extensions
from neutron.api.v2 import attributes
@ -44,11 +42,11 @@ class Servicerouter(extensions.ExtensionDescriptor):
@classmethod
def get_description(cls):
return "Provides service router"
return "Provides service router."
@classmethod
def get_namespace(cls):
return ""
return "http://docs.openstack.org/ext/service-router/api/v1.0"
@classmethod
def get_updated(cls):

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Nicira Networks, Inc. All rights reserved.
# Copyright 2012 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -29,8 +29,8 @@ from neutron import context
from neutron.db import api as db_api
from neutron.db import db_base_plugin_v2
from neutron import manager
from neutron.plugins.nicira.dbexts import nicira_networkgw_db
from neutron.plugins.nicira.extensions import nvp_networkgw as networkgw
from neutron.plugins.nicira.dbexts import networkgw_db
from neutron.plugins.nicira.extensions import networkgw
from neutron.plugins.nicira.NeutronPlugin import NVP_EXT_PATH
from neutron import quota
from neutron.tests import base
@ -52,7 +52,7 @@ class TestExtensionManager(object):
# the global attribute map
attributes.RESOURCE_ATTRIBUTE_MAP.update(
networkgw.RESOURCE_ATTRIBUTE_MAP)
return networkgw.Nvp_networkgw.get_resources()
return networkgw.Networkgw.get_resources()
def get_actions(self):
return []
@ -357,8 +357,8 @@ class NetworkGatewayDbTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
pass
# Verify nothing left on db
session = db_api.get_session()
gw_query = session.query(nicira_networkgw_db.NetworkGateway)
dev_query = session.query(nicira_networkgw_db.NetworkGatewayDevice)
gw_query = session.query(networkgw_db.NetworkGateway)
dev_query = session.query(networkgw_db.NetworkGatewayDevice)
self.assertEqual(exp_gw_count, gw_query.count())
self.assertEqual(0, dev_query.count())
@ -595,7 +595,7 @@ class NetworkGatewayDbTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
class TestNetworkGatewayPlugin(db_base_plugin_v2.NeutronDbPluginV2,
nicira_networkgw_db.NetworkGatewayMixin):
networkgw_db.NetworkGatewayMixin):
"""Simple plugin class for testing db support for network gateway ext."""
supported_extension_aliases = ["network-gateway"]

View File

@ -44,8 +44,8 @@ from neutron.plugins.nicira.common import sync
from neutron.plugins.nicira.dbexts import nicira_db
from neutron.plugins.nicira.dbexts import qos_db
from neutron.plugins.nicira.extensions import distributedrouter as dist_router
from neutron.plugins.nicira.extensions import nvp_networkgw
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
from neutron.plugins.nicira.extensions import networkgw
from neutron.plugins.nicira.extensions import qos
from neutron.plugins.nicira import NeutronPlugin
from neutron.plugins.nicira import nsxlib
from neutron.plugins.nicira import NvpApiClient
@ -1036,7 +1036,7 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
class NvpQoSTestExtensionManager(object):
def get_resources(self):
return ext_qos.Nvp_qos.get_resources()
return qos.Qos.get_resources()
def get_actions(self):
return []
@ -1127,28 +1127,28 @@ class TestQoSQueue(NiciraPluginV2TestCase):
def test_create_port_with_queue(self):
with self.qos_queue(default=True) as q1:
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
queue_id=q1['qos_queue']['id'])
net1 = self.deserialize('json', res)
self.assertEqual(net1['network'][ext_qos.QUEUE],
self.assertEqual(net1['network'][qos.QUEUE],
q1['qos_queue']['id'])
device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
with self.port(device_id=device_id, do_delete=False) as p:
self.assertEqual(len(p['port'][ext_qos.QUEUE]), 36)
self.assertEqual(len(p['port'][qos.QUEUE]), 36)
def test_create_shared_queue_networks(self):
with self.qos_queue(default=True, no_delete=True) as q1:
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
queue_id=q1['qos_queue']['id'])
net1 = self.deserialize('json', res)
self.assertEqual(net1['network'][ext_qos.QUEUE],
self.assertEqual(net1['network'][qos.QUEUE],
q1['qos_queue']['id'])
res = self._create_network('json', 'net2', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
queue_id=q1['qos_queue']['id'])
net2 = self.deserialize('json', res)
self.assertEqual(net1['network'][ext_qos.QUEUE],
self.assertEqual(net1['network'][qos.QUEUE],
q1['qos_queue']['id'])
device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
res = self._create_port('json', net1['network']['id'],
@ -1157,8 +1157,8 @@ class TestQoSQueue(NiciraPluginV2TestCase):
res = self._create_port('json', net2['network']['id'],
device_id=device_id)
port2 = self.deserialize('json', res)
self.assertEqual(port1['port'][ext_qos.QUEUE],
port2['port'][ext_qos.QUEUE])
self.assertEqual(port1['port'][qos.QUEUE],
port2['port'][qos.QUEUE])
self._delete('ports', port1['port']['id'])
self._delete('ports', port2['port']['id'])
@ -1166,40 +1166,40 @@ class TestQoSQueue(NiciraPluginV2TestCase):
def test_remove_queue_in_use_fail(self):
with self.qos_queue(no_delete=True) as q1:
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
queue_id=q1['qos_queue']['id'])
net1 = self.deserialize('json', res)
device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
res = self._create_port('json', net1['network']['id'],
device_id=device_id)
port = self.deserialize('json', res)
self._delete('qos-queues', port['port'][ext_qos.QUEUE], 409)
self._delete('qos-queues', port['port'][qos.QUEUE], 409)
def test_update_network_new_queue(self):
with self.qos_queue() as q1:
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
queue_id=q1['qos_queue']['id'])
net1 = self.deserialize('json', res)
with self.qos_queue() as new_q:
data = {'network': {ext_qos.QUEUE: new_q['qos_queue']['id']}}
data = {'network': {qos.QUEUE: new_q['qos_queue']['id']}}
req = self.new_update_request('networks', data,
net1['network']['id'])
res = req.get_response(self.api)
net1 = self.deserialize('json', res)
self.assertEqual(net1['network'][ext_qos.QUEUE],
self.assertEqual(net1['network'][qos.QUEUE],
new_q['qos_queue']['id'])
def test_update_port_adding_device_id(self):
with self.qos_queue(no_delete=True) as q1:
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
queue_id=q1['qos_queue']['id'])
net1 = self.deserialize('json', res)
device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
res = self._create_port('json', net1['network']['id'])
port = self.deserialize('json', res)
self.assertIsNone(port['port'][ext_qos.QUEUE])
self.assertIsNone(port['port'][qos.QUEUE])
data = {'port': {'device_id': device_id}}
req = self.new_update_request('ports', data,
@ -1207,7 +1207,7 @@ class TestQoSQueue(NiciraPluginV2TestCase):
res = req.get_response(self.api)
port = self.deserialize('json', res)
self.assertEqual(len(port['port'][ext_qos.QUEUE]), 36)
self.assertEqual(len(port['port'][qos.QUEUE]), 36)
def test_get_port_with_qos_not_admin(self):
body = {'qos_queue': {'tenant_id': 'not_admin',
@ -1215,16 +1215,16 @@ class TestQoSQueue(NiciraPluginV2TestCase):
res = self._create_qos_queue('json', body, tenant_id='not_admin')
q1 = self.deserialize('json', res)
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE, 'tenant_id',),
arg_list=(qos.QUEUE, 'tenant_id',),
queue_id=q1['qos_queue']['id'],
tenant_id="not_admin")
net1 = self.deserialize('json', res)
self.assertEqual(len(net1['network'][ext_qos.QUEUE]), 36)
self.assertEqual(len(net1['network'][qos.QUEUE]), 36)
res = self._create_port('json', net1['network']['id'],
tenant_id='not_admin', set_context=True)
port = self.deserialize('json', res)
self.assertNotIn(ext_qos.QUEUE, port['port'])
self.assertNotIn(qos.QUEUE, port['port'])
def test_dscp_value_out_of_range(self):
body = {'qos_queue': {'tenant_id': 'admin', 'dscp': '64',
@ -1245,7 +1245,7 @@ class TestQoSQueue(NiciraPluginV2TestCase):
res = self._create_qos_queue('json', body, tenant_id='not_admin')
q1 = self.deserialize('json', res)
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
tenant_id='not_admin',
queue_id=q1['qos_queue']['id'])
@ -1258,21 +1258,21 @@ class TestQoSQueue(NiciraPluginV2TestCase):
neutron_context = context.Context('', 'not_admin')
port = self._update('ports', port['port']['id'], data,
neutron_context=neutron_context)
self.assertNotIn(ext_qos.QUEUE, port['port'])
self.assertNotIn(qos.QUEUE, port['port'])
def test_rxtx_factor(self):
with self.qos_queue(max=10) as q1:
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
arg_list=(qos.QUEUE,),
queue_id=q1['qos_queue']['id'])
net1 = self.deserialize('json', res)
res = self._create_port('json', net1['network']['id'],
arg_list=(ext_qos.RXTX_FACTOR,),
arg_list=(qos.RXTX_FACTOR,),
rxtx_factor=2, device_id='1')
port = self.deserialize('json', res)
req = self.new_show_request('qos-queues',
port['port'][ext_qos.QUEUE])
port['port'][qos.QUEUE])
res = req.get_response(self.ext_api)
queue = self.deserialize('json', res)
self.assertEqual(queue['qos_queue']['max'], 20)
@ -1475,7 +1475,7 @@ class TestNiciraNetworkGateway(NiciraPluginV2TestCase,
nsxlib.l2gateway, 'update_l2_gw_service') as mock_update_gw:
with self._network_gateway(name='cavani') as nw_gw:
nw_gw_id = nw_gw[self.resource]['id']
self._update(nvp_networkgw.COLLECTION_NAME, nw_gw_id,
self._update(networkgw.COLLECTION_NAME, nw_gw_id,
{self.resource: {'name': 'higuain'}})
mock_update_gw.assert_called_once_with(
mock.ANY, nw_gw_id, 'higuain')
@ -1485,7 +1485,7 @@ class TestNiciraNetworkGateway(NiciraPluginV2TestCase,
nsxlib.l2gateway, 'update_l2_gw_service') as mock_update_gw:
with self._network_gateway(name='something') as nw_gw:
nw_gw_id = nw_gw[self.resource]['id']
self._update(nvp_networkgw.COLLECTION_NAME, nw_gw_id,
self._update(networkgw.COLLECTION_NAME, nw_gw_id,
{self.resource: {}})
self.assertEqual(mock_update_gw.call_count, 0)
@ -1493,9 +1493,9 @@ class TestNiciraNetworkGateway(NiciraPluginV2TestCase,
new_name = 'this_is_a_gateway_whose_name_is_longer_than_40_chars'
with self._network_gateway(name='something') as nw_gw:
nw_gw_id = nw_gw[self.resource]['id']
self._update(nvp_networkgw.COLLECTION_NAME, nw_gw_id,
self._update(networkgw.COLLECTION_NAME, nw_gw_id,
{self.resource: {'name': new_name}})
req = self.new_show_request(nvp_networkgw.COLLECTION_NAME,
req = self.new_show_request(networkgw.COLLECTION_NAME,
nw_gw_id)
res = self.deserialize('json', req.get_response(self.ext_api))
# Assert Neutron name is not truncated
@ -1529,7 +1529,7 @@ class TestNiciraNetworkGateway(NiciraPluginV2TestCase,
def test_list_network_gateways(self):
with self._network_gateway(name='test-gw-1') as gw1:
with self._network_gateway(name='test_gw_2') as gw2:
req = self.new_list_request(nvp_networkgw.COLLECTION_NAME)
req = self.new_list_request(networkgw.COLLECTION_NAME)
res = self.deserialize('json', req.get_response(self.ext_api))
# We expect the default gateway too
key = self.resource + 's'
@ -1551,7 +1551,7 @@ class TestNiciraNetworkGateway(NiciraPluginV2TestCase,
def test_show_network_gateway_nvp_error_returns_404(self):
invalid_id = 'b5afd4a9-eb71-4af7-a082-8fc625a35b61'
req = self.new_show_request(nvp_networkgw.COLLECTION_NAME, invalid_id)
req = self.new_show_request(networkgw.COLLECTION_NAME, invalid_id)
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)