From 744ffcf141203979c3c9dfd0444c8fad09948df8 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Wed, 10 Jul 2013 15:11:16 -0700 Subject: [PATCH] PLUMgrid plugin v2 This commit implements blueprint plumgrid-plugin-v2 Includes PLUMlib Library Fake PLUMLib library for Unit Tests Remove the use of topologies Includes IOVISOR VIF driver Implements External Networks Change-Id: I8ba90862e5a416d04d3327b46fcb0f6f3fa65248 --- etc/neutron/plugins/plumgrid/plumgrid.ini | 23 +- neutron/extensions/portbindings.py | 1 + neutron/plugins/plumgrid/README | 5 +- neutron/plugins/plumgrid/common/exceptions.py | 2 +- neutron/plugins/plumgrid/drivers/__init__.py | 16 + .../plugins/plumgrid/drivers/fake_plumlib.py | 79 +++ neutron/plugins/plumgrid/drivers/plumlib.py | 85 +++ .../plumgrid_nos_snippets.py | 44 -- .../plumgrid_nos_plugin/plumgrid_plugin.py | 325 ----------- .../plumgrid_nos_plugin/rest_connection.py | 97 ---- .../__init__.py | 0 .../plugin_ver.py | 2 +- .../plumgrid_plugin/plumgrid_plugin.py | 546 ++++++++++++++++++ .../unit/plumgrid/test_plumgrid_plugin.py | 84 ++- 14 files changed, 807 insertions(+), 502 deletions(-) create mode 100644 neutron/plugins/plumgrid/drivers/__init__.py create mode 100644 neutron/plugins/plumgrid/drivers/fake_plumlib.py create mode 100644 neutron/plugins/plumgrid/drivers/plumlib.py delete mode 100644 neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_nos_snippets.py delete mode 100644 neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_plugin.py delete mode 100644 neutron/plugins/plumgrid/plumgrid_nos_plugin/rest_connection.py rename neutron/plugins/plumgrid/{plumgrid_nos_plugin => plumgrid_plugin}/__init__.py (100%) rename neutron/plugins/plumgrid/{plumgrid_nos_plugin => plumgrid_plugin}/plugin_ver.py (97%) create mode 100644 neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py diff --git a/etc/neutron/plugins/plumgrid/plumgrid.ini b/etc/neutron/plugins/plumgrid/plumgrid.ini index 6c3f525db4..2addf617fd 100644 --- a/etc/neutron/plugins/plumgrid/plumgrid.ini +++ b/etc/neutron/plugins/plumgrid/plumgrid.ini @@ -1,16 +1,13 @@ -# Config file for Neutron PLUMgrid plugin +# Config file for Neutron PLUMgrid Plugin -[plumgridnos] -# This line should be pointing to the NOS server, -# for the PLUMgrid platform. In other deployments, -# this is known as controller -# nos_server= -# nos_server_port= -# Authentification parameters for the NOS server. +[PLUMgridDirector] +# This line should be pointing to the PLUMgrid Director, +# for the PLUMgrid platform. +# director_server= +# director_server_port= +# Authentification parameters for the Director. # These are the admin credentials to manage and control -# the NOS server. -# username= -# password= +# the PLUMgrid Director server. +# username= +# password= # servertimeout=5 -# Name of the network topology to be deployed by NOS -# topologyname= diff --git a/neutron/extensions/portbindings.py b/neutron/extensions/portbindings.py index fa442d6002..e09d04642d 100644 --- a/neutron/extensions/portbindings.py +++ b/neutron/extensions/portbindings.py @@ -37,6 +37,7 @@ CAP_PORT_FILTER = 'port_filter' VIF_TYPE_UNBOUND = 'unbound' VIF_TYPE_BINDING_FAILED = 'binding_failed' +VIF_TYPE_IOVISOR = 'iovisor' VIF_TYPE_OVS = 'ovs' VIF_TYPE_IVS = 'ivs' VIF_TYPE_BRIDGE = 'bridge' diff --git a/neutron/plugins/plumgrid/README b/neutron/plugins/plumgrid/README index df8eb9f4e4..e7118307d3 100644 --- a/neutron/plugins/plumgrid/README +++ b/neutron/plugins/plumgrid/README @@ -1,7 +1,8 @@ -PLUMgrid Neutron Virtual Network Plugin +PLUMgrid Neutron Plugin for Virtual Network Infrastructure (VNI) This plugin implements Neutron v2 APIs and helps configure L2/L3 virtual networks consisting of PLUMgrid Platform. +Implements External Networks and Port Binding Extension For more details on use please refer to: -http://wiki.openstack.org/plumgrid-neutron +http://wiki.openstack.org/PLUMgrid-Neutron diff --git a/neutron/plugins/plumgrid/common/exceptions.py b/neutron/plugins/plumgrid/common/exceptions.py index f54d55308e..214978639a 100644 --- a/neutron/plugins/plumgrid/common/exceptions.py +++ b/neutron/plugins/plumgrid/common/exceptions.py @@ -28,4 +28,4 @@ class PLUMgridException(base_exec.NeutronException): class PLUMgridConnectionFailed(PLUMgridException): - message = _("Connection failed with PLUMgrid NOS: %(err_msg)s") + message = _("Connection failed with PLUMgrid Director: %(err_msg)s") diff --git a/neutron/plugins/plumgrid/drivers/__init__.py b/neutron/plugins/plumgrid/drivers/__init__.py new file mode 100644 index 0000000000..09cf65a010 --- /dev/null +++ b/neutron/plugins/plumgrid/drivers/__init__.py @@ -0,0 +1,16 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright 2013 PLUMgrid, 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: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. diff --git a/neutron/plugins/plumgrid/drivers/fake_plumlib.py b/neutron/plugins/plumgrid/drivers/fake_plumlib.py new file mode 100644 index 0000000000..20dc8c39a2 --- /dev/null +++ b/neutron/plugins/plumgrid/drivers/fake_plumlib.py @@ -0,0 +1,79 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright 2013 PLUMgrid, 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: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. + + +from neutron.openstack.common import log as logging + +LOG = logging.getLogger(__name__) + + +class Plumlib(): + """ + Class PLUMgrid Fake Library. This library is a by-pass implementation + for the PLUMgrid Library. This class is being used by the unit test + integration in Neutron. + """ + + def __init__(self): + LOG.info('Python PLUMgrid Fake Library Started ') + pass + + def director_conn(self, director_plumgrid, director_port, timeout): + LOG.info('Fake Director: %s', director_plumgrid + ':' + director_port) + pass + + def create_network(self, tenant_id, net_db): + pass + + def update_network(self, tenant_id, net_id): + pass + + def delete_network(self, net_db, net_id): + pass + + def create_subnet(self, sub_db, net_db, ipnet): + pass + + def update_subnet(self, org_sub_db, new_sub_db, ipnet): + pass + + def delete_subnet(self, tenant_id, net_db, net_id): + pass + + def create_port(self, port_db, router_db): + pass + + def update_port(self, port_db, router_db): + pass + + def delete_port(self, port_db, router_db): + pass + + def create_router(self, tenant_id, router_db): + pass + + def update_router(self, router_db, router_id): + pass + + def delete_router(self, tenant_id, router_id): + pass + + def add_router_interface(self, tenant_id, router_id, port_db, ipnet): + pass + + def remove_router_interface(self, tenant_id, net_id, router_id): + pass diff --git a/neutron/plugins/plumgrid/drivers/plumlib.py b/neutron/plugins/plumgrid/drivers/plumlib.py new file mode 100644 index 0000000000..e9ea6c50c6 --- /dev/null +++ b/neutron/plugins/plumgrid/drivers/plumlib.py @@ -0,0 +1,85 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright 2013 PLUMgrid, 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: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. + +""" +Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI) +This plugin will forward authenticated REST API calls +to the PLUMgrid Network Management System called Director +""" + +from plumgridlib import plumlib + +from neutron.openstack.common import log as logging + +LOG = logging.getLogger(__name__) + + +class Plumlib(object): + """ + Class PLUMgrid Python Library. This library is a third-party tool + needed by PLUMgrid plugin to implement all core API in Neutron. + """ + + def __init__(self): + LOG.info('Python PLUMgrid Library Started ') + + def director_conn(self, director_plumgrid, director_port, timeout): + self.plumlib = plumlib.Plumlib(director_plumgrid, + director_port, + timeout) + + def create_network(self, tenant_id, net_db): + self.plumlib.create_network(tenant_id, net_db) + + def update_network(self, tenant_id, net_id): + self.plumlib.update_network(tenant_id, net_id) + + def delete_network(self, net_db, net_id): + self.plumlib.delete_network(net_db, net_id) + + def create_subnet(self, sub_db, net_db, ipnet): + self.plumlib.create_subnet(sub_db, net_db, ipnet) + + def update_subnet(self, org_sub_db, new_sub_db, ipnet): + self.plumlib.update_subnet(org_sub_db, new_sub_db, ipnet) + + def delete_subnet(self, tenant_id, net_db, net_id): + self.plumlib.delete_subnet(tenant_id, net_db, net_id) + + def create_port(self, port_db, router_db): + self.plumlib.create_port(port_db, router_db) + + def update_port(self, port_db, router_db): + self.plumlib.update_port(port_db, router_db) + + def delete_port(self, port_db, router_db): + self.plumlib.delete_port(port_db, router_db) + + def create_router(self, tenant_id, router_db): + self.plumlib.create_router(tenant_id, router_db) + + def update_router(self, router_db, router_id): + self.plumlib.update_router(router_db, router_id) + + def delete_router(self, tenant_id, router_id): + self.plumlib.delete_router(tenant_id, router_id) + + def add_router_interface(self, tenant_id, router_id, port_db, ipnet): + self.plumlib.add_router_interface(tenant_id, router_id, port_db, ipnet) + + def remove_router_interface(self, tenant_id, net_id, router_id): + self.plumlib.remove_router_interface(tenant_id, net_id, router_id) diff --git a/neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_nos_snippets.py b/neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_nos_snippets.py deleted file mode 100644 index 6d6b221279..0000000000 --- a/neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_nos_snippets.py +++ /dev/null @@ -1,44 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2013 PLUMgrid, 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: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. -# @author: Brenden Blanco, bblanco@plumgrid.com, PLUMgrid, Inc. - -""" -Snippets needed by the PLUMgrid Plugin -""" - -from neutron.openstack.common import log as logging - - -LOG = logging.getLogger(__name__) - - -class DataNOSPLUMgrid(): - - BASE_NOS_URL = '/0/connectivity/domain/' - - def __init__(self): - LOG.info(_('NeutronPluginPLUMgrid Status: NOS Body Data Creation')) - - def create_domain_body_data(self, tenant_id): - body_data = {"container_group": tenant_id} - return body_data - - def create_network_body_data(self, tenant_id, topology_name): - body_data = {"config_template": "single_bridge", - "container_group": tenant_id, - "topology_name": topology_name} - return body_data diff --git a/neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_plugin.py b/neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_plugin.py deleted file mode 100644 index eb5f2636ab..0000000000 --- a/neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_plugin.py +++ /dev/null @@ -1,325 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2013 PLUMgrid, 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: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. - -""" -Neutron PLUMgrid Plug-in for PLUMgrid Virtual Technology -This plugin will forward authenticated REST API calls -to the Network Operating System by PLUMgrid called NOS -""" - -from oslo.config import cfg - -from neutron.db import api as db -from neutron.db import db_base_plugin_v2 -from neutron.openstack.common import log as logging -from neutron.plugins.plumgrid.common import exceptions as plum_excep -from neutron.plugins.plumgrid.plumgrid_nos_plugin.plugin_ver import VERSION -from neutron.plugins.plumgrid.plumgrid_nos_plugin import plumgrid_nos_snippets -from neutron.plugins.plumgrid.plumgrid_nos_plugin import rest_connection - - -LOG = logging.getLogger(__name__) - - -nos_server_opts = [ - cfg.StrOpt('nos_server', default='localhost', - help=_("PLUMgrid NOS server to connect to")), - cfg.StrOpt('nos_server_port', default='8080', - help=_("PLUMgrid NOS server port to connect to")), - cfg.StrOpt('username', default='username', - help=_("PLUMgrid NOS admin username")), - cfg.StrOpt('password', default='password', secret=True, - help=_("PLUMgrid NOS admin password")), - cfg.IntOpt('servertimeout', default=5, - help=_("PLUMgrid NOS server timeout")), - cfg.StrOpt('topologyname', default='t1', - help=_("PLUMgrid NOS topology name")), ] - - -cfg.CONF.register_opts(nos_server_opts, "PLUMgridNOS") - - -class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2): - - def __init__(self): - LOG.info(_('NeutronPluginPLUMgrid Status: Starting Plugin')) - - # PLUMgrid NOS configuration - nos_plumgrid = cfg.CONF.PLUMgridNOS.nos_server - nos_port = cfg.CONF.PLUMgridNOS.nos_server_port - timeout = cfg.CONF.PLUMgridNOS.servertimeout - self.topology_name = cfg.CONF.PLUMgridNOS.topologyname - self.snippets = plumgrid_nos_snippets.DataNOSPLUMgrid() - - # TODO(Edgar) These are placeholders for next PLUMgrid release - cfg.CONF.PLUMgridNOS.username - cfg.CONF.PLUMgridNOS.password - self.rest_conn = rest_connection.RestConnection(nos_plumgrid, - nos_port, timeout) - if self.rest_conn is None: - raise SystemExit(_('NeutronPluginPLUMgrid Status: ' - 'Aborting Plugin')) - - else: - # Plugin DB initialization - db.configure_db() - - # PLUMgrid NOS info validation - LOG.info(_('NeutronPluginPLUMgrid NOS: %s'), nos_plumgrid) - if not nos_plumgrid: - raise SystemExit(_('NeutronPluginPLUMgrid Status: ' - 'NOS value is missing in config file')) - - LOG.debug(_('NeutronPluginPLUMgrid Status: Neutron server with ' - 'PLUMgrid Plugin has started')) - - def create_network(self, context, network): - """Create network core Neutron API.""" - - LOG.debug(_('NeutronPluginPLUMgrid Status: create_network() called')) - - # Plugin DB - Network Create and validation - tenant_id = self._get_tenant_id_for_create(context, - network["network"]) - self._network_admin_state(network) - - with context.session.begin(subtransactions=True): - net = super(NeutronPluginPLUMgridV2, self).create_network(context, - network) - - try: - LOG.debug(_('NeutronPluginPLUMgrid Status: %(tenant_id)s, ' - '%(network)s, %(network_id)s'), - dict( - tenant_id=tenant_id, - network=network["network"], - network_id=net["id"], - )) - nos_url = self.snippets.BASE_NOS_URL + net["id"] - headers = {} - body_data = self.snippets.create_domain_body_data(tenant_id) - self.rest_conn.nos_rest_conn(nos_url, - 'PUT', body_data, headers) - - except Exception: - err_message = _("PLUMgrid NOS communication failed") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - - # return created network - return net - - def update_network(self, context, net_id, network): - """Update network core Neutron API.""" - - LOG.debug(_("NeutronPluginPLUMgridV2.update_network() called")) - self._network_admin_state(network) - tenant_id = self._get_tenant_id_for_create(context, network["network"]) - - with context.session.begin(subtransactions=True): - # Plugin DB - Network Update - new_network = super( - NeutronPluginPLUMgridV2, self).update_network(context, - net_id, network) - - try: - # PLUMgrid Server does not support updating resources yet - nos_url = self.snippets.BASE_NOS_URL + net_id - headers = {} - body_data = {} - self.rest_conn.nos_rest_conn(nos_url, - 'DELETE', body_data, headers) - nos_url = self.snippets.BASE_NOS_URL + new_network["id"] - body_data = self.snippets.create_domain_body_data(tenant_id) - self.rest_conn.nos_rest_conn(nos_url, - 'PUT', body_data, headers) - except Exception: - err_message = _("PLUMgrid NOS communication failed") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - - # return updated network - return new_network - - def delete_network(self, context, net_id): - """Delete network core Neutron API.""" - LOG.debug(_("NeutronPluginPLUMgrid Status: delete_network() called")) - super(NeutronPluginPLUMgridV2, self).get_network(context, net_id) - - with context.session.begin(subtransactions=True): - # Plugin DB - Network Delete - super(NeutronPluginPLUMgridV2, self).delete_network(context, - net_id) - - try: - nos_url = self.snippets.BASE_NOS_URL + net_id - headers = {} - body_data = {} - self.rest_conn.nos_rest_conn(nos_url, - 'DELETE', body_data, headers) - except Exception: - err_message = _("PLUMgrid NOS communication failed") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - - def create_port(self, context, port): - """Create port core Neutron API.""" - LOG.debug(_("NeutronPluginPLUMgrid Status: create_port() called")) - - # Port operations on PLUMgrid NOS is an automatic operation from the - # VIF driver operations in Nova. It requires admin_state_up to be True - port["port"]["admin_state_up"] = True - - # Plugin DB - Port Create and Return port - return super(NeutronPluginPLUMgridV2, self).create_port(context, - port) - - def update_port(self, context, port_id, port): - """Update port core Neutron API.""" - LOG.debug(_("NeutronPluginPLUMgrid Status: update_port() called")) - - # Port operations on PLUMgrid NOS is an automatic operation from the - # VIF driver operations in Nova. - - # Plugin DB - Port Update - return super(NeutronPluginPLUMgridV2, self).update_port( - context, port_id, port) - - def delete_port(self, context, port_id): - """Delete port core Neutron API.""" - - LOG.debug(_("NeutronPluginPLUMgrid Status: delete_port() called")) - - # Port operations on PLUMgrid NOS is an automatic operation from the - # VIF driver operations in Nova. - - # Plugin DB - Port Delete - super(NeutronPluginPLUMgridV2, self).delete_port(context, port_id) - - def create_subnet(self, context, subnet): - """Create subnet core Neutron API.""" - - LOG.debug(_("NeutronPluginPLUMgrid Status: create_subnet() called")) - - with context.session.begin(subtransactions=True): - # Plugin DB - Subnet Create - subnet = super(NeutronPluginPLUMgridV2, self).create_subnet( - context, subnet) - subnet_details = self._get_subnet(context, subnet["id"]) - net_id = subnet_details["network_id"] - tenant_id = subnet_details["tenant_id"] - - try: - nos_url = self.snippets.BASE_NOS_URL + net_id - headers = {} - body_data = self.snippets.create_network_body_data( - tenant_id, self.topology_name) - self.rest_conn.nos_rest_conn(nos_url, - 'PUT', body_data, headers) - except Exception: - err_message = _("PLUMgrid NOS communication failed: ") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - - return subnet - - def delete_subnet(self, context, subnet_id): - """Delete subnet core Neutron API.""" - - LOG.debug(_("NeutronPluginPLUMgrid Status: delete_subnet() called")) - #Collecting subnet info - subnet_details = self._get_subnet(context, subnet_id) - - with context.session.begin(subtransactions=True): - # Plugin DB - Subnet Delete - del_subnet = super(NeutronPluginPLUMgridV2, self).delete_subnet( - context, subnet_id) - try: - headers = {} - body_data = {} - net_id = subnet_details["network_id"] - self._cleaning_nos_subnet_structure(body_data, headers, net_id) - except Exception: - err_message = _("PLUMgrid NOS communication failed: ") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - - return del_subnet - - def update_subnet(self, context, subnet_id, subnet): - """Update subnet core Neutron API.""" - - LOG.debug(_("update_subnet() called")) - #Collecting subnet info - initial_subnet = self._get_subnet(context, subnet_id) - net_id = initial_subnet["network_id"] - tenant_id = initial_subnet["tenant_id"] - - with context.session.begin(subtransactions=True): - # Plugin DB - Subnet Update - new_subnet = super(NeutronPluginPLUMgridV2, self).update_subnet( - context, subnet_id, subnet) - - try: - # PLUMgrid Server does not support updating resources yet - headers = {} - body_data = {} - self._cleaning_nos_subnet_structure(body_data, headers, net_id) - nos_url = self.snippets.BASE_NOS_URL + net_id - body_data = self.snippets.create_network_body_data( - tenant_id, self.topology_name) - self.rest_conn.nos_rest_conn(nos_url, - 'PUT', body_data, headers) - - except Exception: - err_message = _("PLUMgrid NOS communication failed: ") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - - return new_subnet - - """ - Extension API implementation - """ - # TODO(Edgar) Complete extensions for PLUMgrid - - """ - Internal PLUMgrid fuctions - """ - - def _get_plugin_version(self): - return VERSION - - def _cleaning_nos_subnet_structure(self, body_data, headers, net_id): - domain_structure = ['/properties', '/link', '/ne'] - for structure in domain_structure: - nos_url = self.snippets.BASE_NOS_URL + net_id + structure - self.rest_conn.nos_rest_conn(nos_url, 'DELETE', body_data, headers) - - def _network_admin_state(self, network): - try: - if network["network"].get("admin_state_up"): - network_name = network["network"]["name"] - if network["network"]["admin_state_up"] is False: - LOG.warning(_("Network with admin_state_up=False are not " - "supported yet by this plugin. Ignoring " - "setting for network %s"), network_name) - except Exception: - err_message = _("Network Admin State Validation Falied: ") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - return network diff --git a/neutron/plugins/plumgrid/plumgrid_nos_plugin/rest_connection.py b/neutron/plugins/plumgrid/plumgrid_nos_plugin/rest_connection.py deleted file mode 100644 index 8e79b33916..0000000000 --- a/neutron/plugins/plumgrid/plumgrid_nos_plugin/rest_connection.py +++ /dev/null @@ -1,97 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2013 PLUMgrid, 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: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. -# @author: Brenden Blanco, bblanco@plumgrid.com, PLUMgrid, Inc. - -""" -Neutron PLUMgrid Plug-in for PLUMgrid Virtual Technology -This plugin will forward authenticated REST API calls -to the Network Operating System by PLUMgrid called NOS -""" - -import httplib -import urllib2 - -from neutron.openstack.common import jsonutils as json -from neutron.openstack.common import log as logging -from neutron.plugins.plumgrid.common import exceptions as plum_excep - - -LOG = logging.getLogger(__name__) - - -class RestConnection(object): - """REST Connection to PLUMgrid NOS Server.""" - - def __init__(self, server, port, timeout): - LOG.debug(_('NeutronPluginPLUMgrid Status: REST Connection Started')) - self.server = server - self.port = port - self.timeout = timeout - - def nos_rest_conn(self, nos_url, action, data, headers): - self.nos_url = nos_url - body_data = json.dumps(data) - if not headers: - headers = {} - headers['Content-type'] = 'application/json' - headers['Accept'] = 'application/json' - - LOG.debug(_("PLUMgrid_NOS_Server: %(server)s %(port)s %(action)s"), - dict(server=self.server, port=self.port, action=action)) - - conn = httplib.HTTPConnection(self.server, self.port, - timeout=self.timeout) - if conn is None: - LOG.error(_('PLUMgrid_NOS_Server: Could not establish HTTP ' - 'connection')) - return - - try: - LOG.debug(_("PLUMgrid_NOS_Server Sending Data: %(nos_url)s " - "%(body_data)s %(headers)s"), - dict( - nos_url=nos_url, - body_data=body_data, - headers=headers, - )) - conn.request(action, nos_url, body_data, headers) - resp = conn.getresponse() - resp_str = resp.read() - - LOG.debug(_("PLUMgrid_NOS_Server Connection Data: %(resp)s, " - "%(resp_str)s"), dict(resp=resp, resp_str=resp_str)) - - if resp.status is httplib.OK: - try: - respdata = json.loads(resp_str) - LOG.debug(_("PLUMgrid_NOS_Server Connection RESP: %s"), - respdata) - pass - except ValueError: - err_message = _("PLUMgrid HTTP Connection Failed: ") - LOG.Exception(err_message) - raise plum_excep.PLUMgridException(err_msg=err_message) - - ret = (resp.status, resp.reason, resp_str) - except urllib2.HTTPError: - LOG.error(_('PLUMgrid_NOS_Server: %(action)s failure, %(e)r')) - ret = 0, None, None, None - conn.close() - LOG.debug(_("PLUMgrid_NOS_Server: status=%(status)d, " - "reason=%(reason)r, ret=%(ret)s"), - {'status': ret[0], 'reason': ret[1], 'ret': ret[2]}) - return ret diff --git a/neutron/plugins/plumgrid/plumgrid_nos_plugin/__init__.py b/neutron/plugins/plumgrid/plumgrid_plugin/__init__.py similarity index 100% rename from neutron/plugins/plumgrid/plumgrid_nos_plugin/__init__.py rename to neutron/plugins/plumgrid/plumgrid_plugin/__init__.py diff --git a/neutron/plugins/plumgrid/plumgrid_nos_plugin/plugin_ver.py b/neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py similarity index 97% rename from neutron/plugins/plumgrid/plumgrid_nos_plugin/plugin_ver.py rename to neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py index d9286de9cf..5a47438c1c 100644 --- a/neutron/plugins/plumgrid/plumgrid_nos_plugin/plugin_ver.py +++ b/neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py @@ -16,4 +16,4 @@ # # @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. -VERSION = "0.1" +VERSION = "0.2" diff --git a/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py b/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py new file mode 100644 index 0000000000..14fff1c3d6 --- /dev/null +++ b/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py @@ -0,0 +1,546 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright 2013 PLUMgrid, 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: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc. + +""" +Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI) +This plugin will forward authenticated REST API calls +to the PLUMgrid Network Management System called Director +""" + +import netaddr +from oslo.config import cfg + +from neutron.api.v2 import attributes +from neutron.db import api as db +from neutron.db import db_base_plugin_v2 +from neutron.db import l3_db +from neutron.db import portbindings_db +from neutron.extensions import portbindings +from neutron.openstack.common import importutils +from neutron.openstack.common import log as logging +from neutron.plugins.plumgrid.common import exceptions as plum_excep +from neutron.plugins.plumgrid.plumgrid_plugin.plugin_ver import VERSION +from neutron import policy + +LOG = logging.getLogger(__name__) +PLUM_DRIVER = 'neutron.plugins.plumgrid.drivers.plumlib.Plumlib' +ERR_MESSAGE = 'PLUMgrid Director communication failed' + +director_server_opts = [ + cfg.StrOpt('director_server', default='localhost', + help=_("PLUMgrid Director server to connect to")), + cfg.StrOpt('director_server_port', default='8080', + help=_("PLUMgrid Director server port to connect to")), + cfg.StrOpt('username', default='username', + help=_("PLUMgrid Director admin username")), + cfg.StrOpt('password', default='password', secret=True, + help=_("PLUMgrid Director admin password")), + cfg.IntOpt('servertimeout', default=5, + help=_("PLUMgrid Director server timeout")), ] + +cfg.CONF.register_opts(director_server_opts, "PLUMgridDirector") + + +class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2, + portbindings_db.PortBindingMixin, + l3_db.L3_NAT_db_mixin): + + supported_extension_aliases = ["router", "binding"] + + binding_view = "extension:port_binding:view" + binding_set = "extension:port_binding:set" + + def __init__(self): + LOG.info(_('Neutron PLUMgrid Director: Starting Plugin')) + + # Plugin DB initialization + db.configure_db() + + self.plumgrid_init() + + LOG.debug(_('Neutron PLUMgrid Director: Neutron server with ' + 'PLUMgrid Plugin has started')) + + def plumgrid_init(self): + """PLUMgrid initialization.""" + director_plumgrid = cfg.CONF.PLUMgridDirector.director_server + director_port = cfg.CONF.PLUMgridDirector.director_server_port + timeout = cfg.CONF.PLUMgridDirector.servertimeout + + # PLUMgrid Director info validation + LOG.info(_('Neutron PLUMgrid Director: %s'), director_plumgrid) + self._plumlib = importutils.import_object(PLUM_DRIVER) + self._plumlib.director_conn(director_plumgrid, director_port, timeout) + + def create_network(self, context, network): + """Create Neutron network. + + Creates a PLUMgrid-based bridge. + """ + + LOG.debug(_('Neutron PLUMgrid Director: create_network() called')) + + # Plugin DB - Network Create and validation + tenant_id = self._get_tenant_id_for_create(context, + network["network"]) + self._network_admin_state(network) + + with context.session.begin(subtransactions=True): + net_db = super(NeutronPluginPLUMgridV2, + self).create_network(context, network) + # Propagate all L3 data into DB + self._process_l3_create(context, net_db, network['network']) + + try: + LOG.debug(_('PLUMgrid Library: create_network() called')) + self._plumlib.create_network(tenant_id, net_db) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + # Return created network + return net_db + + def update_network(self, context, net_id, network): + """Update Neutron network. + + Updates a PLUMgrid-based bridge. + """ + + LOG.debug(_("Neutron PLUMgrid Director: update_network() called")) + self._network_admin_state(network) + tenant_id = self._get_tenant_id_for_create(context, network["network"]) + + with context.session.begin(subtransactions=True): + # Plugin DB - Network Update + net_db = super( + NeutronPluginPLUMgridV2, self).update_network(context, + net_id, network) + + try: + LOG.debug(_("PLUMgrid Library: update_network() called")) + self._plumlib.update_network(tenant_id, net_id) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + # Return updated network + return net_db + + def delete_network(self, context, net_id): + """Delete Neutron network. + + Deletes a PLUMgrid-based bridge. + """ + + LOG.debug(_("Neutron PLUMgrid Director: delete_network() called")) + net_db = super(NeutronPluginPLUMgridV2, + self).get_network(context, net_id) + + with context.session.begin(subtransactions=True): + # Plugin DB - Network Delete + super(NeutronPluginPLUMgridV2, self).delete_network(context, + net_id) + + try: + LOG.debug(_("PLUMgrid Library: update_network() called")) + self._plumlib.delete_network(net_db, net_id) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + def create_port(self, context, port): + """Create Neutron port. + + Creates a PLUMgrid-based port on the specific Virtual Network + Function (VNF). + """ + LOG.debug(_("Neutron PLUMgrid Director: create_port() called")) + + # Port operations on PLUMgrid Director is an automatic operation + # from the VIF driver operations in Nova. + # It requires admin_state_up to be True + + port["port"]["admin_state_up"] = True + + with context.session.begin(subtransactions=True): + # Plugin DB - Port Create and Return port + port_db = super(NeutronPluginPLUMgridV2, self).create_port(context, + port) + device_id = port_db["device_id"] + if port_db["device_owner"] == "network:router_gateway": + router_db = self._get_router(context, device_id) + else: + router_db = None + + try: + LOG.debug(_("PLUMgrid Library: create_port() called")) + self._plumlib.create_port(port_db, router_db) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + # Plugin DB - Port Create and Return port + return self._port_viftype_binding(context, port_db) + + def update_port(self, context, port_id, port): + """Update Neutron port. + + Updates a PLUMgrid-based port on the specific Virtual Network + Function (VNF). + """ + LOG.debug(_("Neutron PLUMgrid Director: update_port() called")) + + with context.session.begin(subtransactions=True): + # Plugin DB - Port Create and Return port + port_db = super(NeutronPluginPLUMgridV2, self).update_port( + context, port_id, port) + device_id = port_db["device_id"] + if port_db["device_owner"] == "network:router_gateway": + router_db = self._get_router(context, device_id) + else: + router_db = None + try: + LOG.debug(_("PLUMgrid Library: create_port() called")) + self._plumlib.update_port(port_db, router_db) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + # Plugin DB - Port Update + return self._port_viftype_binding(context, port_db) + + def delete_port(self, context, port_id, l3_port_check=True): + """Delete Neutron port. + + Deletes a PLUMgrid-based port on the specific Virtual Network + Function (VNF). + """ + + LOG.debug(_("Neutron PLUMgrid Director: delete_port() called")) + + with context.session.begin(subtransactions=True): + # Plugin DB - Port Create and Return port + port_db = super(NeutronPluginPLUMgridV2, + self).get_port(context, port_id) + super(NeutronPluginPLUMgridV2, self).delete_port(context, port_id) + + if port_db["device_owner"] == "network:router_gateway": + device_id = port_db["device_id"] + router_db = self._get_router(context, device_id) + else: + router_db = None + try: + LOG.debug(_("PLUMgrid Library: delete_port() called")) + self._plumlib.delete_port(port_db, router_db) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + def get_port(self, context, id, fields=None): + with context.session.begin(subtransactions=True): + port_db = super(NeutronPluginPLUMgridV2, + self).get_port(context, id, fields) + + self._port_viftype_binding(context, port_db) + return self._fields(port_db, fields) + + def get_ports(self, context, filters=None, fields=None): + with context.session.begin(subtransactions=True): + ports_db = super(NeutronPluginPLUMgridV2, + self).get_ports(context, filters, fields) + for port_db in ports_db: + self._port_viftype_binding(context, port_db) + return [self._fields(port, fields) for port in ports_db] + + def create_subnet(self, context, subnet): + """Create Neutron subnet. + + Creates a PLUMgrid-based DHCP and NAT Virtual Network + Functions (VNFs). + """ + + LOG.debug(_("Neutron PLUMgrid Director: create_subnet() called")) + + with context.session.begin(subtransactions=True): + # Plugin DB - Subnet Create + net_db = super(NeutronPluginPLUMgridV2, self).get_network( + context, subnet['subnet']['network_id'], fields=None) + s = subnet['subnet'] + ipnet = netaddr.IPNetwork(s['cidr']) + + # PLUMgrid Director reserves the last IP address for GW + # when is not defined + if s['gateway_ip'] is attributes.ATTR_NOT_SPECIFIED: + gw_ip = str(netaddr.IPAddress(ipnet.last - 1)) + subnet['subnet']['gateway_ip'] = gw_ip + + # PLUMgrid reserves the first IP + if s['allocation_pools'] == attributes.ATTR_NOT_SPECIFIED: + allocation_pool = self._allocate_pools_for_subnet(context, s) + subnet['subnet']['allocation_pools'] = allocation_pool + + sub_db = super(NeutronPluginPLUMgridV2, self).create_subnet( + context, subnet) + + try: + LOG.debug(_("PLUMgrid Library: create_subnet() called")) + self._plumlib.create_subnet(sub_db, net_db, ipnet) + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + return sub_db + + def delete_subnet(self, context, subnet_id): + """Delete subnet core Neutron API.""" + + LOG.debug(_("Neutron PLUMgrid Director: delete_subnet() called")) + # Collecting subnet info + sub_db = self._get_subnet(context, subnet_id) + tenant_id = self._get_tenant_id_for_create(context, subnet_id) + net_id = sub_db["network_id"] + net_db = self.get_network(context, net_id) + + with context.session.begin(subtransactions=True): + # Plugin DB - Subnet Delete + super(NeutronPluginPLUMgridV2, self).delete_subnet( + context, subnet_id) + try: + LOG.debug(_("PLUMgrid Library: delete_subnet() called")) + self._plumlib.delete_subnet(tenant_id, net_db, net_id) + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + def update_subnet(self, context, subnet_id, subnet): + """Update subnet core Neutron API.""" + + LOG.debug(_("update_subnet() called")) + # Collecting subnet info + org_sub_db = self._get_subnet(context, subnet_id) + + with context.session.begin(subtransactions=True): + # Plugin DB - Subnet Update + new_sub_db = super(NeutronPluginPLUMgridV2, + self).update_subnet(context, subnet_id, subnet) + ipnet = netaddr.IPNetwork(new_sub_db['cidr']) + + try: + # PLUMgrid Server does not support updating resources yet + LOG.debug(_("PLUMgrid Library: update_network() called")) + self._plumlib.update_subnet(org_sub_db, new_sub_db, ipnet) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + return new_sub_db + + def create_router(self, context, router): + """ + Create router extension Neutron API + """ + LOG.debug(_("Neutron PLUMgrid Director: create_router() called")) + + tenant_id = self._get_tenant_id_for_create(context, router["router"]) + + with context.session.begin(subtransactions=True): + + # Create router in DB + router_db = super(NeutronPluginPLUMgridV2, + self).create_router(context, router) + # Create router on the network controller + try: + # Add Router to VND + LOG.debug(_("PLUMgrid Library: create_router() called")) + self._plumlib.create_router(tenant_id, router_db) + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + # Return created router + return router_db + + def update_router(self, context, router_id, router): + + LOG.debug(_("Neutron PLUMgrid Director: update_router() called")) + + with context.session.begin(subtransactions=True): + router_db = super(NeutronPluginPLUMgridV2, + self).update_router(context, router_id, router) + try: + LOG.debug(_("PLUMgrid Library: update_router() called")) + self._plumlib.update_router(router_db, router_id) + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + # Return updated router + return router_db + + def delete_router(self, context, router_id): + LOG.debug(_("Neutron PLUMgrid Director: delete_router() called")) + + with context.session.begin(subtransactions=True): + orig_router = self._get_router(context, router_id) + tenant_id = orig_router["tenant_id"] + + super(NeutronPluginPLUMgridV2, self).delete_router(context, + router_id) + + try: + LOG.debug(_("PLUMgrid Library: delete_router() called")) + self._plumlib.delete_router(tenant_id, router_id) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + def add_router_interface(self, context, router_id, interface_info): + + LOG.debug(_("Neutron PLUMgrid Director: " + "add_router_interface() called")) + with context.session.begin(subtransactions=True): + # Validate args + router_db = self._get_router(context, router_id) + tenant_id = router_db['tenant_id'] + + # Create interface in DB + int_router = super(NeutronPluginPLUMgridV2, + self).add_router_interface(context, + router_id, + interface_info) + port_db = self._get_port(context, int_router['port_id']) + subnet_id = port_db["fixed_ips"][0]["subnet_id"] + subnet_db = super(NeutronPluginPLUMgridV2, + self)._get_subnet(context, subnet_id) + ipnet = netaddr.IPNetwork(subnet_db['cidr']) + + # Create interface on the network controller + try: + LOG.debug(_("PLUMgrid Library: add_router_interface() called")) + self._plumlib.add_router_interface(tenant_id, router_id, + port_db, ipnet) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + return int_router + + def remove_router_interface(self, context, router_id, int_info): + + LOG.debug(_("Neutron PLUMgrid Director: " + "remove_router_interface() called")) + with context.session.begin(subtransactions=True): + # Validate args + router_db = self._get_router(context, router_id) + tenant_id = router_db['tenant_id'] + if 'port_id' in int_info: + port = self._get_port(context, int_info['port_id']) + net_id = port['network_id'] + + elif 'subnet_id' in int_info: + subnet_id = int_info['subnet_id'] + subnet = self._get_subnet(context, subnet_id) + net_id = subnet['network_id'] + + # Remove router in DB + del_int_router = super(NeutronPluginPLUMgridV2, + self).remove_router_interface(context, + router_id, + int_info) + + try: + LOG.debug(_("PLUMgrid Library: " + "remove_router_interface() called")) + self._plumlib.remove_router_interface(tenant_id, + net_id, router_id) + + except Exception: + LOG.error(ERR_MESSAGE) + raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE) + + return del_int_router + + """ + Internal PLUMgrid Fuctions + """ + + def _get_plugin_version(self): + return VERSION + + def _port_viftype_binding(self, context, port): + if self._check_view_auth(context, port, self.binding_view): + port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_IOVISOR + port[portbindings.CAPABILITIES] = { + portbindings.CAP_PORT_FILTER: + 'security-group' in self.supported_extension_aliases} + return port + + def _check_view_auth(self, context, resource, action): + return policy.check(context, action, resource) + + def _network_admin_state(self, network): + try: + if network["network"].get("admin_state_up"): + network_name = network["network"]["name"] + if network["network"]["admin_state_up"] is False: + LOG.warning(_("Network with admin_state_up=False are not " + "supported yet by this plugin. Ignoring " + "setting for network %s"), network_name) + except Exception: + err_message = _("Network Admin State Validation Falied: ") + LOG.error(err_message) + raise plum_excep.PLUMgridException(err_msg=err_message) + return network + + def _allocate_pools_for_subnet(self, context, subnet): + """Create IP allocation pools for a given subnet + + Pools are defined by the 'allocation_pools' attribute, + a list of dict objects with 'start' and 'end' keys for + defining the pool range. + Modified from Neutron DB based class + + """ + + pools = [] + # Auto allocate the pool around gateway_ip + net = netaddr.IPNetwork(subnet['cidr']) + first_ip = net.first + 2 + last_ip = net.last - 1 + gw_ip = int(netaddr.IPAddress(subnet['gateway_ip'] or net.last)) + # Use the gw_ip to find a point for splitting allocation pools + # for this subnet + split_ip = min(max(gw_ip, net.first), net.last) + if split_ip > first_ip: + pools.append({'start': str(netaddr.IPAddress(first_ip)), + 'end': str(netaddr.IPAddress(split_ip - 1))}) + if split_ip < last_ip: + pools.append({'start': str(netaddr.IPAddress(split_ip + 1)), + 'end': str(netaddr.IPAddress(last_ip))}) + # return auto-generated pools + # no need to check for their validity + return pools diff --git a/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py b/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py index f1e50c777b..69650f36c7 100644 --- a/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py +++ b/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py @@ -19,53 +19,84 @@ Test cases for Neutron PLUMgrid Plug-in """ -from mock import patch +import mock +from neutron.extensions import portbindings from neutron.manager import NeutronManager +from neutron.openstack.common import importutils +from neutron.plugins.plumgrid.plumgrid_plugin import plumgrid_plugin +from neutron.tests.unit import _test_extension_portbindings as test_bindings from neutron.tests.unit import test_db_plugin as test_plugin -class PLUMgridPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase): +PLUM_DRIVER = ('neutron.plugins.plumgrid.drivers.fake_plumlib.Plumlib') +FAKE_DIRECTOR = '1.1.1.1' +FAKE_PORT = '1234' +FAKE_TIMEOUT = '0' - _plugin_name = ('neutron.plugins.plumgrid.plumgrid_nos_plugin.' + +class PLUMgridPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase): + _plugin_name = ('neutron.plugins.plumgrid.plumgrid_plugin.' 'plumgrid_plugin.NeutronPluginPLUMgridV2') def setUp(self): - self.restHTTPConnection = patch('httplib.HTTPConnection') - self.restHTTPConnection.start() - super(PLUMgridPluginV2TestCase, self).setUp(self._plugin_name) + def mocked_plumlib_init(self): + director_plumgrid = FAKE_DIRECTOR + director_port = FAKE_PORT + timeout = FAKE_TIMEOUT + self._plumlib = importutils.import_object(PLUM_DRIVER) + self._plumlib.director_conn(director_plumgrid, + director_port, timeout) + + with mock.patch.object(plumgrid_plugin.NeutronPluginPLUMgridV2, + 'plumgrid_init', new=mocked_plumlib_init): + super(PLUMgridPluginV2TestCase, self).setUp(self._plugin_name) def tearDown(self): super(PLUMgridPluginV2TestCase, self).tearDown() - self.restHTTPConnection.stop() -class TestPlumgridPluginV2HTTPResponse(test_plugin.TestV2HTTPResponse, - PLUMgridPluginV2TestCase): +class TestPlumgridPluginNetworksV2(test_plugin.TestNetworksV2, + PLUMgridPluginV2TestCase): + pass + +class TestPlumgridV2HTTPResponse(test_plugin.TestV2HTTPResponse, + PLUMgridPluginV2TestCase): pass class TestPlumgridPluginPortsV2(test_plugin.TestPortsV2, PLUMgridPluginV2TestCase): - - pass - - -class TestPlumgridPluginNetworksV2(test_plugin.TestNetworksV2, - PLUMgridPluginV2TestCase): - - pass + def test_range_allocation(self): + self.skipTest("Plugin does not support Neutron allocation process") class TestPlumgridPluginSubnetsV2(test_plugin.TestSubnetsV2, PLUMgridPluginV2TestCase): + def test_create_subnet_default_gw_conflict_allocation_pool_returns_409( + self): + self.skipTest("Plugin does not support Neutron allocation process") - pass + def test_create_subnet_defaults(self): + self.skipTest("Plugin does not support Neutron allocation process") + + def test_create_subnet_gw_values(self): + self.skipTest("Plugin does not support Neutron allocation process") + + def test_update_subnet_gateway_in_allocation_pool_returns_409(self): + self.skipTest("Plugin does not support Neutron allocation process") + + +class TestPlumgridPluginPortBinding(PLUMgridPluginV2TestCase, + test_bindings.PortBindingsTestCase): + VIF_TYPE = portbindings.VIF_TYPE_IOVISOR + + def setUp(self): + super(TestPlumgridPluginPortBinding, self).setUp() class TestPlumgridNetworkAdminState(PLUMgridPluginV2TestCase): - def test_network_admin_state(self): name = 'network_test' admin_status_up = False @@ -75,3 +106,18 @@ class TestPlumgridNetworkAdminState(PLUMgridPluginV2TestCase): 'tenant_id': tenant_id}} plugin = NeutronManager.get_plugin() self.assertEqual(plugin._network_admin_state(network), network) + + +class TestPlumgridAllocationPool(PLUMgridPluginV2TestCase): + def test_allocate_pools_for_subnet(self): + cidr = '10.0.0.0/24' + gateway_ip = '10.0.0.254' + subnet = {'gateway_ip': gateway_ip, + 'cidr': cidr, + 'ip_version': 4} + allocation_pool = [{"start": '10.0.0.2', + "end": '10.0.0.253'}] + context = None + plugin = NeutronManager.get_plugin() + pool = plugin._allocate_pools_for_subnet(context, subnet) + self.assertEqual(allocation_pool, pool)