--- /dev/null
+[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
'neutron.plugins.vmware.plugin.NsxPlugin',
'neutron.plugins.vmware.plugin.NsxServicePlugin',
'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
'neutron.plugins.vmware.plugin.NsxPlugin',
'neutron.plugins.vmware.plugin.NsxServicePlugin',
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
+ 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
]
from alembic import op
'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin',
'neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2',
'neutron.plugins.vmware.plugin.NsxPlugin',
- 'neutron.plugins.vmware.plugin.NsxServicePlugin'
+ 'neutron.plugins.vmware.plugin.NsxServicePlugin',
+ 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
]
from alembic import op
'neutron.plugins.vmware.plugin.NsxServicePlugin',
'neutron.services.loadbalancer.plugin.LoadBalancerPlugin',
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
+ 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
]
from alembic import op
'neutron.plugins.nec.nec_plugin.NECPluginV2',
'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2',
'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin',
+ 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2',
'neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.'
'NeutronPluginPLUMgridV2',
'neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2',
'neutron.plugins.vmware.plugin.NsxPlugin',
'neutron.plugins.vmware.plugin.NsxServicePlugin',
+ 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
]
from alembic import op
'neutron.plugins.nec.nec_plugin.NECPluginV2',
'neutron.plugins.vmware.plugin.NsxPlugin',
'neutron.plugins.vmware.plugin.NsxServicePlugin',
+ 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
]
from alembic import op
'neutron.plugins.vmware.plugin.NsxServicePlugin',
'neutron.services.loadbalancer.plugin.LoadBalancerPlugin',
'neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2',
+ 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
]
from alembic import op
'ml2': 'neutron.plugins.ml2.plugin.Ml2Plugin',
'nec': 'neutron.plugins.nec.nec_plugin.NECPluginV2',
'nvp': 'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2',
+ 'ocnvsd': 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2',
'ovs': 'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2',
'plumgrid': 'neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.'
'NeutronPluginPLUMgridV2',
PLUGINS['meta'],
PLUGINS['ml2'],
PLUGINS['nec'],
+ PLUGINS['ocnvsd'],
PLUGINS['ovs'],
PLUGINS['ryu'],
PLUGINS['brocade'],
PLUGINS['lbr'],
PLUGINS['ml2'],
PLUGINS['nvp'],
+ PLUGINS['ocnvsd'],
PLUGINS['ovs'],
]
--- /dev/null
+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.
--- /dev/null
+# 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")
--- /dev/null
+# 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")
--- /dev/null
+# 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()
--- /dev/null
+# 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,
+ }
--- /dev/null
+# 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)
--- /dev/null
+# 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
--- /dev/null
+# 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)
--- /dev/null
+# 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)
etc/neutron/plugins/mlnx = etc/neutron/plugins/mlnx/mlnx_conf.ini
etc/neutron/plugins/nec = etc/neutron/plugins/nec/nec.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/plumgrid = etc/neutron/plugins/plumgrid/plumgrid.ini
etc/neutron/plugins/ryu = etc/neutron/plugins/ryu/ryu.ini
mlnx = neutron.plugins.mlnx.mlnx_plugin:MellanoxEswitchPlugin
nec = neutron.plugins.nec.nec_plugin:NECPluginV2
nicira = neutron.plugins.nicira.NeutronPlugin:NvpPluginV2
+ oneconvergence = neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2
openvswitch = neutron.plugins.openvswitch.ovs_neutron_plugin:OVSNeutronPluginV2
plumgrid = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin:NeutronPluginPLUMgridV2
ryu = neutron.plugins.ryu.ryu_neutron_plugin:RyuNeutronPluginV2