From 4530377c6024b188d57efee91dd4cc3feadef6af Mon Sep 17 00:00:00 2001
From: Adit Sarfaty <asarfaty@vmware.com>
Date: Thu, 18 Jan 2018 13:28:53 +0200
Subject: [PATCH] TVD: FWaaS plugins

Adding FWaaS v1/v2 plugins to be used with the TVD core plugin.
The plugins will make sure to separate the v/t returned lists
using the same solution that was introduced for the LBass, now as a
general class decorator.

Change-Id: I5f01b8cf093d5ef3b340dce2d12fc41031dd12e9
---
 doc/source/devstack.rst                       | 13 +++-
 setup.cfg                                     |  4 +-
 vmware_nsx/plugins/nsx/utils.py               | 42 ++++++++++++
 vmware_nsx/services/fwaas/nsx_tv/plugin_v1.py | 29 ++++++++
 vmware_nsx/services/fwaas/nsx_tv/plugin_v2.py | 29 ++++++++
 vmware_nsx/services/lbaas/nsx/plugin.py       | 67 ++++---------------
 6 files changed, 126 insertions(+), 58 deletions(-)
 create mode 100644 vmware_nsx/services/fwaas/nsx_tv/plugin_v1.py
 create mode 100644 vmware_nsx/services/fwaas/nsx_tv/plugin_v2.py

diff --git a/doc/source/devstack.rst b/doc/source/devstack.rst
index a54b5ddc3c..b119a83340 100644
--- a/doc/source/devstack.rst
+++ b/doc/source/devstack.rst
@@ -232,12 +232,17 @@ Add lbaas repo as an external repository and configure following flags in ``loca
     [[local]|[localrc]]
     enable_plugin neutron-lbaas https://git.openstack.org/openstack/neutron-lbaas
     enable_service q-lbaasv2
+    Q_SERVICE_PLUGIN_CLASSES=vmware_nsxtvd_lbaasv2
 
 Configure the service provider::
     [[post-config|$NEUTRON_LBAAS_CONF]]
     [service_providers]
     service_provider = LOADBALANCERV2:VMWareEdge:neutron_lbaas.drivers.vmware.edge_driver_v2.EdgeLoadBalancerDriverV2:default
 
+    [[post-config|$NEUTRON_CONF]]
+    [DEFAULT]
+    api_extensions_path = $DEST/neutron-lbaas/neutron_lbaas/extensions
+
 FWaaS (V1) Driver:
 ~~~~~~~~~~~~~
 
@@ -246,12 +251,14 @@ Add neutron-fwaas repo as an external repository and configure following flags i
     [[local|localrc]]
     enable_plugin neutron-fwaas https://git.openstack.org/openstack/neutron-fwaas
     ENABLED_SERVICES+=,q-fwaas
-    Q_SERVICE_PLUGIN_CLASSES=neutron_fwaas.services.firewall.fwaas_plugin.FirewallPlugin
+    Q_SERVICE_PLUGIN_CLASSES=vmware_nsxtvd_fwaasv1
 
     [[post-config|$NEUTRON_CONF]]
     [fwaas]
     enabled = True
     driver = vmware_nsxtvd_edge_v1
+    [DEFAULT]
+    api_extensions_path = $DEST/neutron-fwaas/neutron_fwaas/extensions
 
 
 FWaaS (V2) Driver
@@ -262,12 +269,14 @@ Add neutron-fwaas repo as an external repository and configure following flags i
     [[local|localrc]]
     enable_plugin neutron-fwaas https://git.openstack.org/openstack/neutron-fwaas
     ENABLED_SERVICES+=,q-fwaas-v2
-    Q_SERVICE_PLUGIN_CLASSES=neutron_fwaas.services.firewall.fwaas_plugin_v2.FirewallPluginV2
+    Q_SERVICE_PLUGIN_CLASSES=vmware_nsxtvd_fwaasv2
 
     [[post-config|$NEUTRON_CONF]]
     [fwaas]
     enabled = True
     driver = vmware_nsxtvd_edge_v2
+    [DEFAULT]
+    api_extensions_path = $DEST/neutron-fwaas/neutron_fwaas/extensions
 
 L2GW Driver
 ~~~~~~~~~~~
diff --git a/setup.cfg b/setup.cfg
index ba5bcbcdf9..8d5322c101 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -43,7 +43,9 @@ firewall_drivers =
     vmware_nsxtvd_edge_v2 = vmware_nsx.services.fwaas.nsx_tv.edge_fwaas_driver_v2:EdgeFwaasTVDriverV2
 neutron.service_plugins =
     vmware_nsxv_qos = vmware_nsx.services.qos.nsx_v.plugin:NsxVQosPlugin
-    vmware_nsxtvd_lbaasv2 = vmware_nsx.services.lbaas.nsx.plugin:LoadBalancerTVDPluginv2
+    vmware_nsxtvd_lbaasv2 = vmware_nsx.services.lbaas.nsx.plugin:LoadBalancerTVPluginV2
+    vmware_nsxtvd_fwaasv1 = vmware_nsx.services.fwaas.nsx_tv.plugin_v1:FwaasTVPluginV1
+    vmware_nsxtvd_fwaasv2 = vmware_nsx.services.fwaas.nsx_tv.plugin_v2:FwaasTVPluginV2
 neutron.qos.notification_drivers =
     vmware_nsxv3_message_queue = vmware_nsx.services.qos.nsx_v3.message_queue:NsxV3QosNotificationDriver
 neutron.ipam_drivers =
diff --git a/vmware_nsx/plugins/nsx/utils.py b/vmware_nsx/plugins/nsx/utils.py
index a422692a31..3392385c60 100644
--- a/vmware_nsx/plugins/nsx/utils.py
+++ b/vmware_nsx/plugins/nsx/utils.py
@@ -16,8 +16,11 @@
 from oslo_config import cfg
 
 from neutron_lib import context as n_context
+from neutron_lib import exceptions
 from neutron_lib.plugins import directory
 
+from vmware_nsx.db import db as nsx_db
+
 
 def is_tvd_core_plugin():
     core_plugin = cfg.CONF.core_plugin
@@ -36,3 +39,42 @@ def get_tvd_plugin_type_for_project(project_id, context=None):
         context = n_context.get_admin_context()
     core_plugin = directory.get_plugin()
     return core_plugin.get_plugin_type_from_project(context, project_id)
+
+
+def filter_plugins(cls):
+    """
+    Class decorator to separate the results of each of the given methods
+    by plugin
+    """
+    def get_project_mapping(context, project_id):
+        """Return the plugin associated with this project"""
+        mapping = nsx_db.get_project_plugin_mapping(
+                context.session, project_id)
+        if mapping:
+            return mapping['plugin']
+        else:
+            raise exceptions.ObjectNotFound(id=project_id)
+
+    def add_separate_plugin_hook(name):
+        orig_method = getattr(cls, name, None)
+
+        def filter_results_by_plugin(self, context, filters=None, fields=None):
+            """Run the original get-list method, and filter the results
+            by the project id of the context
+            """
+            req_p = get_project_mapping(context, context.project_id)
+            entries = orig_method(self, context, filters=filters,
+                                  fields=fields)
+            for entry in entries[:]:
+                p = get_project_mapping(context, entry['tenant_id'])
+                if p != req_p:
+                    entries.remove(entry)
+
+            return entries
+
+        setattr(cls, name, filter_results_by_plugin)
+
+    for method in cls.methods_to_separate:
+        add_separate_plugin_hook(method)
+
+    return cls
diff --git a/vmware_nsx/services/fwaas/nsx_tv/plugin_v1.py b/vmware_nsx/services/fwaas/nsx_tv/plugin_v1.py
new file mode 100644
index 0000000000..bdb0463517
--- /dev/null
+++ b/vmware_nsx/services/fwaas/nsx_tv/plugin_v1.py
@@ -0,0 +1,29 @@
+# Copyright 2018 VMware, Inc.
+# All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from neutron_fwaas.services.firewall import fwaas_plugin
+
+from vmware_nsx.plugins.nsx import utils as tvd_utils
+
+
+@tvd_utils.filter_plugins
+class FwaasTVPluginV1(fwaas_plugin.FirewallPlugin):
+    """NSX-TV plugin for Firewall As A Service - V1.
+
+    This plugin adds separation between T/V instances
+    """
+    methods_to_separate = ['get_firewall',
+                           'get_firewall_policies',
+                           'get_firewall_rules']
diff --git a/vmware_nsx/services/fwaas/nsx_tv/plugin_v2.py b/vmware_nsx/services/fwaas/nsx_tv/plugin_v2.py
new file mode 100644
index 0000000000..9ec45d1f5e
--- /dev/null
+++ b/vmware_nsx/services/fwaas/nsx_tv/plugin_v2.py
@@ -0,0 +1,29 @@
+# Copyright 2018 VMware, Inc.
+# All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from neutron_fwaas.services.firewall import fwaas_plugin_v2
+
+from vmware_nsx.plugins.nsx import utils as tvd_utils
+
+
+@tvd_utils.filter_plugins
+class FwaasTVPluginV2(fwaas_plugin_v2.FirewallPluginV2):
+    """NSX-TV plugin for Firewall As A Service - V2.
+
+    This plugin adds separation between T/V instances
+    """
+    methods_to_separate = ['get_firewall_groups',
+                           'get_firewall_policies',
+                           'get_firewall_rules']
diff --git a/vmware_nsx/services/lbaas/nsx/plugin.py b/vmware_nsx/services/lbaas/nsx/plugin.py
index 4a8ad00eb1..60ac4434bb 100644
--- a/vmware_nsx/services/lbaas/nsx/plugin.py
+++ b/vmware_nsx/services/lbaas/nsx/plugin.py
@@ -12,63 +12,20 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-from neutron_lib import exceptions
 
 from neutron_lbaas.services.loadbalancer import plugin
-from vmware_nsx.db import db as nsx_db
+
+from vmware_nsx.plugins.nsx import utils as tvd_utils
 
 
-class LoadBalancerTVDPluginv2(plugin.LoadBalancerPluginv2):
+@tvd_utils.filter_plugins
+class LoadBalancerTVPluginV2(plugin.LoadBalancerPluginv2):
+    """NSX-TV plugin for LBaaS V2.
 
-    def _get_project_mapping(self, context, filters):
-        project_id = context.project_id
-        if filters:
-            if filters.get('tenant_id'):
-                project_id = filters.get('tenant_id')
-            elif filters.get('project_id'):
-                project_id = filters.get('project_id')
-            # If multiple are requested then we revert to
-            # the context's project id
-            if isinstance(project_id, list):
-                project_id = context.project_id
-        mapping = nsx_db.get_project_plugin_mapping(
-                context.session, project_id)
-        if mapping:
-            return mapping['plugin']
-        else:
-            raise exceptions.ObjectNotFound(id=project_id)
-
-    def _filter_entries(self, method, context, filters=None, fields=None):
-        req_p = self._get_project_mapping(context, filters)
-        entries = method(context, filters=filters, fields=fields)
-        for entry in entries[:]:
-            p = self._get_project_mapping(context,
-                                          entry['tenant_id'])
-            if p != req_p:
-                entries.remove(entry)
-        return entries
-
-    def get_loadbalancers(self, context, filters=None, fields=None):
-        return self._filter_entries(
-            super(LoadBalancerTVDPluginv2, self).get_loadbalancers,
-            context, filters=filters, fields=fields)
-
-    def get_listeners(self, context, filters=None, fields=None):
-        return self._filter_entries(
-            super(LoadBalancerTVDPluginv2, self).get_listeners,
-            context, filters=filters, fields=fields)
-
-    def get_pools(self, context, filters=None, fields=None):
-        return self._filter_entries(
-            super(LoadBalancerTVDPluginv2, self).get_pools,
-            context, filters=filters, fields=fields)
-
-    def get_healthmonitors(self, context, filters=None, fields=None):
-        return self._filter_entries(
-            super(LoadBalancerTVDPluginv2, self).get_healthmonitors,
-            context, filters=filters, fields=fields)
-
-    def get_l7policies(self, context, filters=None, fields=None):
-        return self._filter_entries(
-            super(LoadBalancerTVDPluginv2, self).get_l7policies,
-            context, filters=filters, fields=fields)
+    This plugin adds separation between T/V instances
+    """
+    methods_to_separate = ['get_loadbalancers',
+                           'get_listeners',
+                           'get_pools',
+                           'get_healthmonitors',
+                           'get_l7policies']