Merge "One Convergence Neutron Plugin Implementation"
This commit is contained in:
commit
005fec677c
23
etc/neutron/plugins/oneconvergence/nvsdplugin.ini
Normal file
23
etc/neutron/plugins/oneconvergence/nvsdplugin.ini
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[nvsd]
|
||||||
|
# Configure the NVSD controller. The plugin proxies the api calls using
|
||||||
|
# to NVSD controller which implements the required functionality.
|
||||||
|
|
||||||
|
# IP address of NVSD controller api server
|
||||||
|
# nvsd_ip = <ip address of nvsd controller>
|
||||||
|
|
||||||
|
# Port number of NVSD controller api server
|
||||||
|
# nvsd_port = 8082
|
||||||
|
|
||||||
|
# Authentication credentials to access the api server
|
||||||
|
# nvsd_user = <nvsd controller username>
|
||||||
|
# nvsd_passwd = <password>
|
||||||
|
|
||||||
|
# API request timeout in seconds
|
||||||
|
# request_timeout = <default request timeout>
|
||||||
|
|
||||||
|
# Maximum number of retry attempts to login to the NVSD controller
|
||||||
|
# Specify 0 to retry until success (default)
|
||||||
|
# nvsd_retries = 0
|
||||||
|
|
||||||
|
[database]
|
||||||
|
# connection = mysql://root:<passwd>@127.0.0.1/<neutron_db>?charset=utf8
|
@ -42,7 +42,8 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.vmware.plugin.NsxPlugin',
|
'neutron.plugins.vmware.plugin.NsxPlugin',
|
||||||
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
||||||
'neutron.plugins.embrane.plugins.embrane_ovs_plugin.EmbraneOvsPlugin',
|
'neutron.plugins.embrane.plugins.embrane_ovs_plugin.EmbraneOvsPlugin',
|
||||||
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2'
|
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
]
|
]
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -38,6 +38,7 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.vmware.plugin.NsxPlugin',
|
'neutron.plugins.vmware.plugin.NsxPlugin',
|
||||||
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
||||||
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
|
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
]
|
]
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -38,7 +38,8 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin',
|
'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin',
|
||||||
'neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2',
|
'neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2',
|
||||||
'neutron.plugins.vmware.plugin.NsxPlugin',
|
'neutron.plugins.vmware.plugin.NsxPlugin',
|
||||||
'neutron.plugins.vmware.plugin.NsxServicePlugin'
|
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
]
|
]
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -38,6 +38,7 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
||||||
'neutron.services.loadbalancer.plugin.LoadBalancerPlugin',
|
'neutron.services.loadbalancer.plugin.LoadBalancerPlugin',
|
||||||
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
|
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
]
|
]
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -44,6 +44,7 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.nec.nec_plugin.NECPluginV2',
|
'neutron.plugins.nec.nec_plugin.NECPluginV2',
|
||||||
'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2',
|
'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2',
|
||||||
'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin',
|
'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2',
|
'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2',
|
||||||
'neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.'
|
'neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.'
|
||||||
'NeutronPluginPLUMgridV2',
|
'NeutronPluginPLUMgridV2',
|
||||||
|
@ -38,6 +38,7 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2',
|
'neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2',
|
||||||
'neutron.plugins.vmware.plugin.NsxPlugin',
|
'neutron.plugins.vmware.plugin.NsxPlugin',
|
||||||
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
]
|
]
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -38,6 +38,7 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.nec.nec_plugin.NECPluginV2',
|
'neutron.plugins.nec.nec_plugin.NECPluginV2',
|
||||||
'neutron.plugins.vmware.plugin.NsxPlugin',
|
'neutron.plugins.vmware.plugin.NsxPlugin',
|
||||||
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
]
|
]
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -40,6 +40,7 @@ migration_for_plugins = [
|
|||||||
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
'neutron.plugins.vmware.plugin.NsxServicePlugin',
|
||||||
'neutron.services.loadbalancer.plugin.LoadBalancerPlugin',
|
'neutron.services.loadbalancer.plugin.LoadBalancerPlugin',
|
||||||
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
|
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
|
||||||
|
'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
]
|
]
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -33,6 +33,7 @@ PLUGINS = {
|
|||||||
'ml2': 'neutron.plugins.ml2.plugin.Ml2Plugin',
|
'ml2': 'neutron.plugins.ml2.plugin.Ml2Plugin',
|
||||||
'nec': 'neutron.plugins.nec.nec_plugin.NECPluginV2',
|
'nec': 'neutron.plugins.nec.nec_plugin.NECPluginV2',
|
||||||
'nvp': 'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2',
|
'nvp': 'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2',
|
||||||
|
'ocnvsd': 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
|
||||||
'ovs': 'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2',
|
'ovs': 'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2',
|
||||||
'plumgrid': 'neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.'
|
'plumgrid': 'neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.'
|
||||||
'NeutronPluginPLUMgridV2',
|
'NeutronPluginPLUMgridV2',
|
||||||
@ -45,6 +46,7 @@ L3_CAPABLE = [
|
|||||||
PLUGINS['meta'],
|
PLUGINS['meta'],
|
||||||
PLUGINS['ml2'],
|
PLUGINS['ml2'],
|
||||||
PLUGINS['nec'],
|
PLUGINS['nec'],
|
||||||
|
PLUGINS['ocnvsd'],
|
||||||
PLUGINS['ovs'],
|
PLUGINS['ovs'],
|
||||||
PLUGINS['ryu'],
|
PLUGINS['ryu'],
|
||||||
PLUGINS['brocade'],
|
PLUGINS['brocade'],
|
||||||
@ -56,6 +58,7 @@ FOLSOM_QUOTA = [
|
|||||||
PLUGINS['lbr'],
|
PLUGINS['lbr'],
|
||||||
PLUGINS['ml2'],
|
PLUGINS['ml2'],
|
||||||
PLUGINS['nvp'],
|
PLUGINS['nvp'],
|
||||||
|
PLUGINS['ocnvsd'],
|
||||||
PLUGINS['ovs'],
|
PLUGINS['ovs'],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
32
neutron/plugins/oneconvergence/README
Normal file
32
neutron/plugins/oneconvergence/README
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
One Convergence Neutron Plugin to implement the Neutron v2.0 API. The plugin
|
||||||
|
works with One Convergence NVSD controller to provide network virtualization
|
||||||
|
functionality.
|
||||||
|
|
||||||
|
The plugin is enabled with the following configuration line in neutron.conf:
|
||||||
|
|
||||||
|
core_plugin = neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2
|
||||||
|
|
||||||
|
The configuration parameters required for the plugin are specified in the file
|
||||||
|
etc/neutron/plugins/oneconvergence/nvsdplugin.ini. The configuration file contains
|
||||||
|
description of the different parameters.
|
||||||
|
|
||||||
|
To enable One Convergence Neutron Plugin with devstack and configure the required
|
||||||
|
parameters, use the following lines in localrc:
|
||||||
|
|
||||||
|
Q_PLUGIN=oneconvergence
|
||||||
|
|
||||||
|
disable_service n-net
|
||||||
|
disable_service q-agt
|
||||||
|
enable_service q-dhcp
|
||||||
|
enable_service q-svc
|
||||||
|
enable_service q-l3
|
||||||
|
enable_service q-meta
|
||||||
|
enable_service neutron
|
||||||
|
|
||||||
|
NVSD_IP=
|
||||||
|
NVSD_PORT=
|
||||||
|
NVSD_USER=
|
||||||
|
NVSD_PASSWD=
|
||||||
|
|
||||||
|
The NVSD controller configuration should be specified in nvsdplugin.ini before
|
||||||
|
invoking stack.sh.
|
0
neutron/plugins/oneconvergence/__init__.py
Normal file
0
neutron/plugins/oneconvergence/__init__.py
Normal file
0
neutron/plugins/oneconvergence/lib/__init__.py
Normal file
0
neutron/plugins/oneconvergence/lib/__init__.py
Normal file
41
neutron/plugins/oneconvergence/lib/config.py
Normal file
41
neutron/plugins/oneconvergence/lib/config.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Copyright 2014 OneConvergence, 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
""" Register the configuration options"""
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
|
||||||
|
NVSD_OPT = [
|
||||||
|
cfg.StrOpt('nvsd_ip',
|
||||||
|
default='127.0.0.1',
|
||||||
|
help=_("NVSD Controller IP address")),
|
||||||
|
cfg.IntOpt('nvsd_port',
|
||||||
|
default=8082,
|
||||||
|
help=_("NVSD Controller Port number")),
|
||||||
|
cfg.StrOpt('nvsd_user',
|
||||||
|
default='ocplugin',
|
||||||
|
help=_("NVSD Controller username")),
|
||||||
|
cfg.StrOpt('nvsd_passwd',
|
||||||
|
default='oc123', secret=True,
|
||||||
|
help=_("NVSD Controller password")),
|
||||||
|
cfg.IntOpt('request_timeout',
|
||||||
|
default=30,
|
||||||
|
help=_("NVSD controller REST API request timeout in seconds")),
|
||||||
|
cfg.IntOpt('nvsd_retries', default=0,
|
||||||
|
help=_("Number of login retries to NVSD controller"))
|
||||||
|
]
|
||||||
|
|
||||||
|
cfg.CONF.register_opts(NVSD_OPT, "nvsd")
|
55
neutron/plugins/oneconvergence/lib/exception.py
Normal file
55
neutron/plugins/oneconvergence/lib/exception.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Copyright 2014 OneConvergence, 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""NVSD Exception Definitions."""
|
||||||
|
|
||||||
|
from neutron.common import exceptions as n_exc
|
||||||
|
|
||||||
|
|
||||||
|
class NVSDAPIException(n_exc.NeutronException):
|
||||||
|
'''Base NVSDplugin Exception.'''
|
||||||
|
message = _("An unknown nvsd plugin exception occurred: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
|
class RequestTimeout(NVSDAPIException):
|
||||||
|
message = _("The request has timed out.")
|
||||||
|
|
||||||
|
|
||||||
|
class UnAuthorizedException(NVSDAPIException):
|
||||||
|
message = _("Invalid access credentials to the Server.")
|
||||||
|
|
||||||
|
|
||||||
|
class NotFoundException(NVSDAPIException):
|
||||||
|
message = _("A resource is not found: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
|
class BadRequestException(NVSDAPIException):
|
||||||
|
message = _("Request sent to server is invalid: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
|
class ServerException(NVSDAPIException):
|
||||||
|
message = _("Internal Server Error: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionClosedException(NVSDAPIException):
|
||||||
|
message = _("Connection is closed by the server.")
|
||||||
|
|
||||||
|
|
||||||
|
class ForbiddenException(NVSDAPIException):
|
||||||
|
message = _("The request is forbidden access to the resource: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
|
class InternalServerError(NVSDAPIException):
|
||||||
|
message = _("Internal Server Error from NVSD controller: %(reason)s")
|
262
neutron/plugins/oneconvergence/lib/nvsdlib.py
Normal file
262
neutron/plugins/oneconvergence/lib/nvsdlib.py
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
# Copyright 2014 OneConvergence, 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: Kedar Kulkarni, One Convergence, Inc.
|
||||||
|
|
||||||
|
"""Intermidiate NVSD Library."""
|
||||||
|
|
||||||
|
from neutron.openstack.common import excutils
|
||||||
|
from neutron.openstack.common import jsonutils as json
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
import neutron.plugins.oneconvergence.lib.exception as nvsdexception
|
||||||
|
from neutron.plugins.oneconvergence.lib import plugin_helper
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
NETWORKS_URI = "/pluginhandler/ocplugin/tenant/%s/lnetwork/"
|
||||||
|
NETWORK_URI = NETWORKS_URI + "%s"
|
||||||
|
GET_ALL_NETWORKS = "/pluginhandler/ocplugin/tenant/getallnetworks"
|
||||||
|
|
||||||
|
SUBNETS_URI = NETWORK_URI + "/lsubnet/"
|
||||||
|
SUBNET_URI = SUBNETS_URI + "%s"
|
||||||
|
GET_ALL_SUBNETS = "/pluginhandler/ocplugin/tenant/getallsubnets"
|
||||||
|
|
||||||
|
PORTS_URI = NETWORK_URI + "/lport/"
|
||||||
|
PORT_URI = PORTS_URI + "%s"
|
||||||
|
|
||||||
|
METHODS = {"POST": "create",
|
||||||
|
"PUT": "update",
|
||||||
|
"DELETE": "delete",
|
||||||
|
"GET": "get"}
|
||||||
|
|
||||||
|
|
||||||
|
class NVSDApi(object):
|
||||||
|
|
||||||
|
def build_error_msg(self, method, resource, tenant_id, resource_id):
|
||||||
|
if method == "POST":
|
||||||
|
msg = _("Could not create a %(resource)s under tenant "
|
||||||
|
"%(tenant_id)s") % {'resource': resource,
|
||||||
|
'tenant_id': tenant_id}
|
||||||
|
elif resource_id:
|
||||||
|
msg = _("Failed to %(method)s %(resource)s "
|
||||||
|
"id=%(resource_id)s") % {'method': METHODS[method],
|
||||||
|
'resource': resource,
|
||||||
|
'resource_id': resource_id
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
msg = _("Failed to %(method)s %(resource)s") % {
|
||||||
|
'method': METHODS[method], 'resource': resource}
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def set_connection(self):
|
||||||
|
self.nvsdcontroller = plugin_helper.initialize_plugin_helper()
|
||||||
|
self.nvsdcontroller.login()
|
||||||
|
|
||||||
|
def send_request(self, method, uri, body=None, resource=None,
|
||||||
|
tenant_id='', resource_id=None):
|
||||||
|
"""Issue a request to NVSD controller."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = self.nvsdcontroller.request(method, uri, body=body)
|
||||||
|
except nvsdexception.NVSDAPIException as e:
|
||||||
|
with excutils.save_and_reraise_exception() as ctxt:
|
||||||
|
msg = self.build_error_msg(method, resource, tenant_id,
|
||||||
|
resource_id)
|
||||||
|
LOG.error(msg)
|
||||||
|
# Modifying the reason message without disturbing the exception
|
||||||
|
# info
|
||||||
|
ctxt.value = type(e)(reason=msg)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def create_network(self, network):
|
||||||
|
|
||||||
|
tenant_id = network['tenant_id']
|
||||||
|
router_external = network['router:external'] is True
|
||||||
|
|
||||||
|
network_obj = {
|
||||||
|
"name": network['name'],
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"shared": network['shared'],
|
||||||
|
"admin_state_up": network['admin_state_up'],
|
||||||
|
"router:external": router_external
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = NETWORKS_URI % tenant_id
|
||||||
|
|
||||||
|
response = self.send_request("POST", uri, body=json.dumps(network_obj),
|
||||||
|
resource='network', tenant_id=tenant_id)
|
||||||
|
|
||||||
|
nvsd_net = response.json()
|
||||||
|
|
||||||
|
LOG.debug(_("Network %(id)s created under tenant %(tenant_id)s"),
|
||||||
|
{'id': nvsd_net['id'], 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
return nvsd_net
|
||||||
|
|
||||||
|
def update_network(self, network, network_update):
|
||||||
|
|
||||||
|
tenant_id = network['tenant_id']
|
||||||
|
network_id = network['id']
|
||||||
|
|
||||||
|
uri = NETWORK_URI % (tenant_id, network_id)
|
||||||
|
|
||||||
|
self.send_request("PUT", uri,
|
||||||
|
body=json.dumps(network_update),
|
||||||
|
resource='network', tenant_id=tenant_id,
|
||||||
|
resource_id=network_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Network %(id)s updated under tenant %(tenant_id)s"),
|
||||||
|
{'id': network_id, 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def delete_network(self, network, subnets=[]):
|
||||||
|
|
||||||
|
tenant_id = network['tenant_id']
|
||||||
|
network_id = network['id']
|
||||||
|
|
||||||
|
ports = self._get_ports(tenant_id, network_id)
|
||||||
|
|
||||||
|
for port in ports:
|
||||||
|
self.delete_port(port['id'], port)
|
||||||
|
|
||||||
|
for subnet in subnets:
|
||||||
|
self.delete_subnet(subnet)
|
||||||
|
|
||||||
|
path = NETWORK_URI % (tenant_id, network_id)
|
||||||
|
|
||||||
|
self.send_request("DELETE", path, resource='network',
|
||||||
|
tenant_id=tenant_id, resource_id=network_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Network %(id)s deleted under tenant %(tenant_id)s"),
|
||||||
|
{'id': network_id, 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def create_subnet(self, subnet):
|
||||||
|
|
||||||
|
tenant_id = subnet['tenant_id']
|
||||||
|
network_id = subnet['network_id']
|
||||||
|
|
||||||
|
uri = SUBNETS_URI % (tenant_id, network_id)
|
||||||
|
|
||||||
|
self.send_request("POST", uri, body=json.dumps(subnet),
|
||||||
|
resource='subnet', tenant_id=tenant_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Subnet %(id)s created under tenant %(tenant_id)s"),
|
||||||
|
{'id': subnet['id'], 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def delete_subnet(self, subnet):
|
||||||
|
|
||||||
|
tenant_id = subnet['tenant_id']
|
||||||
|
network_id = subnet['network_id']
|
||||||
|
subnet_id = subnet['id']
|
||||||
|
|
||||||
|
uri = SUBNET_URI % (tenant_id, network_id, subnet_id)
|
||||||
|
|
||||||
|
self.send_request("DELETE", uri, resource='subnet',
|
||||||
|
tenant_id=tenant_id, resource_id=subnet_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Subnet %(id)s deleted under tenant %(tenant_id)s"),
|
||||||
|
{'id': subnet_id, 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def update_subnet(self, subnet, subnet_update):
|
||||||
|
|
||||||
|
tenant_id = subnet['tenant_id']
|
||||||
|
network_id = subnet['network_id']
|
||||||
|
subnet_id = subnet['id']
|
||||||
|
|
||||||
|
uri = SUBNET_URI % (tenant_id, network_id, subnet_id)
|
||||||
|
|
||||||
|
self.send_request("PUT", uri,
|
||||||
|
body=json.dumps(subnet_update),
|
||||||
|
resource='subnet', tenant_id=tenant_id,
|
||||||
|
resource_id=subnet_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Subnet %(id)s updated under tenant %(tenant_id)s"),
|
||||||
|
{'id': subnet_id, 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def create_port(self, tenant_id, port):
|
||||||
|
|
||||||
|
network_id = port["network_id"]
|
||||||
|
fixed_ips = port.get("fixed_ips")
|
||||||
|
ip_address = None
|
||||||
|
subnet_id = None
|
||||||
|
|
||||||
|
if fixed_ips:
|
||||||
|
ip_address = fixed_ips[0].get("ip_address")
|
||||||
|
subnet_id = fixed_ips[0].get("subnet_id")
|
||||||
|
|
||||||
|
lport = {
|
||||||
|
"id": port["id"],
|
||||||
|
"name": port["name"],
|
||||||
|
"device_id": port["device_id"],
|
||||||
|
"device_owner": port["device_owner"],
|
||||||
|
"mac_address": port["mac_address"],
|
||||||
|
"ip_address": ip_address,
|
||||||
|
"subnet_id": subnet_id,
|
||||||
|
"admin_state_up": port["admin_state_up"],
|
||||||
|
"network_id": network_id,
|
||||||
|
"status": port["status"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path = PORTS_URI % (tenant_id, network_id)
|
||||||
|
|
||||||
|
self.send_request("POST", path, body=json.dumps(lport),
|
||||||
|
resource='port', tenant_id=tenant_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Port %(id)s created under tenant %(tenant_id)s"),
|
||||||
|
{'id': port['id'], 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def update_port(self, tenant_id, port, port_update):
|
||||||
|
|
||||||
|
network_id = port['network_id']
|
||||||
|
port_id = port['id']
|
||||||
|
|
||||||
|
lport = {}
|
||||||
|
for k in ('admin_state_up', 'name', 'device_id', 'device_owner'):
|
||||||
|
if k in port_update:
|
||||||
|
lport[k] = port_update[k]
|
||||||
|
|
||||||
|
fixed_ips = port_update.get('fixed_ips', None)
|
||||||
|
if fixed_ips:
|
||||||
|
lport["ip_address"] = fixed_ips[0].get("ip_address")
|
||||||
|
lport["subnet_id"] = fixed_ips[0].get("subnet_id")
|
||||||
|
|
||||||
|
uri = PORT_URI % (tenant_id, network_id, port_id)
|
||||||
|
|
||||||
|
self.send_request("PUT", uri, body=json.dumps(lport),
|
||||||
|
resource='port', tenant_id=tenant_id,
|
||||||
|
resource_id=port_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Port %(id)s updated under tenant %(tenant_id)s"),
|
||||||
|
{'id': port_id, 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def delete_port(self, port_id, port):
|
||||||
|
|
||||||
|
tenant_id = port['tenant_id']
|
||||||
|
network_id = port['network_id']
|
||||||
|
|
||||||
|
uri = PORT_URI % (tenant_id, network_id, port_id)
|
||||||
|
|
||||||
|
self.send_request("DELETE", uri, resource='port', tenant_id=tenant_id,
|
||||||
|
resource_id=port_id)
|
||||||
|
|
||||||
|
LOG.debug(_("Port %(id)s deleted under tenant %(tenant_id)s"),
|
||||||
|
{'id': port_id, 'tenant_id': tenant_id})
|
||||||
|
|
||||||
|
def _get_ports(self, tenant_id, network_id):
|
||||||
|
|
||||||
|
uri = PORTS_URI % (tenant_id, network_id)
|
||||||
|
|
||||||
|
response = self.send_request("GET", uri, resource='ports',
|
||||||
|
tenant_id=tenant_id)
|
||||||
|
|
||||||
|
return response.json()
|
186
neutron/plugins/oneconvergence/lib/plugin_helper.py
Normal file
186
neutron/plugins/oneconvergence/lib/plugin_helper.py
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
# Copyright 2014 OneConvergence, 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: Kedar Kulkarni, One Convergence, Inc.
|
||||||
|
|
||||||
|
"""Library to talk to NVSD controller."""
|
||||||
|
|
||||||
|
import httplib
|
||||||
|
import time
|
||||||
|
from urlparse import urljoin
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from neutron.openstack.common import jsonutils as json
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
import neutron.plugins.oneconvergence.lib.exception as exception
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_plugin_helper():
|
||||||
|
nvsdcontroller = NVSDController()
|
||||||
|
return nvsdcontroller
|
||||||
|
|
||||||
|
|
||||||
|
class NVSDController(object):
|
||||||
|
|
||||||
|
"""Encapsulates the NVSD Controller details."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self._host = cfg.CONF.nvsd.nvsd_ip
|
||||||
|
self._port = cfg.CONF.nvsd.nvsd_port
|
||||||
|
self._user = cfg.CONF.nvsd.nvsd_user
|
||||||
|
self._password = cfg.CONF.nvsd.nvsd_passwd
|
||||||
|
self._retries = cfg.CONF.nvsd.nvsd_retries
|
||||||
|
self._request_timeout = float(cfg.CONF.nvsd.request_timeout)
|
||||||
|
self.api_url = 'http://' + self._host + ':' + str(self._port)
|
||||||
|
|
||||||
|
self.pool = requests.Session()
|
||||||
|
|
||||||
|
self.auth_token = None
|
||||||
|
|
||||||
|
def do_request(self, method, url=None, headers=None, data=None,
|
||||||
|
timeout=10):
|
||||||
|
response = self.pool.request(method, url=url,
|
||||||
|
headers=headers, data=data,
|
||||||
|
timeout=self._request_timeout)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
"""Login to NVSD Controller."""
|
||||||
|
|
||||||
|
headers = {"Content-Type": "application/json"}
|
||||||
|
|
||||||
|
login_url = urljoin(self.api_url,
|
||||||
|
"/pluginhandler/ocplugin/authmgmt/login")
|
||||||
|
|
||||||
|
data = json.dumps({"user_name": self._user, "passwd": self._password})
|
||||||
|
|
||||||
|
attempts = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if attempts < self._retries:
|
||||||
|
attempts += 1
|
||||||
|
elif self._retries == 0:
|
||||||
|
attempts = 0
|
||||||
|
else:
|
||||||
|
msg = _("Unable to connect to NVSD controller. Exiting after "
|
||||||
|
"%(retries)s attempts") % {'retries': self._retries}
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.ServerException(reason=msg)
|
||||||
|
try:
|
||||||
|
response = self.do_request("POST", url=login_url,
|
||||||
|
headers=headers, data=data,
|
||||||
|
timeout=self._request_timeout)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_("Login Failed: %s"), e)
|
||||||
|
LOG.error(_("Unable to establish connection"
|
||||||
|
" with Controller %s"), self.api_url)
|
||||||
|
LOG.error(_("Retrying after 1 second..."))
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
if response.status_code == requests.codes.ok:
|
||||||
|
LOG.debug(_("Login Successful %(uri)s "
|
||||||
|
"%(status)s"), {'uri': self.api_url,
|
||||||
|
'status': response.status_code})
|
||||||
|
self.auth_token = json.loads(response.content)["session_uuid"]
|
||||||
|
LOG.debug(_("AuthToken = %s"), self.auth_token)
|
||||||
|
else:
|
||||||
|
LOG.error(_("login failed"))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def request(self, method, url, body="", content_type="application/json"):
|
||||||
|
"""Issue a request to NVSD controller."""
|
||||||
|
|
||||||
|
if self.auth_token is None:
|
||||||
|
LOG.warning(_("No Token, Re-login"))
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
headers = {"Content-Type": content_type}
|
||||||
|
|
||||||
|
uri = urljoin(url, "?authToken=%s" % self.auth_token)
|
||||||
|
|
||||||
|
url = urljoin(self.api_url, uri)
|
||||||
|
|
||||||
|
request_ok = False
|
||||||
|
response = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self.do_request(method, url=url,
|
||||||
|
headers=headers, data=body,
|
||||||
|
timeout=self._request_timeout)
|
||||||
|
|
||||||
|
LOG.debug(_("request: %(method)s %(uri)s successful"),
|
||||||
|
{'method': method, 'uri': self.api_url + uri})
|
||||||
|
request_ok = True
|
||||||
|
except httplib.IncompleteRead as e:
|
||||||
|
response = e.partial
|
||||||
|
request_ok = True
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_("request: Request failed from "
|
||||||
|
"Controller side :%s"), e)
|
||||||
|
|
||||||
|
if response is None:
|
||||||
|
# Timeout.
|
||||||
|
LOG.error(_("Response is Null, Request timed out: %(method)s to "
|
||||||
|
"%(uri)s"), {'method': method, 'uri': uri})
|
||||||
|
self.auth_token = None
|
||||||
|
raise exception.RequestTimeout()
|
||||||
|
|
||||||
|
status = response.status_code
|
||||||
|
if status == requests.codes.unauthorized:
|
||||||
|
self.auth_token = None
|
||||||
|
# Raise an exception to inform that the request failed.
|
||||||
|
raise exception.UnAuthorizedException()
|
||||||
|
|
||||||
|
if status in self.error_codes:
|
||||||
|
LOG.error(_("Request %(method)s %(uri)s body = %(body)s failed "
|
||||||
|
"with status %(status)s"), {'method': method,
|
||||||
|
'uri': uri, 'body': body,
|
||||||
|
'status': status})
|
||||||
|
LOG.error(_("%s"), response.reason)
|
||||||
|
raise self.error_codes[status]()
|
||||||
|
elif status not in (requests.codes.ok, requests.codes.created,
|
||||||
|
requests.codes.no_content):
|
||||||
|
LOG.error(_("%(method)s to %(url)s, unexpected response code: "
|
||||||
|
"%(status)d"), {'method': method, 'url': url,
|
||||||
|
'status': status})
|
||||||
|
return
|
||||||
|
|
||||||
|
if not request_ok:
|
||||||
|
LOG.error(_("Request failed from Controller side with "
|
||||||
|
"Status=%s"), status)
|
||||||
|
raise exception.ServerException()
|
||||||
|
else:
|
||||||
|
LOG.debug(_("Success: %(method)s %(url)s status=%(status)s"),
|
||||||
|
{'method': method, 'url': self.api_url + uri,
|
||||||
|
'status': status})
|
||||||
|
response.body = response.content
|
||||||
|
return response
|
||||||
|
|
||||||
|
error_codes = {
|
||||||
|
404: exception.NotFoundException,
|
||||||
|
409: exception.BadRequestException,
|
||||||
|
500: exception.InternalServerError,
|
||||||
|
503: exception.ServerException,
|
||||||
|
403: exception.ForbiddenException,
|
||||||
|
301: exception.NVSDAPIException,
|
||||||
|
307: exception.NVSDAPIException,
|
||||||
|
400: exception.NVSDAPIException,
|
||||||
|
}
|
300
neutron/plugins/oneconvergence/plugin.py
Normal file
300
neutron/plugins/oneconvergence/plugin.py
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
# Copyright 2014 OneConvergence, 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: Kedar Kulkarni, One Convergence, Inc.
|
||||||
|
|
||||||
|
"""Implementation of OneConvergence Neutron Plugin."""
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||||
|
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
||||||
|
from neutron.common import constants as q_const
|
||||||
|
from neutron.common import exceptions as nexception
|
||||||
|
from neutron.common import rpc as q_rpc
|
||||||
|
from neutron.common import topics
|
||||||
|
from neutron.db import agents_db
|
||||||
|
from neutron.db import agentschedulers_db
|
||||||
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import external_net_db
|
||||||
|
from neutron.db import extraroute_db
|
||||||
|
from neutron.db import l3_agentschedulers_db
|
||||||
|
from neutron.db import l3_gwmode_db
|
||||||
|
from neutron.db import l3_rpc_base
|
||||||
|
from neutron.db import portbindings_base
|
||||||
|
from neutron.db import quota_db # noqa
|
||||||
|
from neutron.extensions import portbindings
|
||||||
|
from neutron.openstack.common import excutils
|
||||||
|
from neutron.openstack.common import importutils
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.openstack.common import rpc
|
||||||
|
from neutron.plugins.common import constants as svc_constants
|
||||||
|
import neutron.plugins.oneconvergence.lib.config # noqa
|
||||||
|
import neutron.plugins.oneconvergence.lib.exception as nvsdexception
|
||||||
|
from neutron.plugins.oneconvergence.lib import nvsdlib as nvsd_lib
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
IPv6 = 6
|
||||||
|
|
||||||
|
|
||||||
|
class NVSDRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
|
||||||
|
l3_rpc_base.L3RpcCallbackMixin):
|
||||||
|
|
||||||
|
"""Agent callback."""
|
||||||
|
|
||||||
|
RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
|
def create_rpc_dispatcher(self):
|
||||||
|
"""Get the rpc dispatcher for this manager."""
|
||||||
|
return q_rpc.PluginRpcDispatcher([self,
|
||||||
|
agents_db.AgentExtRpcCallback()])
|
||||||
|
|
||||||
|
|
||||||
|
class OneConvergencePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
|
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
|
external_net_db.External_net_db_mixin,
|
||||||
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
|
portbindings_base.PortBindingBaseMixin):
|
||||||
|
|
||||||
|
"""L2 Virtual Network Plugin.
|
||||||
|
|
||||||
|
OneConvergencePluginV2 is a Neutron plugin that provides L2 Virtual Network
|
||||||
|
functionality.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__native_bulk_support = True
|
||||||
|
__native_pagination_support = True
|
||||||
|
__native_sorting_support = True
|
||||||
|
|
||||||
|
supported_extension_aliases = ['agent',
|
||||||
|
'binding',
|
||||||
|
'dhcp_agent_scheduler',
|
||||||
|
'ext-gw-mode',
|
||||||
|
'external-net',
|
||||||
|
'extraroute',
|
||||||
|
'l3_agent_scheduler',
|
||||||
|
'quotas',
|
||||||
|
'router',
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
super(OneConvergencePluginV2, self).__init__()
|
||||||
|
|
||||||
|
self.oneconvergence_init()
|
||||||
|
|
||||||
|
self.base_binding_dict = {
|
||||||
|
portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS}
|
||||||
|
|
||||||
|
portbindings_base.register_port_dict_function()
|
||||||
|
|
||||||
|
self.setup_rpc()
|
||||||
|
|
||||||
|
self.network_scheduler = importutils.import_object(
|
||||||
|
cfg.CONF.network_scheduler_driver)
|
||||||
|
self.router_scheduler = importutils.import_object(
|
||||||
|
cfg.CONF.router_scheduler_driver)
|
||||||
|
|
||||||
|
def oneconvergence_init(self):
|
||||||
|
"""Initialize the connections and set the log levels for the plugin."""
|
||||||
|
|
||||||
|
self.nvsdlib = nvsd_lib.NVSDApi()
|
||||||
|
self.nvsdlib.set_connection()
|
||||||
|
|
||||||
|
def setup_rpc(self):
|
||||||
|
# RPC support
|
||||||
|
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
|
||||||
|
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
|
||||||
|
self.conn = rpc.create_connection(new=True)
|
||||||
|
self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = (
|
||||||
|
dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||||
|
)
|
||||||
|
self.agent_notifiers[q_const.AGENT_TYPE_L3] = (
|
||||||
|
l3_rpc_agent_api.L3AgentNotify
|
||||||
|
)
|
||||||
|
self.callbacks = NVSDRpcCallbacks()
|
||||||
|
self.dispatcher = self.callbacks.create_rpc_dispatcher()
|
||||||
|
for svc_topic in self.service_topics.values():
|
||||||
|
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
|
||||||
|
|
||||||
|
# Consume from all consumers in a thread
|
||||||
|
self.conn.consume_in_thread()
|
||||||
|
|
||||||
|
def create_network(self, context, network):
|
||||||
|
|
||||||
|
net = self.nvsdlib.create_network(network['network'])
|
||||||
|
|
||||||
|
network['network']['id'] = net['id']
|
||||||
|
|
||||||
|
try:
|
||||||
|
neutron_net = super(OneConvergencePluginV2,
|
||||||
|
self).create_network(context, network)
|
||||||
|
|
||||||
|
#following call checks whether the network is external or not and
|
||||||
|
#if it is external then adds this network to externalnetworks
|
||||||
|
#table of neutron db
|
||||||
|
self._process_l3_create(context, neutron_net, network['network'])
|
||||||
|
except nvsdexception.NVSDAPIException:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
self.nvsdlib.delete_network(net)
|
||||||
|
|
||||||
|
return neutron_net
|
||||||
|
|
||||||
|
def update_network(self, context, net_id, network):
|
||||||
|
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
|
||||||
|
neutron_net = super(OneConvergencePluginV2,
|
||||||
|
self).update_network(context, net_id, network)
|
||||||
|
|
||||||
|
self.nvsdlib.update_network(neutron_net, network['network'])
|
||||||
|
# updates neutron database e.g. externalnetworks table.
|
||||||
|
self._process_l3_update(context, neutron_net, network['network'])
|
||||||
|
|
||||||
|
return neutron_net
|
||||||
|
|
||||||
|
def delete_network(self, context, net_id):
|
||||||
|
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
network = self._get_network(context, net_id)
|
||||||
|
#get all the subnets under the network to delete them
|
||||||
|
subnets = self._get_subnets_by_network(context, net_id)
|
||||||
|
|
||||||
|
super(OneConvergencePluginV2, self).delete_network(context,
|
||||||
|
net_id)
|
||||||
|
|
||||||
|
self.nvsdlib.delete_network(network, subnets)
|
||||||
|
|
||||||
|
def create_subnet(self, context, subnet):
|
||||||
|
|
||||||
|
if subnet['subnet']['ip_version'] == IPv6:
|
||||||
|
raise nexception.InvalidInput(
|
||||||
|
error_message="NVSDPlugin doesn't support IPv6.")
|
||||||
|
|
||||||
|
neutron_subnet = super(OneConvergencePluginV2,
|
||||||
|
self).create_subnet(context, subnet)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.nvsdlib.create_subnet(neutron_subnet)
|
||||||
|
except nvsdexception.NVSDAPIException:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
#Log the message and delete the subnet from the neutron
|
||||||
|
super(OneConvergencePluginV2,
|
||||||
|
self).delete_subnet(context, neutron_subnet['id'])
|
||||||
|
LOG.error(_("Failed to create subnet, "
|
||||||
|
"deleting it from neutron"))
|
||||||
|
|
||||||
|
return neutron_subnet
|
||||||
|
|
||||||
|
def delete_subnet(self, context, subnet_id):
|
||||||
|
|
||||||
|
neutron_subnet = self._get_subnet(context, subnet_id)
|
||||||
|
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
|
||||||
|
super(OneConvergencePluginV2, self).delete_subnet(context,
|
||||||
|
subnet_id)
|
||||||
|
|
||||||
|
self.nvsdlib.delete_subnet(neutron_subnet)
|
||||||
|
|
||||||
|
def update_subnet(self, context, subnet_id, subnet):
|
||||||
|
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
|
||||||
|
neutron_subnet = super(OneConvergencePluginV2,
|
||||||
|
self).update_subnet(context, subnet_id,
|
||||||
|
subnet)
|
||||||
|
|
||||||
|
self.nvsdlib.update_subnet(neutron_subnet, subnet)
|
||||||
|
return neutron_subnet
|
||||||
|
|
||||||
|
def create_port(self, context, port):
|
||||||
|
|
||||||
|
network = {}
|
||||||
|
|
||||||
|
network_id = port['port']['network_id']
|
||||||
|
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
|
||||||
|
# Invoke the Neutron API for creating port
|
||||||
|
neutron_port = super(OneConvergencePluginV2,
|
||||||
|
self).create_port(context, port)
|
||||||
|
|
||||||
|
self._process_portbindings_create_and_update(context,
|
||||||
|
port['port'],
|
||||||
|
neutron_port)
|
||||||
|
|
||||||
|
if port['port']['device_owner'] in ('network:router_gateway',
|
||||||
|
'network:floatingip'):
|
||||||
|
# for l3 requests, tenant_id will be None/''
|
||||||
|
network = self._get_network(context, network_id)
|
||||||
|
|
||||||
|
tenant_id = network['tenant_id']
|
||||||
|
else:
|
||||||
|
tenant_id = port['port']['tenant_id']
|
||||||
|
|
||||||
|
port_id = neutron_port['id']
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.nvsdlib.create_port(tenant_id, neutron_port)
|
||||||
|
except nvsdexception.NVSDAPIException:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
LOG.error(_("Deleting newly created "
|
||||||
|
"neutron port %s"), port_id)
|
||||||
|
super(OneConvergencePluginV2, self).delete_port(context,
|
||||||
|
port_id)
|
||||||
|
|
||||||
|
return neutron_port
|
||||||
|
|
||||||
|
def update_port(self, context, port_id, port):
|
||||||
|
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
|
||||||
|
neutron_port = super(OneConvergencePluginV2,
|
||||||
|
self).update_port(context, port_id, port)
|
||||||
|
|
||||||
|
if neutron_port['tenant_id'] == '':
|
||||||
|
network = self._get_network(context,
|
||||||
|
neutron_port['network_id'])
|
||||||
|
tenant_id = network['tenant_id']
|
||||||
|
else:
|
||||||
|
tenant_id = neutron_port['tenant_id']
|
||||||
|
|
||||||
|
self.nvsdlib.update_port(tenant_id, neutron_port, port['port'])
|
||||||
|
|
||||||
|
self._process_portbindings_create_and_update(context,
|
||||||
|
port['port'],
|
||||||
|
neutron_port)
|
||||||
|
return neutron_port
|
||||||
|
|
||||||
|
def delete_port(self, context, port_id, l3_port_check=True):
|
||||||
|
|
||||||
|
if l3_port_check:
|
||||||
|
self.prevent_l3_port_deletion(context, port_id)
|
||||||
|
|
||||||
|
neutron_port = self._get_port(context, port_id)
|
||||||
|
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
|
||||||
|
self.disassociate_floatingips(context, port_id)
|
||||||
|
|
||||||
|
super(OneConvergencePluginV2, self).delete_port(context, port_id)
|
||||||
|
|
||||||
|
network = self._get_network(context, neutron_port['network_id'])
|
||||||
|
neutron_port['tenant_id'] = network['tenant_id']
|
||||||
|
|
||||||
|
self.nvsdlib.delete_port(port_id, neutron_port)
|
0
neutron/tests/unit/oneconvergence/__init__.py
Normal file
0
neutron/tests/unit/oneconvergence/__init__.py
Normal file
109
neutron/tests/unit/oneconvergence/test_nvsd_plugin.py
Normal file
109
neutron/tests/unit/oneconvergence/test_nvsd_plugin.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# Copyright 2014 OneConvergence, 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""Test Library for OneConvergencePlugin."""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron import context
|
||||||
|
from neutron.extensions import portbindings
|
||||||
|
from neutron.manager import NeutronManager
|
||||||
|
from neutron.plugins.oneconvergence import plugin as nvsd_plugin
|
||||||
|
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
||||||
|
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||||
|
|
||||||
|
PLUGIN_NAME = 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2'
|
||||||
|
|
||||||
|
|
||||||
|
class OneConvergencePluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
_plugin_name = PLUGIN_NAME
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
def mocked_oneconvergence_init(self):
|
||||||
|
def side_effect(*args, **kwargs):
|
||||||
|
return {'id': str(uuid.uuid4())}
|
||||||
|
|
||||||
|
self.nvsdlib = mock.Mock()
|
||||||
|
self.nvsdlib.create_network.side_effect = side_effect
|
||||||
|
|
||||||
|
self.addCleanup(mock.patch.stopall)
|
||||||
|
|
||||||
|
with mock.patch.object(nvsd_plugin.OneConvergencePluginV2,
|
||||||
|
'oneconvergence_init',
|
||||||
|
new=mocked_oneconvergence_init):
|
||||||
|
super(OneConvergencePluginV2TestCase,
|
||||||
|
self).setUp(self._plugin_name)
|
||||||
|
|
||||||
|
|
||||||
|
class TestOneConvergencePluginNetworksV2(test_plugin.TestNetworksV2,
|
||||||
|
OneConvergencePluginV2TestCase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestOneConvergencePluginSubnetsV2(test_plugin.TestSubnetsV2,
|
||||||
|
OneConvergencePluginV2TestCase):
|
||||||
|
def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_create_subnet_with_v6_allocation_pool(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
|
||||||
|
class TestOneConvergencePluginPortsV2(test_plugin.TestPortsV2,
|
||||||
|
test_bindings.PortBindingsTestCase,
|
||||||
|
OneConvergencePluginV2TestCase):
|
||||||
|
VIF_TYPE = portbindings.VIF_TYPE_OVS
|
||||||
|
|
||||||
|
def test_requested_subnet_id_v4_and_v6(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_port_vif_details(self):
|
||||||
|
plugin = NeutronManager.get_plugin()
|
||||||
|
with self.port(name='name') as port1:
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
port = plugin.get_port(ctx, port1['port']['id'])
|
||||||
|
self.assertEqual(port['binding:vif_type'],
|
||||||
|
portbindings.VIF_TYPE_OVS)
|
||||||
|
|
||||||
|
def test_ports_vif_details(self):
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
plugin = NeutronManager.get_plugin()
|
||||||
|
with contextlib.nested(self.port(), self.port()) as (port1, port2):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ports = plugin.get_ports(ctx)
|
||||||
|
self.assertEqual(len(ports), 2)
|
||||||
|
for port in ports:
|
||||||
|
self.assertEqual(port['binding:vif_type'],
|
||||||
|
portbindings.VIF_TYPE_OVS)
|
||||||
|
|
||||||
|
|
||||||
|
class TestOneConvergenceBasicGet(test_plugin.TestBasicGet,
|
||||||
|
OneConvergencePluginV2TestCase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestOneConvergenceV2HTTPResponse(test_plugin.TestV2HTTPResponse,
|
||||||
|
OneConvergencePluginV2TestCase):
|
||||||
|
pass
|
186
neutron/tests/unit/oneconvergence/test_nvsdlib.py
Normal file
186
neutron/tests/unit/oneconvergence/test_nvsdlib.py
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
# Copyright 2014 OneConvergence, Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from neutron.openstack.common import jsonutils as json
|
||||||
|
from neutron.plugins.oneconvergence.lib import nvsdlib
|
||||||
|
from neutron.tests import base
|
||||||
|
|
||||||
|
NETWORKS_URI = "/pluginhandler/ocplugin/tenant/%s/lnetwork/"
|
||||||
|
NETWORK_URI = NETWORKS_URI + "%s"
|
||||||
|
GET_ALL_NETWORKS = "/pluginhandler/ocplugin/tenant/getallnetworks"
|
||||||
|
|
||||||
|
SUBNETS_URI = NETWORK_URI + "/lsubnet/"
|
||||||
|
SUBNET_URI = SUBNETS_URI + "%s"
|
||||||
|
GET_ALL_SUBNETS = "/pluginhandler/ocplugin/tenant/getallsubnets"
|
||||||
|
|
||||||
|
PORTS_URI = NETWORK_URI + "/lport/"
|
||||||
|
PORT_URI = PORTS_URI + "%s"
|
||||||
|
|
||||||
|
TEST_NET = 'test-network'
|
||||||
|
TEST_SUBNET = 'test-subnet'
|
||||||
|
TEST_PORT = 'test-port'
|
||||||
|
TEST_TENANT = 'test-tenant'
|
||||||
|
|
||||||
|
|
||||||
|
class TestNVSDApi(base.BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNVSDApi, self).setUp()
|
||||||
|
self.nvsdlib = nvsdlib.NVSDApi()
|
||||||
|
|
||||||
|
def test_create_network(self):
|
||||||
|
network_obj = {
|
||||||
|
"name": 'test-net',
|
||||||
|
"tenant_id": TEST_TENANT,
|
||||||
|
"shared": False,
|
||||||
|
"admin_state_up": True,
|
||||||
|
"router:external": False
|
||||||
|
}
|
||||||
|
resp = mock.Mock()
|
||||||
|
resp.json.return_value = {'id': 'uuid'}
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request',
|
||||||
|
return_value=resp) as send_request:
|
||||||
|
uri = NETWORKS_URI % TEST_TENANT
|
||||||
|
net = self.nvsdlib.create_network(network_obj)
|
||||||
|
send_request.assert_called_once_with("POST", uri,
|
||||||
|
body=json.dumps(network_obj),
|
||||||
|
resource='network',
|
||||||
|
tenant_id=TEST_TENANT)
|
||||||
|
self.assertEqual(net, {'id': 'uuid'})
|
||||||
|
|
||||||
|
def test_update_network(self):
|
||||||
|
network = {'id': TEST_NET,
|
||||||
|
'tenant_id': TEST_TENANT}
|
||||||
|
update_network = {'name': 'new_name'}
|
||||||
|
uri = NETWORK_URI % (TEST_TENANT, TEST_NET)
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
self.nvsdlib.update_network(network, update_network)
|
||||||
|
send_request.assert_called_once_with(
|
||||||
|
"PUT", uri, body=json.dumps(update_network),
|
||||||
|
resource='network', tenant_id=TEST_TENANT,
|
||||||
|
resource_id=TEST_NET)
|
||||||
|
|
||||||
|
def test_delete_network(self):
|
||||||
|
network = {'id': TEST_NET,
|
||||||
|
'tenant_id': TEST_TENANT}
|
||||||
|
|
||||||
|
uri = NETWORK_URI % (TEST_TENANT, TEST_NET)
|
||||||
|
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
with mock.patch.object(self.nvsdlib, '_get_ports'):
|
||||||
|
self.nvsdlib.delete_network(network)
|
||||||
|
send_request.assert_called_once_with(
|
||||||
|
"DELETE", uri, resource='network',
|
||||||
|
tenant_id=TEST_TENANT, resource_id=TEST_NET)
|
||||||
|
|
||||||
|
def test_create_port(self):
|
||||||
|
path = PORTS_URI % (TEST_TENANT, TEST_NET)
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
fixed_ips = [{'ip_address': '10.0.0.2',
|
||||||
|
'subnet_id': TEST_SUBNET}]
|
||||||
|
|
||||||
|
lport = {
|
||||||
|
"id": TEST_PORT,
|
||||||
|
"name": 'test',
|
||||||
|
"device_id": "device_id",
|
||||||
|
"device_owner": "device_owner",
|
||||||
|
"mac_address": "mac_address",
|
||||||
|
"fixed_ips": fixed_ips,
|
||||||
|
"admin_state_up": True,
|
||||||
|
"network_id": TEST_NET,
|
||||||
|
"status": 'ACTIVE'
|
||||||
|
}
|
||||||
|
self.nvsdlib.create_port(TEST_TENANT, lport)
|
||||||
|
expected = {"id": TEST_PORT, "name": 'test',
|
||||||
|
"device_id": "device_id",
|
||||||
|
"device_owner": "device_owner",
|
||||||
|
"mac_address": "mac_address",
|
||||||
|
"ip_address": '10.0.0.2',
|
||||||
|
"subnet_id": TEST_SUBNET,
|
||||||
|
"admin_state_up": True,
|
||||||
|
"network_id": TEST_NET,
|
||||||
|
"status": 'ACTIVE'}
|
||||||
|
send_request.assert_called_once_with("POST", path,
|
||||||
|
body=json.dumps(expected),
|
||||||
|
resource='port',
|
||||||
|
tenant_id=TEST_TENANT)
|
||||||
|
|
||||||
|
def test_update_port(self):
|
||||||
|
port = {'id': TEST_PORT,
|
||||||
|
'network_id': TEST_NET}
|
||||||
|
|
||||||
|
port_update = {'name': 'new-name'}
|
||||||
|
uri = PORT_URI % (TEST_TENANT, TEST_NET, TEST_PORT)
|
||||||
|
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
self.nvsdlib.update_port(TEST_TENANT, port, port_update)
|
||||||
|
send_request.assert_called_once_with("PUT", uri,
|
||||||
|
body=json.dumps(port_update),
|
||||||
|
resource='port',
|
||||||
|
resource_id='test-port',
|
||||||
|
tenant_id=TEST_TENANT)
|
||||||
|
|
||||||
|
def test_delete_port(self):
|
||||||
|
port = {'network_id': TEST_NET,
|
||||||
|
'tenant_id': TEST_TENANT}
|
||||||
|
uri = PORT_URI % (TEST_TENANT, TEST_NET, TEST_PORT)
|
||||||
|
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
self.nvsdlib.delete_port(TEST_PORT, port)
|
||||||
|
send_request.assert_called_once_with("DELETE", uri,
|
||||||
|
resource='port',
|
||||||
|
tenant_id=TEST_TENANT,
|
||||||
|
resource_id=TEST_PORT)
|
||||||
|
|
||||||
|
def test_create_subnet(self):
|
||||||
|
subnet = {'id': TEST_SUBNET,
|
||||||
|
'tenant_id': TEST_TENANT,
|
||||||
|
'network_id': TEST_NET}
|
||||||
|
uri = SUBNETS_URI % (TEST_TENANT, TEST_NET)
|
||||||
|
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
self.nvsdlib.create_subnet(subnet)
|
||||||
|
send_request.assert_called_once_with("POST", uri,
|
||||||
|
body=json.dumps(subnet),
|
||||||
|
resource='subnet',
|
||||||
|
tenant_id=TEST_TENANT)
|
||||||
|
|
||||||
|
def test_update_subnet(self):
|
||||||
|
subnet = {'id': TEST_SUBNET,
|
||||||
|
'tenant_id': TEST_TENANT,
|
||||||
|
'network_id': TEST_NET}
|
||||||
|
subnet_update = {'name': 'new-name'}
|
||||||
|
uri = SUBNET_URI % (TEST_TENANT, TEST_NET, TEST_SUBNET)
|
||||||
|
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
self.nvsdlib.update_subnet(subnet, subnet_update)
|
||||||
|
send_request.assert_called_once_with(
|
||||||
|
"PUT", uri, body=json.dumps(subnet_update), resource='subnet',
|
||||||
|
tenant_id=TEST_TENANT, resource_id=TEST_SUBNET)
|
||||||
|
|
||||||
|
def test_delete_subnet(self):
|
||||||
|
subnet = {'id': TEST_SUBNET,
|
||||||
|
'tenant_id': TEST_TENANT,
|
||||||
|
'network_id': TEST_NET}
|
||||||
|
uri = SUBNET_URI % (TEST_TENANT, TEST_NET, TEST_SUBNET)
|
||||||
|
|
||||||
|
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||||
|
self.nvsdlib.delete_subnet(subnet)
|
||||||
|
send_request.assert_called_once_with("DELETE", uri,
|
||||||
|
resource='subnet',
|
||||||
|
tenant_id=TEST_TENANT,
|
||||||
|
resource_id=TEST_SUBNET)
|
60
neutron/tests/unit/oneconvergence/test_plugin_helper.py
Normal file
60
neutron/tests/unit/oneconvergence/test_plugin_helper.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright 2014 OneConvergence, 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: Kedar Kulkarni, One Convergence, Inc.
|
||||||
|
import mock
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from neutron.openstack.common import jsonutils as json
|
||||||
|
from neutron.plugins.oneconvergence.lib import config # noqa
|
||||||
|
from neutron.plugins.oneconvergence.lib import plugin_helper as client
|
||||||
|
from neutron.tests import base
|
||||||
|
|
||||||
|
|
||||||
|
class TestPluginHelper(base.BaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestPluginHelper, self).setUp()
|
||||||
|
self.nvsdcontroller = client.NVSDController()
|
||||||
|
|
||||||
|
def get_response(self, *args, **kwargs):
|
||||||
|
response = mock.Mock()
|
||||||
|
response.status_code = requests.codes.ok
|
||||||
|
response.content = json.dumps({'session_uuid': 'new_auth_token'})
|
||||||
|
return response
|
||||||
|
|
||||||
|
def test_login(self):
|
||||||
|
login_url = ('http://127.0.0.1:8082/pluginhandler/ocplugin/'
|
||||||
|
'authmgmt/login')
|
||||||
|
headers = {'Content-Type': 'application/json'}
|
||||||
|
data = json.dumps({"user_name": "ocplugin", "passwd": "oc123"})
|
||||||
|
timeout = 30.0
|
||||||
|
|
||||||
|
with mock.patch.object(self.nvsdcontroller, 'do_request',
|
||||||
|
side_effect=self.get_response) as do_request:
|
||||||
|
self.nvsdcontroller.login()
|
||||||
|
do_request.assert_called_once_with('POST', url=login_url,
|
||||||
|
headers=headers, data=data,
|
||||||
|
timeout=timeout)
|
||||||
|
|
||||||
|
def test_request(self):
|
||||||
|
with mock.patch.object(self.nvsdcontroller, 'do_request',
|
||||||
|
side_effect=self.get_response) as do_request:
|
||||||
|
self.nvsdcontroller.login()
|
||||||
|
self.nvsdcontroller.request("POST", "/some_url")
|
||||||
|
self.assertEqual(do_request.call_count, 2)
|
||||||
|
do_request.assert_called_with(
|
||||||
|
'POST',
|
||||||
|
url='http://127.0.0.1:8082/some_url?authToken=new_auth_token',
|
||||||
|
headers={'Content-Type': 'application/json'}, data='',
|
||||||
|
timeout=30.0)
|
@ -69,6 +69,7 @@ data_files =
|
|||||||
etc/neutron/plugins/mlnx = etc/neutron/plugins/mlnx/mlnx_conf.ini
|
etc/neutron/plugins/mlnx = etc/neutron/plugins/mlnx/mlnx_conf.ini
|
||||||
etc/neutron/plugins/nec = etc/neutron/plugins/nec/nec.ini
|
etc/neutron/plugins/nec = etc/neutron/plugins/nec/nec.ini
|
||||||
etc/neutron/plugins/nicira = etc/neutron/plugins/nicira/nvp.ini
|
etc/neutron/plugins/nicira = etc/neutron/plugins/nicira/nvp.ini
|
||||||
|
etc/neutron/plugins/oneconvergence = etc/neutron/plugins/oneconvergence/nvsdplugin.ini
|
||||||
etc/neutron/plugins/openvswitch = etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
|
etc/neutron/plugins/openvswitch = etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
|
||||||
etc/neutron/plugins/plumgrid = etc/neutron/plugins/plumgrid/plumgrid.ini
|
etc/neutron/plugins/plumgrid = etc/neutron/plugins/plumgrid/plumgrid.ini
|
||||||
etc/neutron/plugins/ryu = etc/neutron/plugins/ryu/ryu.ini
|
etc/neutron/plugins/ryu = etc/neutron/plugins/ryu/ryu.ini
|
||||||
@ -145,6 +146,7 @@ neutron.core_plugins =
|
|||||||
mlnx = neutron.plugins.mlnx.mlnx_plugin:MellanoxEswitchPlugin
|
mlnx = neutron.plugins.mlnx.mlnx_plugin:MellanoxEswitchPlugin
|
||||||
nec = neutron.plugins.nec.nec_plugin:NECPluginV2
|
nec = neutron.plugins.nec.nec_plugin:NECPluginV2
|
||||||
nicira = neutron.plugins.nicira.NeutronPlugin:NvpPluginV2
|
nicira = neutron.plugins.nicira.NeutronPlugin:NvpPluginV2
|
||||||
|
oneconvergence = neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2
|
||||||
openvswitch = neutron.plugins.openvswitch.ovs_neutron_plugin:OVSNeutronPluginV2
|
openvswitch = neutron.plugins.openvswitch.ovs_neutron_plugin:OVSNeutronPluginV2
|
||||||
plumgrid = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin:NeutronPluginPLUMgridV2
|
plumgrid = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin:NeutronPluginPLUMgridV2
|
||||||
ryu = neutron.plugins.ryu.ryu_neutron_plugin:RyuNeutronPluginV2
|
ryu = neutron.plugins.ryu.ryu_neutron_plugin:RyuNeutronPluginV2
|
||||||
|
Loading…
Reference in New Issue
Block a user