]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
PLUMgrid plugin v2
authorEdgar Magana <emagana@gmail.com>
Wed, 10 Jul 2013 22:11:16 +0000 (15:11 -0700)
committerEdgar Magana <emagana@gmail.com>
Wed, 31 Jul 2013 21:42:17 +0000 (14:42 -0700)
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

14 files changed:
etc/neutron/plugins/plumgrid/plumgrid.ini
neutron/extensions/portbindings.py
neutron/plugins/plumgrid/README
neutron/plugins/plumgrid/common/exceptions.py
neutron/plugins/plumgrid/drivers/__init__.py [new file with mode: 0644]
neutron/plugins/plumgrid/drivers/fake_plumlib.py [new file with mode: 0644]
neutron/plugins/plumgrid/drivers/plumlib.py [new file with mode: 0644]
neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_nos_snippets.py [deleted file]
neutron/plugins/plumgrid/plumgrid_nos_plugin/plumgrid_plugin.py [deleted file]
neutron/plugins/plumgrid/plumgrid_nos_plugin/rest_connection.py [deleted file]
neutron/plugins/plumgrid/plumgrid_plugin/__init__.py [moved from neutron/plugins/plumgrid/plumgrid_nos_plugin/__init__.py with 100% similarity]
neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py [moved from neutron/plugins/plumgrid/plumgrid_nos_plugin/plugin_ver.py with 97% similarity]
neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py [new file with mode: 0644]
neutron/tests/unit/plumgrid/test_plumgrid_plugin.py

index 6c3f525db4b75889a39605a9337475f9dd5d83b6..2addf617fd83b6cc85026d33b85178e83c48f97d 100644 (file)
@@ -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-ip-address>
-# nos_server_port=<nos-port>
-# Authentification parameters for the NOS server.
+[PLUMgridDirector]
+# This line should be pointing to the PLUMgrid Director,
+# for the PLUMgrid platform.
+# director_server=<director-ip-address>
+# director_server_port=<director-port>
+# Authentification parameters for the Director.
 # These are the admin credentials to manage and control
-# the NOS server.
-# username=<nos-admin-username>
-# password=<nos-admin-password>
+# the PLUMgrid Director server.
+# username=<director-admin-username>
+# password=<director-admin-password>
 # servertimeout=5
-# Name of the network topology to be deployed by NOS
-# topologyname=<nos-topology-name>
index fa442d60023bfe013b99841c46e0a65fb4c19154..e09d04642dad800fbb3f3d9022c4bc50e1be9491 100644 (file)
@@ -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'
index df8eb9f4e4818d4e78f66fabf8948c7df8a753b7..e7118307d3e8f236dc57b651ed4bde3bc73dd508 100644 (file)
@@ -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
index f54d55308e9ca940659f8839ca81c25ae449976b..214978639a44c549f9af46f1032793429e140210 100644 (file)
@@ -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 (file)
index 0000000..09cf65a
--- /dev/null
@@ -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 (file)
index 0000000..20dc8c3
--- /dev/null
@@ -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 (file)
index 0000000..e9ea6c5
--- /dev/null
@@ -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 (file)
index 6d6b221..0000000
+++ /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 (file)
index eb5f263..0000000
+++ /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 (file)
index 8e79b33..0000000
+++ /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
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 d9286de9cf9ed19f815d1540b966f19fe00ef715..5a47438c1c23f2c68e907453b94960abb6376e6a 100644 (file)
@@ -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 (file)
index 0000000..14fff1c
--- /dev/null
@@ -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
index f1e50c777bf1cae4fce2749dde419379a295ee46..69650f36c7b2f1bb1e3ea1d0192c3760c6e286a8 100644 (file)
 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):
+    def test_range_allocation(self):
+        self.skipTest("Plugin does not support Neutron allocation process")
 
-    pass
 
+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")
 
-class TestPlumgridPluginNetworksV2(test_plugin.TestNetworksV2,
-                                   PLUMgridPluginV2TestCase):
+    def test_create_subnet_defaults(self):
+        self.skipTest("Plugin does not support Neutron allocation process")
 
-    pass
+    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 TestPlumgridPluginSubnetsV2(test_plugin.TestSubnetsV2,
-                                  PLUMgridPluginV2TestCase):
 
-    pass
+class TestPlumgridPluginPortBinding(PLUMgridPluginV2TestCase,
+                                    test_bindings.PortBindingsTestCase):
+    VIF_TYPE = portbindings.VIF_TYPE_IOVISOR
 
+    def setUp(self):
+        super(TestPlumgridPluginPortBinding, self).setUp()
 
-class TestPlumgridNetworkAdminState(PLUMgridPluginV2TestCase):
 
+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)