From: berlin Date: Thu, 22 Aug 2013 07:58:58 +0000 (+0800) Subject: Support for NVP advanced FwaaS service X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=db9c24a5194c7b11c1720227808f87add44375ed;p=openstack-build%2Fneutron-build.git Support for NVP advanced FwaaS service 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 --- 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 index 000000000..19c08a7f2 --- /dev/null +++ b/neutron/db/migration/alembic_migrations/versions/3ed8f075e38a_nvp_fwaas_plugin.py @@ -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') diff --git a/neutron/db/routedserviceinsertion_db.py b/neutron/db/routedserviceinsertion_db.py index e8c7af144..12f32e1e7 100644 --- a/neutron/db/routedserviceinsertion_db.py +++ b/neutron/db/routedserviceinsertion_db.py @@ -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) diff --git a/neutron/extensions/routedserviceinsertion.py b/neutron/extensions/routedserviceinsertion.py index b39625347..fc84c0166 100644 --- a/neutron/extensions/routedserviceinsertion.py +++ b/neutron/extensions/routedserviceinsertion.py @@ -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}, + } } diff --git a/neutron/plugins/nicira/NeutronServicePlugin.py b/neutron/plugins/nicira/NeutronServicePlugin.py index 211be7132..7161341ed 100644 --- a/neutron/plugins/nicira/NeutronServicePlugin.py +++ b/neutron/plugins/nicira/NeutronServicePlugin.py @@ -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 @@ -18,13 +18,16 @@ 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 diff --git a/neutron/plugins/nicira/common/exceptions.py b/neutron/plugins/nicira/common/exceptions.py index 21743b6d1..7da4b3323 100644 --- a/neutron/plugins/nicira/common/exceptions.py +++ b/neutron/plugins/nicira/common/exceptions.py @@ -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") diff --git a/neutron/plugins/nicira/dbexts/vcns_db.py b/neutron/plugins/nicira/dbexts/vcns_db.py index 9d7daaa61..f223eca4c 100644 --- a/neutron/plugins/nicira/dbexts/vcns_db.py +++ b/neutron/plugins/nicira/dbexts/vcns_db.py @@ -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() diff --git a/neutron/plugins/nicira/dbexts/vcns_models.py b/neutron/plugins/nicira/dbexts/vcns_models.py index fe96d245c..e2be5f953 100644 --- a/neutron/plugins/nicira/dbexts/vcns_models.py +++ b/neutron/plugins/nicira/dbexts/vcns_models.py @@ -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)) diff --git a/neutron/plugins/nicira/vshield/__init__.py b/neutron/plugins/nicira/vshield/__init__.py index c020e3bcd..fc51d2002 100644 --- a/neutron/plugins/nicira/vshield/__init__.py +++ b/neutron/plugins/nicira/vshield/__init__.py @@ -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 diff --git a/neutron/plugins/nicira/vshield/common/exceptions.py b/neutron/plugins/nicira/vshield/common/exceptions.py index 2e4b210e1..346359af1 100644 --- a/neutron/plugins/nicira/vshield/common/exceptions.py +++ b/neutron/plugins/nicira/vshield/common/exceptions.py @@ -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 index 000000000..a84a9b5c7 --- /dev/null +++ b/neutron/plugins/nicira/vshield/edge_firewall_driver.py @@ -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) diff --git a/neutron/plugins/nicira/vshield/vcns.py b/neutron/plugins/nicira/vshield/vcns.py index b02a97c2c..beace318d 100644 --- a/neutron/plugins/nicira/vshield/vcns.py +++ b/neutron/plugins/nicira/vshield/vcns.py @@ -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 diff --git a/neutron/plugins/nicira/vshield/vcns_driver.py b/neutron/plugins/nicira/vshield/vcns_driver.py index f5f69037c..8178744a9 100644 --- a/neutron/plugins/nicira/vshield/vcns_driver.py +++ b/neutron/plugins/nicira/vshield/vcns_driver.py @@ -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) diff --git a/neutron/tests/unit/db/firewall/test_db_firewall.py b/neutron/tests/unit/db/firewall/test_db_firewall.py index 4c204e371..c2d32b62c 100644 --- a/neutron/tests/unit/db/firewall/test_db_firewall.py +++ b/neutron/tests/unit/db/firewall/test_db_firewall.py @@ -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, diff --git a/neutron/tests/unit/nicira/__init__.py b/neutron/tests/unit/nicira/__init__.py index 62b27ecf9..89a6abcda 100644 --- a/neutron/tests/unit/nicira/__init__.py +++ b/neutron/tests/unit/nicira/__init__.py @@ -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): diff --git a/neutron/tests/unit/nicira/test_edge_router.py b/neutron/tests/unit/nicira/test_edge_router.py index f5dc6971b..f2deff614 100644 --- a/neutron/tests/unit/nicira/test_edge_router.py +++ b/neutron/tests/unit/nicira/test_edge_router.py @@ -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 index 000000000..d1f65aec9 --- /dev/null +++ b/neutron/tests/unit/nicira/test_fwaas_plugin.py @@ -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) diff --git a/neutron/tests/unit/nicira/test_nicira_plugin.py b/neutron/tests/unit/nicira/test_nicira_plugin.py index ec2dadda6..adc6bcee8 100644 --- a/neutron/tests/unit/nicira/test_nicira_plugin.py +++ b/neutron/tests/unit/nicira/test_nicira_plugin.py @@ -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 index 5e8da711f..000000000 --- a/neutron/tests/unit/nicira/vshield/common/__init__.py +++ /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. diff --git a/neutron/tests/unit/nicira/vshield/fake_vcns.py b/neutron/tests/unit/nicira/vshield/fake_vcns.py index cfc9137d6..3435c3b46 100644 --- a/neutron/tests/unit/nicira/vshield/fake_vcns.py +++ b/neutron/tests/unit/nicira/vshield/fake_vcns.py @@ -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 index 000000000..26705dd3c --- /dev/null +++ b/neutron/tests/unit/nicira/vshield/test_firewall_driver.py @@ -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']) diff --git a/neutron/tests/unit/test_l3_plugin.py b/neutron/tests/unit/test_l3_plugin.py index 1819f2c7f..19fc89496 100644 --- a/neutron/tests/unit/test_l3_plugin.py +++ b/neutron/tests/unit/test_l3_plugin.py @@ -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 diff --git a/neutron/tests/unit/test_routerserviceinsertion.py b/neutron/tests/unit/test_routerserviceinsertion.py index 295914a90..da545a96c 100644 --- a/neutron/tests/unit/test_routerserviceinsertion.py +++ b/neutron/tests/unit/test_routerserviceinsertion.py @@ -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):