]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Support for NVP advanced FwaaS service
authorberlin <linb@vmware.com>
Thu, 22 Aug 2013 07:58:58 +0000 (15:58 +0800)
committerKaiwei Fan <fank@vmware.com>
Tue, 17 Sep 2013 17:18:22 +0000 (10:18 -0700)
The patch adds advanced FWaaS service support for NVP with
VCNS:
        * NVP FWaaS is an advanced Service of NVP depending on NVP
          advanced service router
            - Once an advanced router id created, one corresponding
              vshield edge will be deployed, and then we can configure
              FW service on the vshield edge
        * NVP FWaaS service plugin still uses FWaaS DB service logic,
          while finally calling vShield Edge to support FWaaS service
            - When firewall object is created, we will attach the
              object to the advanced router with routedserviceinsertion_db
              service
        * on driver part, the driver will first convert the object
          to VSM known object input, and then send a synchronous JSON
          calling to VSM, and receive the result

Implements: blueprint nvp-fwaas-plugin
Change-Id: Id43af8821f5c553356e3cc870993eef99ef7def3

22 files changed:
neutron/db/migration/alembic_migrations/versions/3ed8f075e38a_nvp_fwaas_plugin.py [new file with mode: 0755]
neutron/db/routedserviceinsertion_db.py
neutron/extensions/routedserviceinsertion.py
neutron/plugins/nicira/NeutronServicePlugin.py
neutron/plugins/nicira/common/exceptions.py
neutron/plugins/nicira/dbexts/vcns_db.py
neutron/plugins/nicira/dbexts/vcns_models.py
neutron/plugins/nicira/vshield/__init__.py
neutron/plugins/nicira/vshield/common/exceptions.py
neutron/plugins/nicira/vshield/edge_firewall_driver.py [new file with mode: 0644]
neutron/plugins/nicira/vshield/vcns.py
neutron/plugins/nicira/vshield/vcns_driver.py
neutron/tests/unit/db/firewall/test_db_firewall.py
neutron/tests/unit/nicira/__init__.py
neutron/tests/unit/nicira/test_edge_router.py
neutron/tests/unit/nicira/test_fwaas_plugin.py [new file with mode: 0644]
neutron/tests/unit/nicira/test_nicira_plugin.py
neutron/tests/unit/nicira/vshield/common/__init__.py [deleted file]
neutron/tests/unit/nicira/vshield/fake_vcns.py
neutron/tests/unit/nicira/vshield/test_firewall_driver.py [new file with mode: 0644]
neutron/tests/unit/test_l3_plugin.py
neutron/tests/unit/test_routerserviceinsertion.py

diff --git a/neutron/db/migration/alembic_migrations/versions/3ed8f075e38a_nvp_fwaas_plugin.py b/neutron/db/migration/alembic_migrations/versions/3ed8f075e38a_nvp_fwaas_plugin.py
new file mode 100755 (executable)
index 0000000..19c08a7
--- /dev/null
@@ -0,0 +1,60 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 OpenStack Foundation
+#
+#    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.
+#
+
+"""nvp fwaas plugin
+
+Revision ID: 3ed8f075e38a
+Revises: 338d7508968c
+Create Date: 2013-09-13 19:14:25.509033
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '3ed8f075e38a'
+down_revision = '338d7508968c'
+
+# Change to ['*'] if this migration applies to all plugins
+
+migration_for_plugins = [
+    'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin'
+]
+
+from alembic import op
+import sqlalchemy as sa
+
+from neutron.db import migration
+
+
+def upgrade(active_plugins=None, options=None):
+    if not migration.should_run(active_plugins, migration_for_plugins):
+        return
+
+    op.create_table(
+        'vcns_firewall_rule_bindings',
+        sa.Column('rule_id', sa.String(length=36), nullable=False),
+        sa.Column('edge_id', sa.String(length=36), nullable=False),
+        sa.Column('rule_vseid', sa.String(length=36), nullable=True),
+        sa.ForeignKeyConstraint(['rule_id'], ['firewall_rules.id'], ),
+        sa.PrimaryKeyConstraint('rule_id', 'edge_id')
+    )
+
+
+def downgrade(active_plugins=None, options=None):
+    if not migration.should_run(active_plugins, migration_for_plugins):
+        return
+
+    op.drop_table('vcns_firewall_rule_bindings')
index e8c7af14475061061ff14f48ccbbe580941ce2bb..12f32e1e761bf986d4a2c5e55556ad121c97069e 100644 (file)
@@ -65,13 +65,34 @@ class RoutedServiceInsertionDbMixin(object):
             context, resource['resource_id'], model)
         resource[rsi.ROUTER_ID] = binding['router_id']
 
-    def _get_resource_router_id_binding(self, context, resource_id, model):
+    def _get_resource_router_id_binding(self, context, model,
+                                        resource_id=None,
+                                        router_id=None):
         query = self._model_query(context, ServiceRouterBinding)
         query = query.filter(
-            ServiceRouterBinding.resource_id == resource_id,
             ServiceRouterBinding.resource_type == model.__tablename__)
+        if resource_id:
+            query = query.filter(
+                ServiceRouterBinding.resource_id == resource_id)
+        if router_id:
+            query = query.filter(
+                ServiceRouterBinding.router_id == router_id)
         return query.first()
 
+    def _get_resource_router_id_bindings(self, context, model,
+                                         resource_ids=None,
+                                         router_ids=None):
+        query = self._model_query(context, ServiceRouterBinding)
+        query = query.filter(
+            ServiceRouterBinding.resource_type == model.__tablename__)
+        if resource_ids:
+            query = query.filter(
+                ServiceRouterBinding.resource_id.in_(resource_ids))
+        if router_ids:
+            query = query.filter(
+                ServiceRouterBinding.router_id.in_(router_ids))
+        return query.all()
+
     def _make_resource_router_id_dict(self, resource_router_binding, model,
                                       fields=None):
         resource = {'resource_id': resource_router_binding['resource_id'],
@@ -82,6 +103,6 @@ class RoutedServiceInsertionDbMixin(object):
     def _delete_resource_router_id_binding(self, context, resource_id, model):
         with context.session.begin(subtransactions=True):
             binding = self._get_resource_router_id_binding(
-                context, resource_id, model)
+                context, model, resource_id=resource_id)
             if binding:
                 context.session.delete(binding)
index b3962534748238c3a65775ab9bb5ebd1b07bf7be..fc84c016674b6f728a82ee8652018a6e1d6e1965 100644 (file)
@@ -34,6 +34,12 @@ EXTENDED_ATTRIBUTES_2_0 = {
                     'validate': {'type:uuid_or_none': None},
                     'default': None, 'is_visible': True},
     },
+
+    'firewalls': {
+        ROUTER_ID: {'allow_post': True, 'allow_put': False,
+                    'validate': {'type:uuid_or_none': None},
+                    'default': None, 'is_visible': True},
+    }
 }
 
 
index 211be7132390ddc9b8bf5226363fc5dabe97fc93..7161341ed5b90cacf552cb7505f10a30e60c069d 100644 (file)
@@ -1,4 +1,4 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
+    # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
 # Copyright 2013 VMware, Inc.
 # All Rights Reserved
 
 import netaddr
 from oslo.config import cfg
-from sqlalchemy.orm import exc as sa_exc
 
 from neutron.common import exceptions as q_exc
+from neutron.db.firewall import firewall_db
 from neutron.db import l3_db
+from neutron.db import routedserviceinsertion_db as rsi_db
+from neutron.extensions import firewall as fw_ext
 from neutron.openstack.common import log as logging
 from neutron.plugins.common import constants as service_constants
 from neutron.plugins.nicira.common import config  # noqa
+from neutron.plugins.nicira.common import exceptions as nvp_exc
 from neutron.plugins.nicira.dbexts import servicerouter as sr_db
 from neutron.plugins.nicira.dbexts import vcns_db
 from neutron.plugins.nicira.dbexts import vcns_models
@@ -38,6 +41,7 @@ from neutron.plugins.nicira.vshield.common.constants import RouterStatus
 from neutron.plugins.nicira.vshield.common import exceptions
 from neutron.plugins.nicira.vshield.tasks.constants import TaskStatus
 from neutron.plugins.nicira.vshield import vcns_driver
+from sqlalchemy.orm import exc as sa_exc
 
 LOG = logging.getLogger(__name__)
 
@@ -66,11 +70,15 @@ ROUTER_STATUS_LEVEL = {
 
 
 class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
-                        NeutronPlugin.NvpPluginV2):
-
+                        NeutronPlugin.NvpPluginV2,
+                        rsi_db.RoutedServiceInsertionDbMixin,
+                        firewall_db.Firewall_db_mixin,
+                        ):
     supported_extension_aliases = (
         NeutronPlugin.NvpPluginV2.supported_extension_aliases + [
-            'service-router'
+            "service-router",
+            "routed-service-insertion",
+            "fwaas"
         ])
 
     def __init__(self):
@@ -652,7 +660,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
             router = self._get_router(context, router_id)
             if router.enable_snat:
                 self._update_nat_rules(context, router)
-            # TODO(fank): do rollback if error, or have a dedicated thread
+            # TODO(fank): do rollback on error, or have a dedicated thread
             # do sync work (rollback, re-configure, or make router down)
             self._vcns_update_static_routes(context, router=router)
         return info
@@ -664,7 +672,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
             router = self._get_router(context, router_id)
             if router.enable_snat:
                 self._update_nat_rules(context, router)
-            # TODO(fank): do rollback if error, or have a dedicated thread
+            # TODO(fank): do rollback on error, or have a dedicated thread
             # do sync work (rollback, re-configure, or make router down)
             self._vcns_update_static_routes(context, router=router)
         return info
@@ -675,7 +683,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
         router_id = fip.get('router_id')
         if router_id and self._is_advanced_service_router(context, router_id):
             router = self._get_router(context, router_id)
-            # TODO(fank): do rollback if error, or have a dedicated thread
+            # TODO(fank): do rollback on error, or have a dedicated thread
             # do sync work (rollback, re-configure, or make router down)
             self._update_interface(context, router)
             self._update_nat_rules(context, router)
@@ -687,7 +695,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
         router_id = fip.get('router_id')
         if router_id and self._is_advanced_service_router(context, router_id):
             router = self._get_router(context, router_id)
-            # TODO(fank): do rollback if error, or have a dedicated thread
+            # TODO(fank): do rollback on error, or have a dedicated thread
             # do sync work (rollback, re-configure, or make router down)
             self._update_interface(context, router)
             self._update_nat_rules(context, router)
@@ -701,7 +709,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
         super(NvpAdvancedPlugin, self).delete_floatingip(context, id)
         if router_id and self._is_advanced_service_router(context, router_id):
             router = self._get_router(context, router_id)
-            # TODO(fank): do rollback if error, or have a dedicated thread
+            # TODO(fank): do rollback on error, or have a dedicated thread
             # do sync work (rollback, re-configure, or make router down)
             self._update_interface(context, router)
             self._update_nat_rules(context, router)
@@ -717,16 +725,291 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
                                                                 port_id)
         if router_id and self._is_advanced_service_router(context, router_id):
             router = self._get_router(context, router_id)
-            # TODO(fank): do rollback if error, or have a dedicated thread
+            # TODO(fank): do rollback on error, or have a dedicated thread
             # do sync work (rollback, re-configure, or make router down)
             self._update_interface(context, router)
             self._update_nat_rules(context, router)
 
+    #
+    # FWaaS plugin implementation
+    #
+    def _firewall_set_status(
+        self, context, firewall_id, status, firewall=None):
+        with context.session.begin(subtransactions=True):
+            fw_db = self._get_firewall(context, firewall_id)
+            if status == service_constants.PENDING_UPDATE and (
+                fw_db.status == service_constants.PENDING_DELETE):
+                    raise fw_ext.FirewallInPendingState(
+                        firewall_id=firewall_id, pending_state=status)
+            else:
+                fw_db.status = status
+                if firewall:
+                    firewall['status'] = status
+
+    def _ensure_firewall_update_allowed(self, context, firewall_id):
+        fwall = self.get_firewall(context, firewall_id)
+        if fwall['status'] in [service_constants.PENDING_CREATE,
+                               service_constants.PENDING_UPDATE,
+                               service_constants.PENDING_DELETE]:
+            raise fw_ext.FirewallInPendingState(firewall_id=firewall_id,
+                                                pending_state=fwall['status'])
+
+    def _ensure_firewall_policy_update_allowed(
+        self, context, firewall_policy_id):
+        firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
+        for firewall_id in firewall_policy.get('firewall_list', []):
+            self._ensure_firewall_update_allowed(context, firewall_id)
+
+    def _ensure_update_or_delete_firewall_rule(
+        self, context, firewall_rule_id):
+        fw_rule = self.get_firewall_rule(context, firewall_rule_id)
+        if fw_rule.get('firewall_policy_id'):
+            self._ensure_firewall_policy_update_allowed(
+                context, fw_rule['firewall_policy_id'])
+
+    def _make_firewall_rule_list_by_policy_id(self, context, fw_policy_id):
+        if not fw_policy_id:
+            return None
+        firewall_policy_db = self._get_firewall_policy(context, fw_policy_id)
+        return [
+            self._make_firewall_rule_dict(fw_rule_db)
+            for fw_rule_db in firewall_policy_db['firewall_rules']
+        ]
+
+    def _get_edge_id_by_vcns_edge_binding(self, context,
+                                          router_id):
+        #Get vcns_router_binding mapping between router and edge
+        router_binding = vcns_db.get_vcns_router_binding(
+            context.session, router_id)
+        return router_binding.edge_id
+
+    def _get_firewall_list_from_firewall_policy(self, context, policy_id):
+        firewall_policy_db = self._get_firewall_policy(context, policy_id)
+        return [
+            self._make_firewall_dict(fw_db)
+            for fw_db in firewall_policy_db['firewalls']
+        ]
+
+    def _get_firewall_list_from_firewall_rule(self, context, rule_id):
+        rule = self._get_firewall_rule(context, rule_id)
+        if not rule.firewall_policy_id:
+            # The firewall rule is not associated with firewall policy yet
+            return None
+
+        return self._get_firewall_list_from_firewall_policy(
+            context, rule.firewall_policy_id)
+
+    def _vcns_update_firewall(self, context, fw, router_id=None, **kwargs):
+        edge_id = kwargs.get('edge_id')
+        if not edge_id:
+            edge_id = self._get_edge_id_by_vcns_edge_binding(
+                context, router_id)
+        firewall_rule_list = kwargs.get('firewall_rule_list')
+        if not firewall_rule_list:
+            firewall_rule_list = self._make_firewall_rule_list_by_policy_id(
+                context, fw['firewall_policy_id'])
+        fw_with_rules = fw
+        fw_with_rules['firewall_rule_list'] = firewall_rule_list
+        try:
+            self.vcns_driver.update_firewall(context, edge_id, fw_with_rules)
+        except exceptions.VcnsApiException as e:
+            self._firewall_set_status(
+                context, fw['id'], service_constants.ERROR)
+            msg = (_("Failed to create firewall on vShield Edge "
+                     "bound on router %s") % router_id)
+            LOG.exception(msg)
+            raise e
 
-class VcnsCallbacks(object):
-    """Edge callback implementation
+        except exceptions.BadRequest as e:
+            self._firewall_set_status(
+                context, fw['id'], service_constants.ERROR)
+            LOG.exception(_("Bad Firewall request Input"))
+            raise e
 
-    Callback functions for asynchronous tasks
+    def _vcns_delete_firewall(self, context, router_id=None, **kwargs):
+        edge_id = kwargs.get('edge_id')
+        if not edge_id:
+            edge_id = self._get_edge_id_by_vcns_edge_binding(
+                context, router_id)
+        #TODO(linb):do rollback on error
+        self.vcns_driver.delete_firewall(context, edge_id)
+
+    def create_firewall(self, context, firewall):
+        LOG.debug(_("create_firewall() called"))
+        router_id = firewall['firewall'].get(vcns_const.ROUTER_ID)
+        if not router_id:
+            msg = _("router_id is not provided!")
+            LOG.error(msg)
+            raise q_exc.BadRequest(resource='router', msg=msg)
+        if not self._is_advanced_service_router(context, router_id):
+            msg = _("router_id:%s is not an advanced router!") % router_id
+            LOG.error(msg)
+            raise q_exc.BadRequest(resource='router', msg=msg)
+        if self._get_resource_router_id_binding(
+            context, firewall_db.Firewall, router_id=router_id):
+            msg = _("A firewall is already associated with the router")
+            LOG.error(msg)
+            raise nvp_exc.NvpServiceOverQuota(
+                overs='firewall', err_msg=msg)
+
+        fw = super(NvpAdvancedPlugin, self).create_firewall(context, firewall)
+        #Add router service insertion binding with firewall object
+        res = {
+            'id': fw['id'],
+            'router_id': router_id
+        }
+        self._process_create_resource_router_id(
+            context, res, firewall_db.Firewall)
+        #Since there is only one firewall per edge,
+        #here would be bulk configureation operation on firewall
+        self._vcns_update_firewall(context, fw, router_id)
+        self._firewall_set_status(
+            context, fw['id'], service_constants.ACTIVE, fw)
+        return fw
+
+    def update_firewall(self, context, id, firewall):
+        LOG.debug(_("update_firewall() called"))
+        self._ensure_firewall_update_allowed(context, id)
+        rule_list_pre = self._make_firewall_rule_list_by_policy_id(
+            context,
+            self.get_firewall(context, id)['firewall_policy_id'])
+        firewall['firewall']['status'] = service_constants.PENDING_UPDATE
+        fw = super(NvpAdvancedPlugin, self).update_firewall(
+            context, id, firewall)
+        rule_list_new = self._make_firewall_rule_list_by_policy_id(
+            context, fw['firewall_policy_id'])
+        if rule_list_pre == rule_list_new:
+            self._firewall_set_status(
+                context, fw['id'], service_constants.ACTIVE, fw)
+            return fw
+        else:
+            service_router_binding = self._get_resource_router_id_binding(
+                context, firewall_db.Firewall, resource_id=id)
+            self._vcns_update_firewall(
+                context, fw, service_router_binding.router_id)
+            self._firewall_set_status(
+                context, fw['id'], service_constants.ACTIVE, fw)
+            return fw
+
+    def delete_firewall(self, context, id):
+        LOG.debug(_("delete_firewall() called"))
+        self._firewall_set_status(
+            context, id, service_constants.PENDING_DELETE)
+        service_router_binding = self._get_resource_router_id_binding(
+            context, firewall_db.Firewall, resource_id=id)
+        self._vcns_delete_firewall(context, service_router_binding.router_id)
+        super(NvpAdvancedPlugin, self).delete_firewall(context, id)
+        self._delete_resource_router_id_binding(
+            context, id, firewall_db.Firewall)
+
+    def update_firewall_rule(self, context, id, firewall_rule):
+        LOG.debug(_("update_firewall_rule() called"))
+        self._ensure_update_or_delete_firewall_rule(context, id)
+        fwr_pre = self.get_firewall_rule(context, id)
+        fwr = super(NvpAdvancedPlugin, self).update_firewall_rule(
+            context, id, firewall_rule)
+        if fwr_pre == fwr:
+            return fwr
+
+        # check if this rule is associated with firewall
+        fw_list = self._get_firewall_list_from_firewall_rule(context, id)
+        if not fw_list:
+            return fwr
+
+        for fw in fw_list:
+            # get router service insertion binding with firewall id
+            service_router_binding = self._get_resource_router_id_binding(
+                context, firewall_db.Firewall, resource_id=fw['id'])
+            edge_id = self._get_edge_id_by_vcns_edge_binding(
+                context, service_router_binding.router_id)
+
+            #TODO(linb): do rollback on error
+            self.vcns_driver.update_firewall_rule(context, id, edge_id, fwr)
+
+        return fwr
+
+    def update_firewall_policy(self, context, id, firewall_policy):
+        LOG.debug(_("update_firewall_policy() called"))
+        self._ensure_firewall_policy_update_allowed(context, id)
+        firewall_rules_pre = self._make_firewall_rule_list_by_policy_id(
+            context, id)
+        fwp = super(NvpAdvancedPlugin, self).update_firewall_policy(
+            context, id, firewall_policy)
+        firewall_rules = self._make_firewall_rule_list_by_policy_id(
+            context, id)
+        if firewall_rules_pre == firewall_rules:
+            return fwp
+
+        # check if this policy is associated with firewall
+        fw_list = self._get_firewall_list_from_firewall_policy(context, id)
+        if not fw_list:
+            return fwp
+
+        for fw in fw_list:
+            # Get the router_service insertion binding with firewall id
+            # TODO(fank): optimized by using _get_resource_router_id_bindings
+            service_router_binding = self._get_resource_router_id_binding(
+                context, firewall_db.Firewall, resource_id=fw['id'])
+            self._vcns_update_firewall(
+                context, fw, service_router_binding.router_id)
+        return fwp
+
+    def insert_rule(self, context, id, rule_info):
+        LOG.debug(_("insert_rule() called"))
+        self._ensure_firewall_policy_update_allowed(context, id)
+        fwp = super(NvpAdvancedPlugin, self).insert_rule(
+            context, id, rule_info)
+        fwr = super(NvpAdvancedPlugin, self).get_firewall_rule(
+            context, rule_info['firewall_rule_id'])
+
+        # check if this policy is associated with firewall
+        fw_list = self._get_firewall_list_from_firewall_policy(context, id)
+        if not fw_list:
+            return fwp
+        for fw in fw_list:
+            # TODO(fank): optimized by using _get_resource_router_id_bindings
+            service_router_binding = self._get_resource_router_id_binding(
+                context, firewall_db.Firewall, resource_id=fw['id'])
+            edge_id = self._get_edge_id_by_vcns_edge_binding(
+                context, service_router_binding.router_id)
+
+            if rule_info.get('insert_before') or rule_info.get('insert_after'):
+                #if insert_before or insert_after is set, we would call
+                #VCNS insert_rule API
+                #TODO(linb): do rollback on error
+                self.vcns_driver.insert_rule(context, rule_info, edge_id, fwr)
+            else:
+                #Else we would call bulk configuration on the firewall
+                self._vcns_update_firewall(context, fw, edge_id=edge_id)
+        return fwp
+
+    def remove_rule(self, context, id, rule_info):
+        LOG.debug(_("remove_rule() called"))
+        self._ensure_firewall_policy_update_allowed(context, id)
+        fwp = super(NvpAdvancedPlugin, self).remove_rule(
+            context, id, rule_info)
+        fwr = super(NvpAdvancedPlugin, self).get_firewall_rule(
+            context, rule_info['firewall_rule_id'])
+
+        # check if this policy is associated with firewall
+        fw_list = self._get_firewall_list_from_firewall_policy(context, id)
+        if not fw_list:
+            return fwp
+        for fw in fw_list:
+            # TODO(fank): optimized by using _get_resource_router_id_bindings
+            service_router_binding = self._get_resource_router_id_binding(
+                context, firewall_db.Firewall, resource_id=fw['id'])
+            edge_id = self._get_edge_id_by_vcns_edge_binding(
+                context, service_router_binding.router_id)
+            #TODO(linb): do rollback on error
+            self.vcns_driver.delete_firewall_rule(
+                context, fwr['id'], edge_id)
+        return fwp
+
+
+class VcnsCallbacks(object):
+    """Edge callback implementation Callback functions for
+    asynchronous tasks.
     """
     def __init__(self, plugin):
         self.plugin = plugin
index 21743b6d14ac4be5ce774151f4cb7d9e4062bcf1..7da4b3323acc8754c87deed49b305579de5ef2b2 100644 (file)
@@ -62,3 +62,17 @@ class MaintenanceInProgress(NvpPluginException):
     message = _("The networking backend is currently in maintenance mode and "
                 "therefore unable to accept requests which modify its state. "
                 "Please try later.")
+
+
+class NvpServicePluginException(q_exc.NeutronException):
+    """NVP Service Plugin exceptions."""
+    message = _("An unexpected error happened "
+                "in the NVP Service Plugin:%(err_msg)s")
+
+
+class NvpServiceOverQuota(q_exc.Conflict):
+    message = _("Quota exceeded for Vcns resource: %(overs)s: %(err_msg)s")
+
+
+class NvpVcnsDriverException(NvpServicePluginException):
+    message = _("Error happened in NVP VCNS Driver: %(err_msg)s")
index 9d7daaa615c231282b892d397cd276438db554bf..f223eca4cc1510c459c26c440efe4728c6d431ba 100644 (file)
@@ -15,6 +15,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from sqlalchemy.orm import exc
+
+from neutron.plugins.nicira.common import exceptions as nvp_exc
 from neutron.plugins.nicira.dbexts import vcns_models
 
 
@@ -48,3 +51,47 @@ def delete_vcns_router_binding(session, router_id):
         binding = (session.query(vcns_models.VcnsRouterBinding).
                    filter_by(router_id=router_id).one())
         session.delete(binding)
+
+
+#
+# Edge Firewall binding methods
+def add_vcns_edge_firewallrule_binding(session, map_info):
+    with session.begin(subtransactions=True):
+        binding = vcns_models.VcnsEdgeFirewallRuleBinding(
+            rule_id=map_info['rule_id'],
+            rule_vseid=map_info['rule_vseid'],
+            edge_id=map_info['edge_id'])
+        session.add(binding)
+        return binding
+
+
+def delete_vcns_edge_firewallrule_binding(session, id):
+    with session.begin(subtransactions=True):
+        if not (session.query(vcns_models.VcnsEdgeFirewallRuleBinding).
+                filter_by(rule_id=id).delete()):
+            msg = _("Rule Resource binding with id:%s not found!") % id
+            raise nvp_exc.NvpServicePluginException(err_msg=msg)
+
+
+def get_vcns_edge_firewallrule_binding(session, id, edge_id):
+    with session.begin(subtransactions=True):
+        return (session.query(vcns_models.VcnsEdgeFirewallRuleBinding).
+                filter_by(rule_id=id, edge_id=edge_id).first())
+
+
+def get_vcns_edge_firewallrule_binding_by_vseid(
+        session, edge_id, rule_vseid):
+    with session.begin(subtransactions=True):
+        try:
+            return (session.query(vcns_models.VcnsEdgeFirewallRuleBinding).
+                    filter_by(edge_id=edge_id, rule_vseid=rule_vseid).one())
+        except exc.NoResultFound:
+            msg = _("Rule Resource binding not found!")
+            raise nvp_exc.NvpServicePluginException(err_msg=msg)
+
+
+def cleanup_vcns_edge_firewallrule_binding(session, edge_id):
+    with session.begin(subtransactions=True):
+        session.query(
+            vcns_models.VcnsEdgeFirewallRuleBinding).filter_by(
+                edge_id=edge_id).delete()
index fe96d245c5c63d8fee97c2b1d65e64efedf96902..e2be5f95377a7aafca8c776b81ff0b8cb75a9edb 100644 (file)
@@ -36,3 +36,18 @@ class VcnsRouterBinding(model_base.BASEV2, models_v2.HasStatusDescription):
                         nullable=True)
     lswitch_id = sa.Column(sa.String(36),
                            nullable=False)
+
+
+#
+# VCNS Edge FW mapping tables
+#
+class VcnsEdgeFirewallRuleBinding(model_base.BASEV2):
+    """1:1 mapping between firewall rule and edge firewall rule_id."""
+
+    __tablename__ = 'vcns_firewall_rule_bindings'
+
+    rule_id = sa.Column(sa.String(36),
+                        sa.ForeignKey("firewall_rules.id"),
+                        primary_key=True)
+    edge_id = sa.Column(sa.String(36), primary_key=True)
+    rule_vseid = sa.Column(sa.String(36))
index c020e3bcdadf5fb9514fc11828270feebebb67f5..fc51d20020e88101c12b3b9d425765818ff51de9 100644 (file)
@@ -1,7 +1,7 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
-# Copyright 2013 VMware, Inc.
-# All Rights Reserved
+# Copyright 2013 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
index 2e4b210e1e0cf8cd7415592244e1e4bec5466c02..346359af19a0560db932b16618b3d1c06e453bb3 100644 (file)
@@ -29,6 +29,14 @@ class VcnsGeneralException(VcnsException):
         super(VcnsGeneralException, self).__init__()
 
 
+class VcnsBadRequest(exceptions.BadRequest):
+    pass
+
+
+class VcnsNotFound(exceptions.NotFound):
+    message = _('%(resource)s not found: %(msg)s')
+
+
 class VcnsApiException(VcnsException):
     message = _("An unknown exception %(status)s occurred: %(response)s.")
 
diff --git a/neutron/plugins/nicira/vshield/edge_firewall_driver.py b/neutron/plugins/nicira/vshield/edge_firewall_driver.py
new file mode 100644 (file)
index 0000000..a84a9b5
--- /dev/null
@@ -0,0 +1,354 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 VMware, Inc
+#
+#    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: Leon Cui, VMware
+
+from neutron.db import db_base_plugin_v2
+from neutron.openstack.common import excutils
+from neutron.openstack.common import log as logging
+from neutron.plugins.common import constants
+from neutron.plugins.nicira.dbexts import vcns_db
+from neutron.plugins.nicira.vshield.common import (
+    exceptions as vcns_exc)
+
+LOG = logging.getLogger(__name__)
+
+VSE_FWAAS_ALLOW = "accept"
+VSE_FWAAS_DENY = "deny"
+
+
+class EdgeFirewallDriver(db_base_plugin_v2.NeutronDbPluginV2):
+    """Implementation of driver APIs for
+       Edge Firewall feature configuration
+    """
+    def _convert_firewall_action(self, action):
+        if action == constants.FWAAS_ALLOW:
+            return VSE_FWAAS_ALLOW
+        elif action == constants.FWAAS_DENY:
+            return VSE_FWAAS_DENY
+        else:
+            msg = _("Invalid action value %s in a firewall rule") % action
+            raise vcns_exc.BadRequest(resource='firewall_rule', msg=msg)
+
+    def _restore_firewall_action(self, action):
+        if action == VSE_FWAAS_ALLOW:
+            return constants.FWAAS_ALLOW
+        elif action == VSE_FWAAS_DENY:
+            return constants.FWAAS_DENY
+        else:
+            msg = (_("Invalid action value %s in "
+                     "a vshield firewall rule") % action)
+            raise vcns_exc.BadRequest(resource='firewall_rule', msg=msg)
+
+    def _get_port_range_from_min_max_ports(self, min_port, max_port):
+        if not min_port:
+            return None
+        if min_port == max_port:
+            return str(min_port)
+        else:
+            return '%d:%d' % (min_port, max_port)
+
+    def _get_min_max_ports_from_range(self, port_range):
+        if not port_range:
+            return [None, None]
+        min_port, sep, max_port = port_range.partition(":")
+        if not max_port:
+            max_port = min_port
+        return [int(min_port), int(max_port)]
+
+    def _convert_firewall_rule(self, context, rule, index=None):
+        vcns_rule = {
+            "name": rule['name'],
+            "description": rule['description'],
+            "action": self._convert_firewall_action(rule['action']),
+            "enabled": rule['enabled']}
+        if rule.get('source_ip_address'):
+            vcns_rule['source'] = {
+                "ipAddress": [rule['source_ip_address']]
+            }
+        if rule.get('destination_ip_address'):
+            vcns_rule['destination'] = {
+                "ipAddress": [rule['destination_ip_address']]
+            }
+        service = {}
+        if rule.get('source_port'):
+            min_port, max_port = self._get_min_max_ports_from_range(
+                rule['source_port'])
+            service['sourcePort'] = [i for i in range(min_port, max_port + 1)]
+        if rule.get('destination_port'):
+            min_port, max_port = self._get_min_max_ports_from_range(
+                rule['destination_port'])
+            service['port'] = [i for i in range(min_port, max_port + 1)]
+        if rule.get('protocol'):
+            service['protocol'] = rule['protocol']
+        if service:
+            vcns_rule['application'] = {
+                'service': [service]
+            }
+        if index:
+            vcns_rule['ruleTag'] = index
+        return vcns_rule
+
+    def _restore_firewall_rule(self, context, edge_id, response):
+        rule = response
+        rule_binding = vcns_db.get_vcns_edge_firewallrule_binding_by_vseid(
+            context.session, edge_id, rule['ruleId'])
+        service = rule['application']['service'][0]
+        src_port_range = self._get_port_range_from_min_max_ports(
+            service['sourcePort'][0], service['sourcePort'][-1])
+        dst_port_range = self._get_port_range_from_min_max_ports(
+            service['port'][0], service['port'][-1])
+        return {
+            'firewall_rule': {
+                'name': rule['name'],
+                'id': rule_binding['rule_id'],
+                'description': rule['description'],
+                'source_ip_address': rule['source']['ipAddress'][0],
+                'destination_ip_address': rule['destination']['ipAddress'][0],
+                'protocol': service['protocol'],
+                'destination_port': dst_port_range,
+                'source_port': src_port_range,
+                'action': self._restore_firewall_action(rule['action']),
+                'enabled': rule['enabled']}}
+
+    def _convert_firewall(self, context, firewall):
+        #bulk configuration on firewall and rescheduling the rule binding
+        ruleTag = 1
+        vcns_rules = []
+        for rule in firewall['firewall_rule_list']:
+            vcns_rule = self._convert_firewall_rule(context, rule, ruleTag)
+            vcns_rules.append(vcns_rule)
+            ruleTag += 1
+        return {
+            'featureType': "firewall_4.0",
+            'firewallRules': {
+                'firewallRules': vcns_rules}}
+
+    def _restore_firewall(self, context, edge_id, response):
+        res = {}
+        res['firewall_rule_list'] = []
+        for rule in response['firewallRules']['firewallRules']:
+            rule_binding = (
+                vcns_db.get_vcns_edge_firewallrule_binding_by_vseid(
+                    context.session, edge_id, rule['ruleId']))
+            if rule_binding is None:
+                continue
+            service = rule['application']['service'][0]
+            src_port_range = self._get_port_range_from_min_max_ports(
+                service['sourcePort'][0], service['sourcePort'][-1])
+            dst_port_range = self._get_port_range_from_min_max_ports(
+                service['port'][0], service['port'][-1])
+            item = {
+                'firewall_rule': {
+                    'name': rule['name'],
+                    'id': rule_binding['rule_id'],
+                    'description': rule['description'],
+                    'source_ip_address': rule['source']['ipAddress'][0],
+                    'destination_ip_address': rule[
+                        'destination']['ipAddress'][0],
+                    'protocol': service['protocol'],
+                    'destination_port': dst_port_range,
+                    'source_port': src_port_range,
+                    'action': self._restore_firewall_action(rule['action']),
+                    'enabled': rule['enabled']}}
+            res['firewall_rule_list'].append(item)
+        return res
+
+    def _create_rule_id_mapping(
+        self, context, edge_id, firewall, vcns_fw):
+        for rule in vcns_fw['firewallRules']['firewallRules']:
+            index = rule['ruleTag'] - 1
+            #TODO(linb):a simple filter of the retrived rules which may be
+            #created by other operations unintentionally
+            if index < len(firewall['firewall_rule_list']):
+                rule_vseid = rule['ruleId']
+                rule_id = firewall['firewall_rule_list'][index]['id']
+                map_info = {
+                    'rule_id': rule_id,
+                    'rule_vseid': rule_vseid,
+                    'edge_id': edge_id
+                }
+                vcns_db.add_vcns_edge_firewallrule_binding(
+                    context.session, map_info)
+
+    def _get_firewall(self, context, edge_id):
+        try:
+            return self.vcns.get_firewall(edge_id)[1]
+        except vcns_exc.VcnsApiException as e:
+            LOG.exception(_("Failed to get firewall with edge "
+                            "id: %s"), edge_id)
+            raise e
+
+    def _get_firewall_rule_next(self, context, edge_id, rule_vseid):
+        # Return the firewall rule below 'rule_vseid'
+        fw_cfg = self._get_firewall(context, edge_id)
+        for i in range(len(fw_cfg['firewallRules']['firewallRules'])):
+            rule_cur = fw_cfg['firewallRules']['firewallRules'][i]
+            if str(rule_cur['ruleId']) == rule_vseid:
+                if (i + 1) == len(fw_cfg['firewallRules']['firewallRules']):
+                    return None
+                else:
+                    return fw_cfg['firewallRules']['firewallRules'][i + 1]
+
+    def get_firewall_rule(self, context, id, edge_id):
+        rule_map = vcns_db.get_vcns_edge_firewallrule_binding(
+            context.session, id, edge_id)
+        if rule_map is None:
+            msg = _("No rule id:%s found in the edge_firewall_binding") % id
+            LOG.error(msg)
+            raise vcns_exc.VcnsNotFound(
+                resource='vcns_firewall_rule_bindings', msg=msg)
+        vcns_rule_id = rule_map.rule_vseid
+        try:
+            response = self.vcns.get_firewall_rule(
+                edge_id, vcns_rule_id)[1]
+        except vcns_exc.VcnsApiException as e:
+            LOG.exception(_("Failed to get firewall rule: %(rule_id)s "
+                            "with edge_id: %(edge_id)s"), {
+                          'rule_id': id,
+                          'edge_id': edge_id})
+            raise e
+        return self._restore_firewall_rule(context, edge_id, response)
+
+    def get_firewall(self, context, edge_id):
+        response = self._get_firewall(context, edge_id)
+        return self._restore_firewall(context, edge_id, response)
+
+    def update_firewall(self, context, edge_id, firewall):
+        fw_req = self._convert_firewall(context, firewall)
+        try:
+            self.vcns.update_firewall(edge_id, fw_req)
+        except vcns_exc.VcnsApiException as e:
+            LOG.exception(_("Failed to update firewall "
+                            "with edge_id: %s"), edge_id)
+            raise e
+        fw_res = self._get_firewall(context, edge_id)
+        vcns_db.cleanup_vcns_edge_firewallrule_binding(
+            context.session, edge_id)
+        self._create_rule_id_mapping(context, edge_id, firewall, fw_res)
+
+    def delete_firewall(self, context, edge_id):
+        try:
+            self.vcns.delete_firewall(edge_id)
+        except vcns_exc.VcnsApiException as e:
+            LOG.exception(_("Failed to delete firewall "
+                            "with edge_id:%s"), edge_id)
+            raise e
+        vcns_db.cleanup_vcns_edge_firewallrule_binding(
+            context.session, edge_id)
+
+    def update_firewall_rule(self, context, id, edge_id, firewall_rule):
+        rule_map = vcns_db.get_vcns_edge_firewallrule_binding(
+            context.session, id, edge_id)
+        vcns_rule_id = rule_map.rule_vseid
+        fwr_req = self._convert_firewall_rule(context, firewall_rule)
+        try:
+            self.vcns.update_firewall_rule(edge_id, vcns_rule_id, fwr_req)
+        except vcns_exc.VcnsApiException:
+            with excutils.save_and_reraise_exception():
+                LOG.exception(_("Failed to update firewall rule: %(rule_id)s "
+                                "with edge_id: %(edge_id)s"),
+                              {'rule_id': id,
+                               'edge_id': edge_id})
+
+    def delete_firewall_rule(self, context, id, edge_id):
+        rule_map = vcns_db.get_vcns_edge_firewallrule_binding(
+            context.session, id, edge_id)
+        vcns_rule_id = rule_map.rule_vseid
+        try:
+            self.vcns.delete_firewall_rule(edge_id, vcns_rule_id)
+        except vcns_exc.VcnsApiException:
+            with excutils.save_and_reraise_exception():
+                LOG.exception(_("Failed to delete firewall rule: %(rule_id)s "
+                                "with edge_id: %(edge_id)s"),
+                              {'rule_id': id,
+                               'edge_id': edge_id})
+        vcns_db.delete_vcns_edge_firewallrule_binding(
+            context.session, id)
+
+    def _add_rule_above(self, context, ref_rule_id, edge_id, firewall_rule):
+        rule_map = vcns_db.get_vcns_edge_firewallrule_binding(
+            context.session, ref_rule_id, edge_id)
+        ref_vcns_rule_id = rule_map.rule_vseid
+        fwr_req = self._convert_firewall_rule(context, firewall_rule)
+        try:
+            header = self.vcns.add_firewall_rule_above(
+                edge_id, ref_vcns_rule_id, fwr_req)[0]
+        except vcns_exc.VcnsApiException:
+            with excutils.save_and_reraise_exception():
+                LOG.exception(_("Failed to add firewall rule above: "
+                                "%(rule_id)s with edge_id: %(edge_id)s"),
+                              {'rule_id': ref_vcns_rule_id,
+                               'edge_id': edge_id})
+
+        objuri = header['location']
+        fwr_vseid = objuri[objuri.rfind("/") + 1:]
+        map_info = {
+            'rule_id': firewall_rule['id'],
+            'rule_vseid': fwr_vseid,
+            'edge_id': edge_id}
+        vcns_db.add_vcns_edge_firewallrule_binding(
+            context.session, map_info)
+
+    def _add_rule_below(self, context, ref_rule_id, edge_id, firewall_rule):
+        rule_map = vcns_db.get_vcns_edge_firewallrule_binding(
+            context.session, ref_rule_id, edge_id)
+        ref_vcns_rule_id = rule_map.rule_vseid
+        fwr_vse_next = self._get_firewall_rule_next(
+            context, edge_id, ref_vcns_rule_id)
+        fwr_req = self._convert_firewall_rule(context, firewall_rule)
+        if fwr_vse_next:
+            ref_vcns_rule_id = fwr_vse_next['ruleId']
+            try:
+                header = self.vcns.add_firewall_rule_above(
+                    edge_id, int(ref_vcns_rule_id), fwr_req)[0]
+            except vcns_exc.VcnsApiException:
+                with excutils.save_and_reraise_exception():
+                    LOG.exception(_("Failed to add firewall rule above: "
+                                    "%(rule_id)s with edge_id: %(edge_id)s"),
+                                  {'rule_id': ref_vcns_rule_id,
+                                   'edge_id': edge_id})
+        else:
+            # append the rule at the bottom
+            try:
+                header = self.vcns.add_firewall_rule(
+                    edge_id, fwr_req)[0]
+            except vcns_exc.VcnsApiException:
+                with excutils.save_and_reraise_exception():
+                    LOG.exception(_("Failed to append a firewall rule"
+                                    "with edge_id: %s"), edge_id)
+
+        objuri = header['location']
+        fwr_vseid = objuri[objuri.rfind("/") + 1:]
+        map_info = {
+            'rule_id': firewall_rule['id'],
+            'rule_vseid': fwr_vseid,
+            'edge_id': edge_id
+        }
+        vcns_db.add_vcns_edge_firewallrule_binding(
+            context.session, map_info)
+
+    def insert_rule(self, context, rule_info, edge_id, fwr):
+        if rule_info.get('insert_before'):
+            self._add_rule_above(
+                context, rule_info['insert_before'], edge_id, fwr)
+        elif rule_info.get('insert_after'):
+            self._add_rule_below(
+                context, rule_info['insert_after'], edge_id, fwr)
+        else:
+            msg = _("Can't execute insert rule operation "
+                    "without reference rule_id")
+            raise vcns_exc.BadRequest(resource='firewall_rule', msg=msg)
index b02a97c2c9bbc182720324ba13522bb3f8583c28..beace318da6da94897bf18e77dfbdf2f9d46ac6d 100644 (file)
@@ -28,6 +28,10 @@ HTTP_DELETE = "DELETE"
 HTTP_PUT = "PUT"
 URI_PREFIX = "/api/4.0/edges"
 
+#FwaaS constants
+FIREWALL_SERVICE = "firewall/config"
+FIREWALL_RULE_RESOURCE = "rules"
+
 
 class Vcns(object):
 
@@ -106,3 +110,69 @@ class Vcns(object):
     def delete_lswitch(self, lswitch_id):
         uri = "/api/ws.v1/lswitch/%s" % lswitch_id
         return self.do_request(HTTP_DELETE, uri)
+
+    def update_firewall(self, edge_id, fw_req):
+        uri = self._build_uri_path(
+            edge_id, FIREWALL_SERVICE)
+        return self.do_request(HTTP_PUT, uri, fw_req)
+
+    def delete_firewall(self, edge_id):
+        uri = self._build_uri_path(
+            edge_id, FIREWALL_SERVICE, None)
+        return self.do_request(HTTP_DELETE, uri)
+
+    def update_firewall_rule(self, edge_id, vcns_rule_id, fwr_req):
+        uri = self._build_uri_path(
+            edge_id, FIREWALL_SERVICE,
+            FIREWALL_RULE_RESOURCE,
+            vcns_rule_id)
+        return self.do_request(HTTP_PUT, uri, fwr_req)
+
+    def delete_firewall_rule(self, edge_id, vcns_rule_id):
+        uri = self._build_uri_path(
+            edge_id, FIREWALL_SERVICE,
+            FIREWALL_RULE_RESOURCE,
+            vcns_rule_id)
+        return self.do_request(HTTP_DELETE, uri)
+
+    def add_firewall_rule_above(self, edge_id, ref_vcns_rule_id, fwr_req):
+        uri = self._build_uri_path(
+            edge_id, FIREWALL_SERVICE,
+            FIREWALL_RULE_RESOURCE)
+        uri += "?aboveRuleId=" + ref_vcns_rule_id
+        return self.do_request(HTTP_POST, uri, fwr_req)
+
+    def add_firewall_rule(self, edge_id, fwr_req):
+        uri = self._build_uri_path(
+            edge_id, FIREWALL_SERVICE,
+            FIREWALL_RULE_RESOURCE)
+        return self.do_request(HTTP_POST, uri, fwr_req)
+
+    def get_firewall(self, edge_id):
+        uri = self._build_uri_path(edge_id, FIREWALL_SERVICE)
+        return self.do_request(HTTP_GET, uri, decode=True)
+
+    def get_firewall_rule(self, edge_id, vcns_rule_id):
+        uri = self._build_uri_path(
+            edge_id, FIREWALL_SERVICE,
+            FIREWALL_RULE_RESOURCE,
+            vcns_rule_id)
+        return self.do_request(HTTP_GET, uri, decode=True)
+
+    def _build_uri_path(self, edge_id,
+                        service,
+                        resource=None,
+                        resource_id=None,
+                        parent_resource_id=None,
+                        fields=None,
+                        relations=None,
+                        filters=None,
+                        types=None,
+                        is_attachment=False):
+        uri_prefix = "%s/%s/%s" % (URI_PREFIX, edge_id, service)
+        if resource:
+            res_path = resource + (resource_id and "/%s" % resource_id or '')
+            uri_path = "%s/%s" % (uri_prefix, res_path)
+        else:
+            uri_path = uri_prefix
+        return uri_path
index f5f69037c733e16da9d94b66c08bdf502a7b8ffb..8178744a9187271f960c1c583ff51fed9118f6bb 100644 (file)
@@ -20,11 +20,13 @@ from oslo.config import cfg
 
 from neutron.plugins.nicira.common import config  # noqa
 from neutron.plugins.nicira.vshield import edge_appliance_driver
+from neutron.plugins.nicira.vshield import edge_firewall_driver
 from neutron.plugins.nicira.vshield.tasks import tasks
 from neutron.plugins.nicira.vshield import vcns
 
 
-class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver):
+class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver,
+                 edge_firewall_driver.EdgeFirewallDriver):
     def __init__(self, callbacks):
         super(VcnsDriver, self).__init__()
 
@@ -40,5 +42,4 @@ class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver):
         interval = cfg.CONF.vcns.task_status_check_interval
         self.task_manager = tasks.TaskManager(interval)
         self.task_manager.start()
-
         self.vcns = vcns.Vcns(self.vcns_uri, self.vcns_user, self.vcns_passwd)
index 4c204e37199fccfdebe896307523554755feb87b..c2d32b62c5acf13b9d19ab81355a552b74c6ac58 100644 (file)
@@ -58,23 +58,25 @@ class FirewallPluginDbTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
         for k in firewall.RESOURCE_ATTRIBUTE_MAP.keys()
     )
 
-    def setUp(self, core_plugin=None, fw_plugin=None):
+    def setUp(self, core_plugin=None, fw_plugin=None, ext_mgr=None):
         if not fw_plugin:
             fw_plugin = DB_FW_PLUGIN_KLASS
         service_plugins = {'fw_plugin_name': fw_plugin}
 
         fdb.Firewall_db_mixin.supported_extension_aliases = ["fwaas"]
         super(FirewallPluginDbTestCase, self).setUp(
+            ext_mgr=ext_mgr,
             service_plugins=service_plugins
         )
 
-        self.plugin = importutils.import_object(fw_plugin)
-        ext_mgr = api_ext.PluginAwareExtensionManager(
-            extensions_path,
-            {constants.FIREWALL: self.plugin}
-        )
-        app = config.load_paste_app('extensions_test_app')
-        self.ext_api = api_ext.ExtensionMiddleware(app, ext_mgr=ext_mgr)
+        if not ext_mgr:
+            self.plugin = importutils.import_object(fw_plugin)
+            ext_mgr = api_ext.PluginAwareExtensionManager(
+                extensions_path,
+                {constants.FIREWALL: self.plugin}
+            )
+            app = config.load_paste_app('extensions_test_app')
+            self.ext_api = api_ext.ExtensionMiddleware(app, ext_mgr=ext_mgr)
 
     def _test_list_resources(self, resource, items,
                              neutron_context=None,
index 62b27ecf98ed208eb3e499cd5ff9e745c2a985fa..89a6abcda75467ea89f73685e120c9920ebc8046 100644 (file)
@@ -22,13 +22,18 @@ from neutron.plugins.nicira import extensions
 import neutron.plugins.nicira.NeutronPlugin as plugin
 import neutron.plugins.nicira.NeutronServicePlugin as service_plugin
 import neutron.plugins.nicira.NvpApiClient as nvpapi
+from neutron.plugins.nicira.vshield.common import (
+    VcnsApiClient as vcnsapi)
 from neutron.plugins.nicira.vshield import vcns
+import neutron.plugins.nicira.vshield.vcns_driver as vcnsdriver
 
 nvp_plugin = plugin.NvpPluginV2
 nvp_service_plugin = service_plugin.NvpAdvancedPlugin
 api_helper = nvpapi.NVPApiHelper
 nvp_client = client.NvpApiClientEventlet
 vcns_class = vcns.Vcns
+vcns_driver = vcnsdriver.VcnsDriver
+vcns_api_helper = vcnsapi.VcnsApiHelper
 
 STUBS_PATH = os.path.join(os.path.dirname(__file__), 'etc')
 NVPEXT_PATH = os.path.dirname(extensions.__file__)
@@ -38,6 +43,9 @@ SERVICE_PLUGIN_NAME = '%s.%s' % (nvp_service_plugin.__module__,
                                  nvp_service_plugin.__name__)
 CLIENT_NAME = '%s.%s' % (nvp_client.__module__, nvp_client.__name__)
 VCNS_NAME = '%s.%s' % (vcns_class.__module__, vcns_class.__name__)
+VCNS_DRIVER_NAME = '%s.%s' % (vcns_driver.__module__, vcns_driver.__name__)
+VCNSAPI_NAME = '%s.%s' % (vcns_api_helper.__module__,
+                          vcns_api_helper.__name__)
 
 
 def get_fake_conf(filename):
index f5dc6971b4ea48275e71b838658d58ade82c5c95..f2deff6145c0ed8d376314095aee1129a86c9c9e 100644 (file)
@@ -61,15 +61,17 @@ class ServiceRouterTestExtensionManager(object):
 
 class NvpRouterTestCase(test_nicira_plugin.TestNiciraL3NatTestCase):
 
-    def setUp(self, plugin=None, ext_mgr=None):
+    def setUp(self, plugin=None, ext_mgr=None, service_plugins=None):
         plugin = plugin or SERVICE_PLUGIN_NAME
-        super(NvpRouterTestCase, self).setUp(plugin=plugin, ext_mgr=ext_mgr)
+        super(NvpRouterTestCase, self).setUp(plugin=plugin, ext_mgr=ext_mgr,
+                                             service_plugins=service_plugins)
 
 
-class ServiceRouterTestCase(NvpRouterTestCase):
+class ServiceRouterTest(test_nicira_plugin.NiciraL3NatTest):
 
     def vcns_patch(self):
         instance = self.mock_vcns.start()
+        self.vcns_instance = instance
         instance.return_value.deploy_edge.side_effect = self.fc2.deploy_edge
         instance.return_value.get_edge_id.side_effect = self.fc2.get_edge_id
         instance.return_value.get_edge_deploy_status.side_effect = (
@@ -93,7 +95,7 @@ class ServiceRouterTestCase(NvpRouterTestCase):
         instance.return_value.delete_lswitch.side_effect = (
             self.fc2.delete_lswitch)
 
-    def setUp(self):
+    def setUp(self, ext_mgr=None, service_plugins=None):
         cfg.CONF.set_override('api_extensions_path', NVPEXT_PATH)
         cfg.CONF.set_override('task_status_check_interval', 100, group="vcns")
 
@@ -103,8 +105,11 @@ class ServiceRouterTestCase(NvpRouterTestCase):
         self.mock_vcns = mock.patch(VCNS_NAME, autospec=True)
         self.vcns_patch()
 
-        super(ServiceRouterTestCase, self).setUp(
-            ext_mgr=ServiceRouterTestExtensionManager())
+        ext_mgr = ext_mgr or ServiceRouterTestExtensionManager()
+        super(ServiceRouterTest, self).setUp(
+            plugin=SERVICE_PLUGIN_NAME,
+            service_plugins=service_plugins,
+            ext_mgr=ext_mgr)
 
         self.fc2.set_fake_nvpapi(self.fc)
         self.addCleanup(self.fc2.reset_all)
@@ -122,7 +127,7 @@ class ServiceRouterTestCase(NvpRouterTestCase):
             raise Exception(_("Tasks not completed"))
         manager.stop()
 
-        super(ServiceRouterTestCase, self).tearDown()
+        super(ServiceRouterTest, self).tearDown()
 
     def _create_router(self, fmt, tenant_id, name=None,
                        admin_state_up=None, set_context=False,
@@ -145,6 +150,9 @@ class ServiceRouterTestCase(NvpRouterTestCase):
 
         return router_req.get_response(self.ext_api)
 
+
+class ServiceRouterTestCase(ServiceRouterTest, NvpRouterTestCase):
+
     def test_router_create(self):
         name = 'router1'
         tenant_id = _uuid()
diff --git a/neutron/tests/unit/nicira/test_fwaas_plugin.py b/neutron/tests/unit/nicira/test_fwaas_plugin.py
new file mode 100644 (file)
index 0000000..d1f65ae
--- /dev/null
@@ -0,0 +1,564 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 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.
+#
+
+import contextlib
+import copy
+import webob.exc
+
+from neutron.api.v2 import attributes
+from neutron import context
+from neutron.extensions import firewall
+from neutron import manager
+from neutron.openstack.common import uuidutils
+from neutron.plugins.common import constants as const
+from neutron.tests.unit.db.firewall import test_db_firewall
+from neutron.tests.unit.nicira import test_edge_router
+
+_uuid = uuidutils.generate_uuid
+
+FW_PLUGIN_CLASS = (
+    "neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin"
+)
+
+
+class FirewallTestExtensionManager(
+        test_edge_router.ServiceRouterTestExtensionManager):
+
+    def get_resources(self):
+        # If l3 resources have been loaded and updated by main API
+        # router, update the map in the l3 extension so it will load
+        # the same attributes as the API router
+        resources = super(FirewallTestExtensionManager, self).get_resources()
+        firewall_attr_map = copy.deepcopy(firewall.RESOURCE_ATTRIBUTE_MAP)
+        for res in firewall.RESOURCE_ATTRIBUTE_MAP.keys():
+            attr_info = attributes.RESOURCE_ATTRIBUTE_MAP.get(res)
+            if attr_info:
+                firewall.RESOURCE_ATTRIBUTE_MAP[res] = attr_info
+        fw_resources = firewall.Firewall.get_resources()
+        # restore the original resources once the controllers are created
+        firewall.RESOURCE_ATTRIBUTE_MAP = firewall_attr_map
+
+        resources.extend(fw_resources)
+
+        return resources
+
+    def get_actions(self):
+        return []
+
+    def get_request_extensions(self):
+        return []
+
+
+class FirewallPluginTestCase(test_db_firewall.FirewallPluginDbTestCase,
+                             test_edge_router.ServiceRouterTest):
+
+    def vcns_firewall_patch(self):
+        self.vcns_instance.return_value.update_firewall.side_effect = (
+            self.fc2.update_firewall)
+        self.vcns_instance.return_value.delete_firewall.side_effect = (
+            self.fc2.delete_firewall)
+        self.vcns_instance.return_value.update_firewall_rule.side_effect = (
+            self.fc2.update_firewall_rule)
+        self.vcns_instance.return_value.delete_firewall_rule.side_effect = (
+            self.fc2.delete_firewall_rule)
+        self.vcns_instance.return_value.add_firewall_rule_above.side_effect = (
+            self.fc2.add_firewall_rule_above)
+        self.vcns_instance.return_value.add_firewall_rule.side_effect = (
+            self.fc2.add_firewall_rule)
+        self.vcns_instance.return_value.get_firewall.side_effect = (
+            self.fc2.get_firewall)
+        self.vcns_instance.return_value.get_firewall_rule.side_effect = (
+            self.fc2.get_firewall_rule)
+
+    def setUp(self):
+        # Save the global RESOURCE_ATTRIBUTE_MAP
+        self.saved_attr_map = {}
+        for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
+            self.saved_attr_map[resource] = attrs.copy()
+
+        super(FirewallPluginTestCase, self).setUp(
+            ext_mgr=FirewallTestExtensionManager(),
+            fw_plugin=FW_PLUGIN_CLASS)
+        self.vcns_firewall_patch()
+        self.plugin = manager.NeutronManager.get_plugin()
+        self.router_id = None
+
+    def tearDown(self):
+        super(FirewallPluginTestCase, self).tearDown()
+        # Restore the global RESOURCE_ATTRIBUTE_MAP
+        attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
+        self.ext_api = None
+        self.plugin = None
+
+    def _fake_router_edge_mapping(self):
+        req = self._create_router(self.fmt, self._tenant_id)
+        res = self.deserialize(self.fmt, req)
+        self.router_id = res['router']['id']
+
+    def _create_firewall(self, fmt, name, description, firewall_policy_id,
+                         admin_state_up=True, expected_res_status=None,
+                         **kwargs):
+        data = {'firewall': {'name': name,
+                             'description': description,
+                             'firewall_policy_id': firewall_policy_id,
+                             'router_id': self.router_id,
+                             'admin_state_up': admin_state_up,
+                             'tenant_id': self._tenant_id}}
+
+        firewall_req = self.new_create_request('firewalls', data, fmt)
+        firewall_res = firewall_req.get_response(self.ext_api)
+        if expected_res_status:
+            self.assertEqual(firewall_res.status_int, expected_res_status)
+
+        return firewall_res
+
+    def test_create_firewall(self):
+        self._fake_router_edge_mapping()
+
+        name = "new_fw"
+        attrs = self._get_test_firewall_attrs(name)
+
+        with self.firewall_policy() as fwp:
+            fwp_id = fwp['firewall_policy']['id']
+            attrs['firewall_policy_id'] = fwp_id
+            with self.firewall(name=name,
+                               firewall_policy_id=fwp_id,
+                               router_id=self.router_id,
+                               admin_state_up=
+                               test_db_firewall.ADMIN_STATE_UP,
+                               expected_res_status=201) as fw:
+                attrs = self._replace_firewall_status(
+                    attrs, const.PENDING_CREATE, const.ACTIVE)
+                for k, v in attrs.iteritems():
+                    self.assertEqual(fw['firewall'][k], v)
+
+    def test_update_firewall(self):
+        self._fake_router_edge_mapping()
+
+        name = "new_fw"
+        attrs = self._get_test_firewall_attrs(name)
+
+        with self.firewall_policy() as fwp:
+            fwp_id = fwp['firewall_policy']['id']
+            attrs['firewall_policy_id'] = fwp_id
+            with self.firewall(
+                firewall_policy_id=fwp_id, router_id=self.router_id,
+                admin_state_up=test_db_firewall.ADMIN_STATE_UP) as fw:
+                fw_id = fw['firewall']['id']
+                new_data = {'firewall': {'name': name}}
+                req = self.new_update_request('firewalls', new_data, fw_id)
+                res = req.get_response(self.ext_api)
+                self.assertEqual(res.status_int, 200)
+                res_json = self.deserialize(
+                    self.fmt, res)
+                attrs = self._replace_firewall_status(
+                    attrs, const.PENDING_CREATE, const.ACTIVE)
+                for k, v in attrs.iteritems():
+                    self.assertEqual(res_json['firewall'][k], v)
+
+    def test_delete_firewall(self):
+        ctx = context.get_admin_context()
+        self._fake_router_edge_mapping()
+
+        with self.firewall_policy() as fwp:
+            fwp_id = fwp['firewall_policy']['id']
+            with self.firewall(
+                firewall_policy_id=fwp_id,
+                router_id=self.router_id,
+                admin_state_up=test_db_firewall.ADMIN_STATE_UP,
+                no_delete=True) as fw:
+                fw_id = fw['firewall']['id']
+                with ctx.session.begin(subtransactions=True):
+                    req = self.new_delete_request('firewalls', fw_id)
+                    res = req.get_response(self.ext_api)
+                    self.assertEqual(res.status_int, 204)
+                    self.assertRaises(
+                        firewall.FirewallNotFound,
+                        self.plugin.get_firewall, ctx, fw_id)
+
+    def test_create_firewall_with_rules(self):
+        ctx = context.get_admin_context()
+        self._fake_router_edge_mapping()
+
+        with contextlib.nested(self.firewall_rule(name='fwr1'),
+                               self.firewall_rule(name='fwr2'),
+                               self.firewall_rule(name='fwr3')) as fr:
+            with self.firewall_policy() as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
+                data = {'firewall_policy':
+                        {'firewall_rules': fw_rule_ids}}
+                req = self.new_update_request(
+                    'firewall_policies', data, fwp_id)
+                req.get_response(self.ext_api)
+                attrs = self._get_test_firewall_attrs()
+                attrs['firewall_policy_id'] = fwp_id
+                with self.firewall(
+                    firewall_policy_id=fwp_id, router_id=self.router_id,
+                    admin_state_up=test_db_firewall.ADMIN_STATE_UP) as fw:
+                    rule_list = (
+                        self.plugin._make_firewall_rule_list_by_policy_id(
+                            ctx, fw['firewall']['firewall_policy_id']))
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fr, rule_list)
+
+    def test_update_firewall_policy_with_no_firewall(self):
+        name = "new_firewall_policy1"
+        attrs = self._get_test_firewall_policy_attrs(name)
+
+        with self.firewall_policy(shared=test_db_firewall.SHARED,
+                                  firewall_rules=None,
+                                  audited=test_db_firewall.AUDITED) as fwp:
+            data = {'firewall_policy': {'name': name}}
+            req = self.new_update_request('firewall_policies', data,
+                                          fwp['firewall_policy']['id'])
+            res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+            for k, v in attrs.iteritems():
+                self.assertEqual(res['firewall_policy'][k], v)
+
+    def test_update_firewall_policy_with_firewall(self):
+        self._fake_router_edge_mapping()
+
+        name = "new_firewall_policy1"
+        attrs = self._get_test_firewall_policy_attrs(name)
+
+        with self.firewall_policy(shared=test_db_firewall.SHARED,
+                                  firewall_rules=None,
+                                  audited=test_db_firewall.AUDITED) as fwp:
+            fwp_id = fwp['firewall_policy']['id']
+            with self.firewall(firewall_policy_id=fwp_id,
+                               router_id=self.router_id,
+                               admin_state_up=
+                               test_db_firewall.ADMIN_STATE_UP):
+                data = {'firewall_policy': {'name': name}}
+                req = self.new_update_request(
+                    'firewall_policies', data, fwp['firewall_policy']['id'])
+                res = self.deserialize(
+                    self.fmt, req.get_response(self.ext_api))
+                for k, v in attrs.iteritems():
+                    self.assertEqual(res['firewall_policy'][k], v)
+
+    def test_update_firewall_rule_with_no_firewall(self):
+        name = "new_firewall_rule1"
+        attrs = self._get_test_firewall_rule_attrs(name)
+
+        attrs['source_port'] = '10:20'
+        attrs['destination_port'] = '30:40'
+        with self.firewall_rule() as fwr:
+            data = {'firewall_rule': {'name': name,
+                                      'source_port': '10:20',
+                                      'destination_port': '30:40'}}
+            req = self.new_update_request(
+                'firewall_rules', data, fwr['firewall_rule']['id'])
+            res = self.deserialize(
+                self.fmt, req.get_response(self.ext_api))
+            for k, v in attrs.iteritems():
+                self.assertEqual(res['firewall_rule'][k], v)
+
+        attrs['source_port'] = '10000'
+        attrs['destination_port'] = '80'
+        with self.firewall_rule() as fwr:
+            data = {'firewall_rule': {'name': name,
+                                      'source_port': 10000,
+                                      'destination_port': 80}}
+            req = self.new_update_request('firewall_rules', data,
+                                          fwr['firewall_rule']['id'])
+            res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+            for k, v in attrs.iteritems():
+                self.assertEqual(res['firewall_rule'][k], v)
+
+        attrs['source_port'] = None
+        attrs['destination_port'] = None
+        with self.firewall_rule() as fwr:
+            data = {'firewall_rule': {'name': name,
+                                      'source_port': None,
+                                      'destination_port': None}}
+            req = self.new_update_request(
+                'firewall_rules', data, fwr['firewall_rule']['id'])
+            res = self.deserialize(
+                self.fmt, req.get_response(self.ext_api))
+            for k, v in attrs.iteritems():
+                self.assertEqual(res['firewall_rule'][k], v)
+
+    def test_update_firewall_rule_with_firewall(self):
+        self._fake_router_edge_mapping()
+
+        name = "new_firewall_rule1"
+        attrs = self._get_test_firewall_rule_attrs(name)
+        with self.firewall_rule() as fwr:
+            with self.firewall_policy() as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                attrs['firewall_policy_id'] = fwp_id
+                with self.firewall(firewall_policy_id=fwp_id,
+                                   router_id=self.router_id,
+                                   admin_state_up=
+                                   test_db_firewall.ADMIN_STATE_UP):
+                    fwr_id = fwr['firewall_rule']['id']
+                    data = {'firewall_policy': {'firewall_rules': [fwr_id]}}
+                    req = self.new_update_request(
+                        'firewall_policies', data,
+                        fwp['firewall_policy']['id'])
+                    req.get_response(self.ext_api)
+                    data = {'firewall_rule': {'name': name}}
+                    req = self.new_update_request(
+                        'firewall_rules', data,
+                        fwr['firewall_rule']['id'])
+                    res = self.deserialize(
+                        self.fmt, req.get_response(self.ext_api))
+                    attrs['firewall_policy_id'] = fwp_id
+                    for k, v in attrs.iteritems():
+                        self.assertEqual(res['firewall_rule'][k], v)
+
+    def test_insert_rule_with_no_firewall(self):
+        attrs = self._get_test_firewall_policy_attrs()
+        attrs['audited'] = False
+        attrs['firewall_list'] = []
+        with contextlib.nested(self.firewall_rule(name='fwr0'),
+                               self.firewall_rule(name='fwr1'),
+                               self.firewall_rule(name='fwr2'),
+                               self.firewall_rule(name='fwr3'),
+                               self.firewall_rule(name='fwr4'),
+                               self.firewall_rule(name='fwr5'),
+                               self.firewall_rule(name='fwr6')) as fwr:
+            with self.firewall_policy() as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                attrs['id'] = fwp_id
+                # test insert when rule list is empty
+                fwr0_id = fwr[0]['firewall_rule']['id']
+                attrs['firewall_rules'].insert(0, fwr0_id)
+                self._rule_action('insert', fwp_id, fwr0_id,
+                                  insert_before=None,
+                                  insert_after=None,
+                                  expected_code=webob.exc.HTTPOk.code,
+                                  expected_body=attrs)
+                # test insert at top of rule list, insert_before and
+                # insert_after not provided
+                fwr1_id = fwr[1]['firewall_rule']['id']
+                attrs['firewall_rules'].insert(0, fwr1_id)
+                insert_data = {'firewall_rule_id': fwr1_id}
+                self._rule_action('insert', fwp_id, fwr0_id,
+                                  expected_code=webob.exc.HTTPOk.code,
+                                  expected_body=attrs, body_data=insert_data)
+                # test insert at top of list above existing rule
+                fwr2_id = fwr[2]['firewall_rule']['id']
+                attrs['firewall_rules'].insert(0, fwr2_id)
+                self._rule_action('insert', fwp_id, fwr2_id,
+                                  insert_before=fwr1_id,
+                                  insert_after=None,
+                                  expected_code=webob.exc.HTTPOk.code,
+                                  expected_body=attrs)
+                # test insert at bottom of list
+                fwr3_id = fwr[3]['firewall_rule']['id']
+                attrs['firewall_rules'].append(fwr3_id)
+                self._rule_action('insert', fwp_id, fwr3_id,
+                                  insert_before=None,
+                                  insert_after=fwr0_id,
+                                  expected_code=webob.exc.HTTPOk.code,
+                                  expected_body=attrs)
+                # test insert in the middle of the list using
+                # insert_before
+                fwr4_id = fwr[4]['firewall_rule']['id']
+                attrs['firewall_rules'].insert(1, fwr4_id)
+                self._rule_action('insert', fwp_id, fwr4_id,
+                                  insert_before=fwr1_id,
+                                  insert_after=None,
+                                  expected_code=webob.exc.HTTPOk.code,
+                                  expected_body=attrs)
+                # test insert in the middle of the list using
+                # insert_after
+                fwr5_id = fwr[5]['firewall_rule']['id']
+                attrs['firewall_rules'].insert(1, fwr5_id)
+                self._rule_action('insert', fwp_id, fwr5_id,
+                                  insert_before=None,
+                                  insert_after=fwr2_id,
+                                  expected_code=webob.exc.HTTPOk.code,
+                                  expected_body=attrs)
+                # test insert when both insert_before and
+                # insert_after are set
+                fwr6_id = fwr[6]['firewall_rule']['id']
+                attrs['firewall_rules'].insert(1, fwr6_id)
+                self._rule_action('insert', fwp_id, fwr6_id,
+                                  insert_before=fwr5_id,
+                                  insert_after=fwr5_id,
+                                  expected_code=webob.exc.HTTPOk.code,
+                                  expected_body=attrs)
+
+    def test_insert_rule_with_firewall(self):
+        self._fake_router_edge_mapping()
+
+        attrs = self._get_test_firewall_policy_attrs()
+        attrs['audited'] = False
+        attrs['firewall_list'] = []
+        with contextlib.nested(self.firewall_rule(name='fwr0'),
+                               self.firewall_rule(name='fwr1'),
+                               self.firewall_rule(name='fwr2'),
+                               self.firewall_rule(name='fwr3'),
+                               self.firewall_rule(name='fwr4'),
+                               self.firewall_rule(name='fwr5'),
+                               self.firewall_rule(name='fwr6')) as fwr:
+            with self.firewall_policy() as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                attrs['id'] = fwp_id
+                with self.firewall(router_id=self.router_id,
+                                   firewall_policy_id=fwp_id) as fw:
+                    # test insert when rule list is empty
+                    fwr0_id = fwr[0]['firewall_rule']['id']
+                    attrs['firewall_rules'].insert(0, fwr0_id)
+                    attrs['firewall_list'].insert(0, fw['firewall']['id'])
+                    self._rule_action('insert', fwp_id, fwr0_id,
+                                      insert_before=None,
+                                      insert_after=None,
+                                      expected_code=webob.exc.HTTPOk.code,
+                                      expected_body=attrs)
+                    # test insert at top of rule list, insert_before and
+                    # insert_after not provided
+                    fwr1_id = fwr[1]['firewall_rule']['id']
+                    attrs['firewall_rules'].insert(0, fwr1_id)
+                    insert_data = {'firewall_rule_id': fwr1_id}
+                    self._rule_action(
+                        'insert', fwp_id, fwr0_id,
+                        expected_code=webob.exc.HTTPOk.code,
+                        expected_body=attrs, body_data=insert_data)
+                    # test insert at top of list above existing rule
+                    fwr2_id = fwr[2]['firewall_rule']['id']
+                    attrs['firewall_rules'].insert(0, fwr2_id)
+                    self._rule_action('insert', fwp_id, fwr2_id,
+                                      insert_before=fwr1_id,
+                                      insert_after=None,
+                                      expected_code=webob.exc.HTTPOk.code,
+                                      expected_body=attrs)
+                    # test insert at bottom of list
+                    fwr3_id = fwr[3]['firewall_rule']['id']
+                    attrs['firewall_rules'].append(fwr3_id)
+                    self._rule_action('insert', fwp_id, fwr3_id,
+                                      insert_before=None,
+                                      insert_after=fwr0_id,
+                                      expected_code=webob.exc.HTTPOk.code,
+                                      expected_body=attrs)
+                    # test insert in the middle of the list using
+                    # insert_before
+                    fwr4_id = fwr[4]['firewall_rule']['id']
+                    attrs['firewall_rules'].insert(1, fwr4_id)
+                    self._rule_action('insert', fwp_id, fwr4_id,
+                                      insert_before=fwr1_id,
+                                      insert_after=None,
+                                      expected_code=webob.exc.HTTPOk.code,
+                                      expected_body=attrs)
+                    # test insert in the middle of the list using
+                    # insert_after
+                    fwr5_id = fwr[5]['firewall_rule']['id']
+                    attrs['firewall_rules'].insert(1, fwr5_id)
+                    self._rule_action('insert', fwp_id, fwr5_id,
+                                      insert_before=None,
+                                      insert_after=fwr2_id,
+                                      expected_code=webob.exc.HTTPOk.code,
+                                      expected_body=attrs)
+                    # test insert when both insert_before and
+                    # insert_after are set
+                    fwr6_id = fwr[6]['firewall_rule']['id']
+                    attrs['firewall_rules'].insert(1, fwr6_id)
+                    self._rule_action('insert', fwp_id, fwr6_id,
+                                      insert_before=fwr5_id,
+                                      insert_after=fwr5_id,
+                                      expected_code=webob.exc.HTTPOk.code,
+                                      expected_body=attrs)
+
+    def test_remove_rule_with_no_firewall(self):
+        attrs = self._get_test_firewall_policy_attrs()
+        attrs['audited'] = False
+        attrs['firewall_list'] = []
+        with self.firewall_policy() as fwp:
+            fwp_id = fwp['firewall_policy']['id']
+            attrs['id'] = fwp_id
+            with contextlib.nested(self.firewall_rule(name='fwr1'),
+                                   self.firewall_rule(name='fwr2'),
+                                   self.firewall_rule(name='fwr3')) as fr1:
+                fw_rule_ids = [r['firewall_rule']['id'] for r in fr1]
+                attrs['firewall_rules'] = fw_rule_ids[:]
+                data = {'firewall_policy':
+                        {'firewall_rules': fw_rule_ids}}
+                req = self.new_update_request('firewall_policies', data,
+                                              fwp_id)
+                req.get_response(self.ext_api)
+                # test removing a rule from a policy that does not exist
+                self._rule_action('remove', '123', fw_rule_ids[1],
+                                  expected_code=webob.exc.HTTPNotFound.code,
+                                  expected_body=None)
+                # test removing a rule in the middle of the list
+                attrs['firewall_rules'].remove(fw_rule_ids[1])
+                self._rule_action('remove', fwp_id, fw_rule_ids[1],
+                                  expected_body=attrs)
+                # test removing a rule at the top of the list
+                attrs['firewall_rules'].remove(fw_rule_ids[0])
+                self._rule_action('remove', fwp_id, fw_rule_ids[0],
+                                  expected_body=attrs)
+                # test removing remaining rule in the list
+                attrs['firewall_rules'].remove(fw_rule_ids[2])
+                self._rule_action('remove', fwp_id, fw_rule_ids[2],
+                                  expected_body=attrs)
+                # test removing rule that is not associated with the policy
+                self._rule_action('remove', fwp_id, fw_rule_ids[2],
+                                  expected_code=webob.exc.HTTPBadRequest.code,
+                                  expected_body=None)
+
+    def test_remove_rule_with_firewall(self):
+        self._fake_router_edge_mapping()
+
+        attrs = self._get_test_firewall_policy_attrs()
+        attrs['audited'] = False
+        attrs['firewall_list'] = []
+        with self.firewall_policy() as fwp:
+            fwp_id = fwp['firewall_policy']['id']
+            attrs['id'] = fwp_id
+            with self.firewall(router_id=self.router_id,
+                               firewall_policy_id=fwp_id) as fw:
+                attrs['firewall_list'].insert(0, fw['firewall']['id'])
+                with contextlib.nested(self.firewall_rule(name='fwr1'),
+                                       self.firewall_rule(name='fwr2'),
+                                       self.firewall_rule(name='fwr3')) as fr1:
+                    fw_rule_ids = [r['firewall_rule']['id'] for r in fr1]
+                    attrs['firewall_rules'] = fw_rule_ids[:]
+                    data = {'firewall_policy':
+                            {'firewall_rules': fw_rule_ids}}
+                    req = self.new_update_request(
+                        'firewall_policies', data, fwp_id)
+                    req.get_response(self.ext_api)
+                    # test removing a rule from a policy that does not exist
+                    self._rule_action(
+                        'remove', '123',
+                        fw_rule_ids[1],
+                        expected_code=webob.exc.HTTPNotFound.code,
+                        expected_body=None)
+                    # test removing a rule in the middle of the list
+                    attrs['firewall_rules'].remove(fw_rule_ids[1])
+                    self._rule_action('remove', fwp_id, fw_rule_ids[1],
+                                      expected_body=attrs)
+                    # test removing a rule at the top of the list
+                    attrs['firewall_rules'].remove(fw_rule_ids[0])
+                    self._rule_action('remove', fwp_id, fw_rule_ids[0],
+                                      expected_body=attrs)
+                    # test removing remaining rule in the list
+                    attrs['firewall_rules'].remove(fw_rule_ids[2])
+                    self._rule_action('remove', fwp_id, fw_rule_ids[2],
+                                      expected_body=attrs)
+                    # test removing rule that is not
+                    #associated with the policy
+                    self._rule_action(
+                        'remove', fwp_id, fw_rule_ids[2],
+                        expected_code=webob.exc.HTTPBadRequest.code,
+                        expected_body=None)
index ec2dadda669b3d36e177315b9cc756f54e2ae3a9..adc6bcee8c1f9b0c46eafd496043e41459e468a8 100644 (file)
@@ -474,13 +474,13 @@ class TestNiciraL3ExtensionManager(object):
         return []
 
 
-class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBIntTestCase,
-                              NiciraPluginV2TestCase):
+class NiciraL3NatTest(test_l3_plugin.L3BaseForIntTests,
+                      NiciraPluginV2TestCase):
 
     def _restore_l3_attribute_map(self):
         l3.RESOURCE_ATTRIBUTE_MAP = self._l3_attribute_map_bk
 
-    def setUp(self, plugin=None, ext_mgr=None):
+    def setUp(self, plugin=None, ext_mgr=None, service_plugins=None):
         self._l3_attribute_map_bk = {}
         for item in l3.RESOURCE_ATTRIBUTE_MAP:
             self._l3_attribute_map_bk[item] = (
@@ -488,16 +488,18 @@ class TestNiciraL3NatTestCase(test_l3_plugin.L3NatDBIntTestCase,
         cfg.CONF.set_override('api_extensions_path', NVPEXT_PATH)
         self.addCleanup(self._restore_l3_attribute_map)
         ext_mgr = ext_mgr or TestNiciraL3ExtensionManager()
-        super(TestNiciraL3NatTestCase, self).setUp(
-            plugin=plugin, ext_mgr=ext_mgr)
+        super(NiciraL3NatTest, self).setUp(
+            plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins)
         plugin_instance = NeutronManager.get_plugin()
         self._plugin_name = "%s.%s" % (
             plugin_instance.__module__,
             plugin_instance.__class__.__name__)
         self._plugin_class = plugin_instance.__class__
 
-    def tearDown(self):
-        super(TestNiciraL3NatTestCase, self).tearDown()
+
+class TestNiciraL3NatTestCase(NiciraL3NatTest,
+                              test_l3_plugin.L3NatDBIntTestCase,
+                              NiciraPluginV2TestCase):
 
     def _create_l3_ext_network(self, vlan_id=None):
         name = 'l3_ext_net'
diff --git a/neutron/tests/unit/nicira/vshield/common/__init__.py b/neutron/tests/unit/nicira/vshield/common/__init__.py
deleted file mode 100644 (file)
index 5e8da71..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2013 OpenStack Foundation.
-# 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.
index cfc9137d6347e6d43cd5ec2c4ca4e78bffba9e31..3435c3b46053602438930f4fa3bd8074d64d2393 100644 (file)
@@ -20,10 +20,20 @@ import copy
 import json
 
 from neutron.openstack.common import uuidutils
+from neutron.plugins.nicira.vshield.common import exceptions
 
 
 class FakeVcns(object):
 
+    errors = {
+        303: exceptions.ResourceRedirect,
+        400: exceptions.RequestBad,
+        403: exceptions.Forbidden,
+        404: exceptions.ResourceNotFound,
+        415: exceptions.MediaTypeUnsupport,
+        503: exceptions.ServiceUnavailable
+    }
+
     def __init__(self, unique_router_name=True):
         self._jobs = {}
         self._job_idx = 0
@@ -32,6 +42,12 @@ class FakeVcns(object):
         self._lswitches = {}
         self._unique_router_name = unique_router_name
         self._fake_nvpapi = None
+        self.fake_firewall_dict = {}
+        self.temp_firewall = {
+            "firewallRules": {
+                "firewallRules": []
+            }
+        }
 
     def set_fake_nvpapi(self, fake_nvpapi):
         self._fake_nvpapi = fake_nvpapi
@@ -243,7 +259,123 @@ class FakeVcns(object):
         response = ''
         return (header, response)
 
+    def update_firewall(self, edge_id, fw_req):
+        self.fake_firewall_dict[edge_id] = fw_req
+        rules = self.fake_firewall_dict[edge_id][
+            'firewallRules']['firewallRules']
+        index = 10
+        for rule in rules:
+            rule['ruleId'] = index
+            index += 10
+        header = {'status': 204}
+        response = ""
+        return self.return_helper(header, response)
+
+    def delete_firewall(self, edge_id):
+        header = {'status': 404}
+        if edge_id in self.fake_firewall_dict:
+            header = {'status': 204}
+            del self.fake_firewall_dict[edge_id]
+        response = ""
+        return self.return_helper(header, response)
+
+    def update_firewall_rule(self, edge_id, vcns_rule_id, fwr_req):
+        if edge_id not in self.fake_firewall_dict:
+            raise Exception(_("Edge %s does not exist") % edge_id)
+        header = {'status': 404}
+        rules = self.fake_firewall_dict[edge_id][
+            'firewallRules']['firewallRules']
+        for rule in rules:
+            if rule['ruleId'] == int(vcns_rule_id):
+                header['status'] = 204
+                rule.update(fwr_req)
+                break
+        response = ""
+        return self.return_helper(header, response)
+
+    def delete_firewall_rule(self, edge_id, vcns_rule_id):
+        if edge_id not in self.fake_firewall_dict:
+            raise Exception(_("Edge %s does not exist") % edge_id)
+        header = {'status': 404}
+        rules = self.fake_firewall_dict[edge_id][
+            'firewallRules']['firewallRules']
+        for index in range(len(rules)):
+            if rules[index]['ruleId'] == int(vcns_rule_id):
+                header['status'] = 204
+                del rules[index]
+                break
+        response = ""
+        return self.return_helper(header, response)
+
+    def add_firewall_rule_above(self, edge_id, ref_vcns_rule_id, fwr_req):
+        if edge_id not in self.fake_firewall_dict:
+            raise Exception(_("Edge %s does not exist") % edge_id)
+        header = {'status': 404}
+        rules = self.fake_firewall_dict[edge_id][
+            'firewallRules']['firewallRules']
+        pre = 0
+        for index in range(len(rules)):
+            if rules[index]['ruleId'] == int(ref_vcns_rule_id):
+                rules.insert(index, fwr_req)
+                rules[index]['ruleId'] = (int(ref_vcns_rule_id) + pre) / 2
+                header = {
+                    'status': 204,
+                    'location': "https://host/api/4.0/edges/edge_id/firewall"
+                                "/config/rules/%s" % rules[index]['ruleId']}
+                break
+            pre = int(rules[index]['ruleId'])
+        response = ""
+        return self.return_helper(header, response)
+
+    def add_firewall_rule(self, edge_id, fwr_req):
+        if edge_id not in self.fake_firewall_dict:
+            self.fake_firewall_dict[edge_id] = self.temp_firewall
+        rules = self.fake_firewall_dict[edge_id][
+            'firewallRules']['firewallRules']
+        rules.append(fwr_req)
+        index = len(rules)
+        rules[index - 1]['ruleId'] = index * 10
+        header = {
+            'status': 204,
+            'location': "https://host/api/4.0/edges/edge_id/firewall"
+                        "/config/rules/%s" % rules[index - 1]['ruleId']}
+        response = ""
+        return self.return_helper(header, response)
+
+    def get_firewall(self, edge_id):
+        if edge_id not in self.fake_firewall_dict:
+            self.fake_firewall_dict[edge_id] = self.temp_firewall
+        header = {'status': 204}
+        response = self.fake_firewall_dict[edge_id]
+        return self.return_helper(header, response)
+
+    def get_firewall_rule(self, edge_id, vcns_rule_id):
+        if edge_id not in self.fake_firewall_dict:
+            raise Exception(_("Edge %s does not exist") % edge_id)
+        header = {'status': 404}
+        response = ""
+        rules = self.fake_firewall_dict[edge_id][
+            'firewallRules']['firewallRules']
+        for rule in rules:
+            if rule['ruleId'] == int(vcns_rule_id):
+                header['status'] = 204
+                response = rule
+                break
+        return self.return_helper(header, response)
+
+    def return_helper(self, header, response):
+        status = int(header['status'])
+        if 200 <= status <= 300:
+            return (header, response)
+        if status in self.errors:
+            cls = self.errors[status]
+        else:
+            cls = exceptions.VcnsApiException
+        raise cls(
+            status=status, header=header, uri='fake_url', response=response)
+
     def reset_all(self):
         self._jobs.clear()
         self._edges.clear()
         self._lswitches.clear()
+        self.fake_firewall_dict = {}
diff --git a/neutron/tests/unit/nicira/vshield/test_firewall_driver.py b/neutron/tests/unit/nicira/vshield/test_firewall_driver.py
new file mode 100644 (file)
index 0000000..26705dd
--- /dev/null
@@ -0,0 +1,381 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 VMware, Inc
+#
+#    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: linb, VMware
+
+import contextlib
+import mock
+import webob.exc
+
+from neutron.common import config as n_config
+from neutron import context
+from neutron.db.firewall import firewall_db
+from neutron.openstack.common import uuidutils
+from neutron.plugins.nicira.vshield.common import exceptions as vcns_exc
+from neutron.plugins.nicira.vshield import vcns_driver
+from neutron.tests.unit.db.firewall import test_db_firewall
+from neutron.tests.unit.nicira import get_fake_conf
+from neutron.tests.unit.nicira import VCNS_NAME
+from neutron.tests.unit.nicira.vshield import fake_vcns
+
+
+_uuid = uuidutils.generate_uuid
+
+VSE_ID = 'edge-1'
+ROUTER_ID = '42f95450-5cc9-44e4-a744-1320e592a9d5'
+
+VCNS_CONFIG_FILE = get_fake_conf("vcns.ini.test")
+
+
+class VcnsDriverTestCase(test_db_firewall.FirewallPluginDbTestCase,
+                         firewall_db.Firewall_db_mixin):
+
+    def vcns_firewall_patch(self):
+        instance = self.mock_vcns.start()
+        instance.return_value.update_firewall.side_effect = (
+            self.fc2.update_firewall)
+        instance.return_value.delete_firewall.side_effect = (
+            self.fc2.delete_firewall)
+        instance.return_value.update_firewall_rule.side_effect = (
+            self.fc2.update_firewall_rule)
+        instance.return_value.delete_firewall_rule.side_effect = (
+            self.fc2.delete_firewall_rule)
+        instance.return_value.add_firewall_rule_above.side_effect = (
+            self.fc2.add_firewall_rule_above)
+        instance.return_value.add_firewall_rule.side_effect = (
+            self.fc2.add_firewall_rule)
+        instance.return_value.get_firewall.side_effect = (
+            self.fc2.get_firewall)
+        instance.return_value.get_firewall_rule.side_effect = (
+            self.fc2.get_firewall_rule)
+
+    def setUp(self):
+
+        n_config.parse(['--config-file', VCNS_CONFIG_FILE])
+        # mock vcns
+        self.fc2 = fake_vcns.FakeVcns(unique_router_name=False)
+        self.mock_vcns = mock.patch(VCNS_NAME, autospec=True)
+        self.vcns_firewall_patch()
+
+        self.nvp_service_plugin_callback = mock.Mock()
+        self.driver = vcns_driver.VcnsDriver(self.nvp_service_plugin_callback)
+
+        super(VcnsDriverTestCase, self).setUp()
+        self.addCleanup(self.fc2.reset_all)
+        self.addCleanup(self.mock_vcns.stop)
+
+        self.tenant_id = _uuid()
+        self.subnet_id = _uuid()
+
+
+class TestEdgeFwDriver(VcnsDriverTestCase):
+
+    def _make_firewall_dict_with_rules(self, context, firewall_id):
+        fw = self.get_firewall(context, firewall_id)
+        fw_policy_id = fw['firewall_policy_id']
+        if fw_policy_id:
+            firewall_policy_db = self._get_firewall_policy(
+                context, fw_policy_id)
+            fw['firewall_rule_list'] = [
+                self._make_firewall_rule_dict(fw_rule_db)
+                for fw_rule_db in firewall_policy_db['firewall_rules']
+            ]
+
+        return fw
+
+    def _compare_firewall_rule_lists(self, firewall_policy_id,
+                                     list1, list2):
+        for r1, r2 in zip(list1, list2):
+            rule = r1['firewall_rule']
+            rule['firewall_policy_id'] = firewall_policy_id
+            for k in rule:
+                self.assertEqual(rule[k], r2[k])
+
+    def test_create_and_get_firewall(self):
+        ctx = context.get_admin_context()
+        name = 'firewall'
+        with contextlib.nested(self.firewall_rule(name='fwr1',
+                                                  no_delete=True),
+                               self.firewall_rule(name='fwr2',
+                                                  no_delete=True),
+                               self.firewall_rule(name='fwr3',
+                                                  no_delete=True)) as fr:
+            fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
+            with self.firewall_policy(firewall_rules=fw_rule_ids,
+                                      no_delete=True) as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                with self.firewall(name=name,
+                                   firewall_policy_id=fwp_id) as firewall:
+                    fw_create = firewall['firewall']
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+                    self.driver.update_firewall(ctx, VSE_ID, fw_expect)
+                    fw_get = self.driver.get_firewall(ctx, VSE_ID)
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fw_get['firewall_rule_list'],
+                        fw_expect['firewall_rule_list'])
+
+    def test_update_firewall_with_rules(self):
+        ctx = context.get_admin_context()
+        name = 'new_firewall'
+        with contextlib.nested(self.firewall_rule(name='fwr1',
+                                                  no_delete=True),
+                               self.firewall_rule(name='fwr2',
+                                                  no_delete=True),
+                               self.firewall_rule(name='fwr3',
+                                                  no_delete=True)) as fr:
+            fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
+            with self.firewall_policy(firewall_rules=fw_rule_ids,
+                                      no_delete=True) as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                with self.firewall(name=name,
+                                   firewall_policy_id=fwp_id) as firewall:
+                    fw_create = firewall['firewall']
+                    fw_create = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+                    self.driver.update_firewall(ctx, VSE_ID, fw_create)
+
+                    data = {'firewall_rule': {'name': name,
+                                              'source_port': '10:20',
+                                              'destination_port': '30:40'}}
+                    self.new_update_request('firewall_rules', data,
+                                            fr[0]['firewall_rule']['id'])
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+                    self.driver.update_firewall(ctx, VSE_ID, fw_expect)
+
+                    fw_get = self.driver.get_firewall(
+                        ctx, VSE_ID)
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fw_get['firewall_rule_list'],
+                        fw_expect['firewall_rule_list'])
+
+    def test_delete_firewall(self):
+        ctx = context.get_admin_context()
+        name = 'firewall'
+        with contextlib.nested(self.firewall_rule(name='fwr1',
+                                                  no_delete=True),
+                               self.firewall_rule(name='fwr2',
+                                                  no_delete=True),
+                               self.firewall_rule(name='fwr3',
+                                                  no_delete=True)) as fr:
+            fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
+            with self.firewall_policy(firewall_rules=fw_rule_ids,
+                                      no_delete=True) as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                with self.firewall(name=name,
+                                   firewall_policy_id=fwp_id) as firewall:
+                    fw_create = firewall['firewall']
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+                    self.driver.update_firewall(ctx, VSE_ID, fw_expect)
+                    self.driver.delete_firewall(ctx, VSE_ID)
+                    fw_get = self.driver.get_firewall(
+                        ctx, VSE_ID)
+                    self.assertFalse(fw_get['firewall_rule_list'])
+
+    def test_update_firewall_rule(self):
+        ctx = context.get_admin_context()
+        name = 'new_firewall'
+        with contextlib.nested(self.firewall_rule(name='fwr1',
+                                                  no_delete=True)) as fr:
+            fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
+            with self.firewall_policy(firewall_rules=fw_rule_ids,
+                                      no_delete=True) as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                with self.firewall(name=name,
+                                   firewall_policy_id=fwp_id) as firewall:
+                    fw_create = firewall['firewall']
+                    fw_create = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+                    self.driver.update_firewall(ctx, VSE_ID, fw_create)
+
+                    data = {'firewall_rule': {'name': name,
+                                              'source_port': '10:20',
+                                              'destination_port': '30:40'}}
+                    req = self.new_update_request(
+                        'firewall_rules', data,
+                        fr[0]['firewall_rule']['id'])
+                    res = self.deserialize(self.fmt,
+                                           req.get_response(self.ext_api))
+                    rule_expect = res['firewall_rule']
+                    rule_expect['edge_id'] = VSE_ID
+                    self.driver.update_firewall_rule(
+                        ctx, rule_expect['id'], VSE_ID, rule_expect)
+                    rule_get = self.driver.get_firewall_rule(
+                        ctx, rule_expect['id'], VSE_ID)
+                    for k, v in rule_get['firewall_rule'].items():
+                        self.assertEqual(rule_expect[k], v)
+
+    def test_delete_firewall_rule(self):
+        ctx = context.get_admin_context()
+        name = 'new_firewall'
+        with contextlib.nested(self.firewall_rule(name='fwr1',
+                                                  no_delete=True),
+                               self.firewall_rule(name='fwr2',
+                                                  no_delete=True)) as fr:
+            fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
+            with self.firewall_policy(firewall_rules=fw_rule_ids,
+                                      no_delete=True) as fwp:
+                fwp_id = fwp['firewall_policy']['id']
+                with self.firewall(name=name,
+                                   firewall_policy_id=fwp_id) as firewall:
+                    fw_create = firewall['firewall']
+                    fw_create = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+                    self.driver.update_firewall(ctx, VSE_ID, fw_create)
+
+                    fr[0]['firewall_rule']['edge_id'] = VSE_ID
+                    self.driver.delete_firewall_rule(
+                        ctx, fr[0]['firewall_rule']['id'],
+                        VSE_ID)
+                    self.assertRaises(vcns_exc.VcnsNotFound,
+                                      self.driver.get_firewall_rule,
+                                      ctx, fr[0]['firewall_rule']['id'],
+                                      VSE_ID)
+
+    def test_insert_rule(self):
+        ctx = context.get_admin_context()
+        with self.firewall_policy() as fwp:
+            fwp_id = fwp['firewall_policy']['id']
+            with self.firewall(firewall_policy_id=fwp_id) as firewall:
+                fw_create = firewall['firewall']
+                fw_create = self._make_firewall_dict_with_rules(
+                    ctx, fw_create['id'])
+                self.driver.update_firewall(ctx, VSE_ID, fw_create)
+                with contextlib.nested(self.firewall_rule(name='fwr0',
+                                                          no_delete=True),
+                                       self.firewall_rule(name='fwr1',
+                                                          no_delete=True),
+                                       self.firewall_rule(name='fwr2',
+                                                          no_delete=True),
+                                       self.firewall_rule(name='fwr3',
+                                                          no_delete=True),
+                                       self.firewall_rule(name='fwr4',
+                                                          no_delete=True),
+                                       self.firewall_rule(name='fwr5',
+                                                          no_delete=True),
+                                       self.firewall_rule(
+                                           name='fwr6',
+                                           no_delete=True)) as fwr:
+                    # test insert when rule list is empty
+                    fwr0_id = fwr[0]['firewall_rule']['id']
+                    self._rule_action('insert', fwp_id, fwr0_id,
+                                      insert_before=None,
+                                      insert_after=None,
+                                      expected_code=webob.exc.HTTPOk.code)
+                    fw_update = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+                    self.driver.update_firewall(ctx, VSE_ID, fw_update)
+                    # test insert at top of list above existing rule
+                    fwr1_id = fwr[1]['firewall_rule']['id']
+                    self._rule_action('insert', fwp_id, fwr1_id,
+                                      insert_before=fwr0_id,
+                                      insert_after=None,
+                                      expected_code=webob.exc.HTTPOk.code)
+
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+
+                    rule_info = {'firewall_rule_id': fwr1_id,
+                                 'insert_before': fwr0_id,
+                                 'insert_after': None}
+                    rule = fwr[1]['firewall_rule']
+                    self.driver.insert_rule(ctx, rule_info, VSE_ID, rule)
+                    fw_get = self.driver.get_firewall(
+                        ctx, VSE_ID)
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fw_get['firewall_rule_list'],
+                        fw_expect['firewall_rule_list'])
+                    # test insert at bottom of list
+                    fwr2_id = fwr[2]['firewall_rule']['id']
+                    self._rule_action('insert', fwp_id, fwr2_id,
+                                      insert_before=None,
+                                      insert_after=fwr0_id,
+                                      expected_code=webob.exc.HTTPOk.code)
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+
+                    rule_info = {'firewall_rule_id': fwr2_id,
+                                 'insert_before': None,
+                                 'insert_after': fwr0_id}
+                    rule = fwr[2]['firewall_rule']
+                    self.driver.insert_rule(ctx, rule_info, VSE_ID, rule)
+                    fw_get = self.driver.get_firewall(
+                        ctx, VSE_ID)
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fw_get['firewall_rule_list'],
+                        fw_expect['firewall_rule_list'])
+                    # test insert in the middle of the list using
+                    # insert_before
+                    fwr3_id = fwr[3]['firewall_rule']['id']
+                    self._rule_action('insert', fwp_id, fwr3_id,
+                                      insert_before=fwr2_id,
+                                      insert_after=None,
+                                      expected_code=webob.exc.HTTPOk.code)
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+
+                    rule_info = {'firewall_rule_id': fwr3_id,
+                                 'insert_before': fwr2_id,
+                                 'insert_after': None}
+                    rule = fwr[3]['firewall_rule']
+                    self.driver.insert_rule(ctx, rule_info, VSE_ID, rule)
+                    fw_get = self.driver.get_firewall(
+                        ctx, VSE_ID)
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fw_get['firewall_rule_list'],
+                        fw_expect['firewall_rule_list'])
+                    # test insert in the middle of the list using
+                    # insert_after
+                    fwr4_id = fwr[4]['firewall_rule']['id']
+                    self._rule_action('insert', fwp_id, fwr4_id,
+                                      insert_before=None,
+                                      insert_after=fwr3_id,
+                                      expected_code=webob.exc.HTTPOk.code)
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+
+                    rule_info = {'firewall_rule_id': fwr4_id,
+                                 'insert_before': None,
+                                 'insert_after': fwr3_id}
+                    rule = fwr[4]['firewall_rule']
+                    self.driver.insert_rule(ctx, rule_info, VSE_ID, rule)
+                    fw_get = self.driver.get_firewall(
+                        ctx, VSE_ID)
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fw_get['firewall_rule_list'],
+                        fw_expect['firewall_rule_list'])
+                    # test insert when both insert_before and
+                    # insert_after are set
+                    fwr5_id = fwr[5]['firewall_rule']['id']
+                    self._rule_action('insert', fwp_id, fwr5_id,
+                                      insert_before=fwr4_id,
+                                      insert_after=fwr4_id,
+                                      expected_code=webob.exc.HTTPOk.code)
+                    fw_expect = self._make_firewall_dict_with_rules(
+                        ctx, fw_create['id'])
+
+                    rule_info = {'firewall_rule_id': fwr5_id,
+                                 'insert_before': fwr4_id,
+                                 'insert_after': fwr4_id}
+                    rule = fwr[5]['firewall_rule']
+                    self.driver.insert_rule(ctx, rule_info, VSE_ID, rule)
+                    fw_get = self.driver.get_firewall(
+                        ctx, VSE_ID)
+                    self._compare_firewall_rule_lists(
+                        fwp_id, fw_get['firewall_rule_list'],
+                        fw_expect['firewall_rule_list'])
index 1819f2c7f34e58f927387428428644d0d7800782..19fc89496707d1706c2ddecd2facf5a40df6a837 100644 (file)
@@ -1653,14 +1653,15 @@ class L3AgentDbTestCaseBase(L3NatTestCaseMixin):
 
 class L3BaseForIntTests(test_db_plugin.NeutronDbPluginV2TestCase):
 
-    def setUp(self, plugin=None, ext_mgr=None):
+    def setUp(self, plugin=None, ext_mgr=None, service_plugins=None):
         test_config['plugin_name_v2'] = (
             'neutron.tests.unit.test_l3_plugin.TestL3NatIntPlugin')
         # for these tests we need to enable overlapping ips
         cfg.CONF.set_default('allow_overlapping_ips', True)
         ext_mgr = ext_mgr or L3TestExtensionManager()
         test_config['extension_manager'] = ext_mgr
-        super(L3BaseForIntTests, self).setUp(plugin=plugin, ext_mgr=ext_mgr)
+        super(L3BaseForIntTests, self).setUp(plugin=plugin, ext_mgr=ext_mgr,
+                                             service_plugins=service_plugins)
 
         # Set to None to reload the drivers
         notifier_api._drivers = None
index 295914a906c9f9e927d05502186e9fa7a81ea651..da545a96c7353daa55e9e34182882ef9496f779e 100644 (file)
@@ -52,8 +52,8 @@ class RouterServiceInsertionTestPlugin(
     db_base_plugin_v2.NeutronDbPluginV2):
 
     supported_extension_aliases = [
-        "router", "router-service-type",
-        "routed-service-insertion", "service-type", "lbaas"
+        "router", "router-service-type", "routed-service-insertion",
+        "service-type", "lbaas"
     ]
 
     def create_router(self, context, router):
@@ -104,7 +104,7 @@ class RouterServiceInsertionTestPlugin(
         o = method(context, id, fields)
         if fields is None or rsi.ROUTER_ID in fields:
             rsbind = self._get_resource_router_id_binding(
-                context, id, model)
+                context, model, id)
             if rsbind:
                 o[rsi.ROUTER_ID] = rsbind['router_id']
         return o
@@ -116,7 +116,7 @@ class RouterServiceInsertionTestPlugin(
                              method_name)
             method(context, id)
             self._delete_resource_router_id_binding(context, id, model)
-        if self._get_resource_router_id_binding(context, id, model):
+        if self._get_resource_router_id_binding(context, model, id):
             raise Exception("{0}-router binding is not deleted".format(res))
 
     def create_pool(self, context, pool):