FWaaS Insertion Model on Routers

Implementation for FWaaS insertion model to associate a Firewall
with specified Routers as opposed to the current model of association
with all Routers in the tenant.

- extension and new table tracking associated routers
- plugin changes to manage router association
- changes to plugin - agent interface (adding router associations)
- fw agent changes to pick up router associations from plugin
- UT changes
- Upgrade script

APIImpact
DocImpact

Change-Id: I0eba4b0aa127738397e6b9c45556e207216d79c7
Implements: blueprint fwaas-router-insertion
This commit is contained in:
Sridar Kandaswamy 2015-02-03 13:53:13 -08:00
parent d735611981
commit d0704f0560
9 changed files with 988 additions and 436 deletions

View File

@ -27,7 +27,7 @@ from sqlalchemy.ext.orderinglist import ordering_list
from sqlalchemy import orm
from sqlalchemy.orm import exc
from neutron_fwaas.extensions import firewall
from neutron_fwaas.extensions import firewall as fw_ext
LOG = logging.getLogger(__name__)
@ -83,7 +83,7 @@ class FirewallPolicy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
firewalls = orm.relationship(Firewall, backref='firewall_policies')
class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
class Firewall_db_mixin(fw_ext.FirewallPluginBase, base_db.CommonDbMixin):
"""Mixin class for Firewall DB implementation."""
@property
@ -94,19 +94,19 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
try:
return self._get_by_id(context, Firewall, id)
except exc.NoResultFound:
raise firewall.FirewallNotFound(firewall_id=id)
raise fw_ext.FirewallNotFound(firewall_id=id)
def _get_firewall_policy(self, context, id):
try:
return self._get_by_id(context, FirewallPolicy, id)
except exc.NoResultFound:
raise firewall.FirewallPolicyNotFound(firewall_policy_id=id)
raise fw_ext.FirewallPolicyNotFound(firewall_policy_id=id)
def _get_firewall_rule(self, context, id):
try:
return self._get_by_id(context, FirewallRule, id)
except exc.NoResultFound:
raise firewall.FirewallRuleNotFound(firewall_rule_id=id)
raise fw_ext.FirewallRuleNotFound(firewall_rule_id=id)
def _make_firewall_dict(self, fw, fields=None):
res = {'id': fw['id'],
@ -180,7 +180,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
def _check_firewall_rule_conflict(self, fwr_db, fwp_db):
if not fwr_db['shared']:
if fwr_db['tenant_id'] != fwp_db['tenant_id']:
raise firewall.FirewallRuleConflict(
raise fw_ext.FirewallRuleConflict(
firewall_rule_id=fwr_db['id'],
tenant_id=fwr_db['tenant_id'])
@ -202,20 +202,20 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
# If we find an invalid rule in the list we
# do not perform the update since this breaks
# the integrity of this list.
raise firewall.FirewallRuleNotFound(
raise fw_ext.FirewallRuleNotFound(
firewall_rule_id=fwrule_id)
elif rules_dict[fwrule_id]['firewall_policy_id']:
if (rules_dict[fwrule_id]['firewall_policy_id'] !=
fwp_db['id']):
raise firewall.FirewallRuleInUse(
raise fw_ext.FirewallRuleInUse(
firewall_rule_id=fwrule_id)
if 'shared' in fwp:
if fwp['shared'] and not rules_dict[fwrule_id]['shared']:
raise firewall.FirewallRuleSharingConflict(
raise fw_ext.FirewallRuleSharingConflict(
firewall_rule_id=fwrule_id,
firewall_policy_id=fwp_db['id'])
elif fwp_db['shared'] and not rules_dict[fwrule_id]['shared']:
raise firewall.FirewallRuleSharingConflict(
raise fw_ext.FirewallRuleSharingConflict(
firewall_rule_id=fwrule_id,
firewall_policy_id=fwp_db['id'])
for fwr_db in rules_in_db:
@ -235,7 +235,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
rules_in_db = fwp_db['firewall_rules']
for fwr_db in rules_in_db:
if not fwr_db['shared']:
raise firewall.FirewallPolicySharingConflict(
raise fw_ext.FirewallPolicySharingConflict(
firewall_rule_id=fwr_db['id'],
firewall_policy_id=fwp_db['id'])
@ -275,18 +275,19 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
protocol = fwr['protocol']
if protocol not in (const.TCP, const.UDP):
if fwr['source_port'] or fwr['destination_port']:
raise firewall.FirewallRuleInvalidICMPParameter(
raise fw_ext.FirewallRuleInvalidICMPParameter(
param="Source, destination port")
def create_firewall(self, context, firewall):
def create_firewall(self, context, firewall, status=None):
LOG.debug("create_firewall() called")
fw = firewall['firewall']
tenant_id = self._get_tenant_id_for_create(context, fw)
# distributed routers may required a more complex state machine;
# the introduction of a new 'CREATED' state allows this, whilst
# keeping a backward compatible behavior of the logical resource.
status = (const.CREATED
if cfg.CONF.router_distributed else const.PENDING_CREATE)
if not status:
status = (const.CREATED if cfg.CONF.router_distributed
else const.PENDING_CREATE)
with context.session.begin(subtransactions=True):
firewall_db = Firewall(
id=uuidutils.generate_uuid(),
@ -305,7 +306,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
with context.session.begin(subtransactions=True):
count = context.session.query(Firewall).filter_by(id=id).update(fw)
if not count:
raise firewall.FirewallNotFound(firewall_id=id)
raise fw_ext.FirewallNotFound(firewall_id=id)
return self.get_firewall(context, id)
def delete_firewall(self, context, id):
@ -315,7 +316,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
# firewall is active
count = context.session.query(Firewall).filter_by(id=id).delete()
if not count:
raise firewall.FirewallNotFound(firewall_id=id)
raise fw_ext.FirewallNotFound(firewall_id=id)
def get_firewall(self, context, id, fields=None):
LOG.debug("get_firewall() called")
@ -357,7 +358,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
if not fwp.get('shared', True) and fwp_db.firewalls:
for fw in fwp_db['firewalls']:
if fwp_db['tenant_id'] != fw['tenant_id']:
raise firewall.FirewallPolicyInUse(
raise fw_ext.FirewallPolicyInUse(
firewall_policy_id=id)
# check any existing rules are not shared
if 'shared' in fwp and 'firewall_rules' not in fwp:
@ -378,7 +379,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
# being used
qry = context.session.query(Firewall)
if qry.filter_by(firewall_policy_id=id).first():
raise firewall.FirewallPolicyInUse(firewall_policy_id=id)
raise fw_ext.FirewallPolicyInUse(firewall_policy_id=id)
else:
context.session.delete(fwp)
@ -405,7 +406,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
tenant_id = self._get_tenant_id_for_create(context, fwr)
if not fwr['protocol'] and (fwr['source_port'] or
fwr['destination_port']):
raise firewall.FirewallRuleWithPortWithoutProtocolInvalid()
raise fw_ext.FirewallRuleWithPortWithoutProtocolInvalid()
src_port_min, src_port_max = self._get_min_max_ports_from_range(
fwr['source_port'])
dst_port_min, dst_port_max = self._get_min_max_ports_from_range(
@ -439,7 +440,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
fwr_db.firewall_policy_id)
if 'shared' in fwr and not fwr['shared']:
if fwr_db['tenant_id'] != fwp_db['tenant_id']:
raise firewall.FirewallRuleInUse(firewall_rule_id=id)
raise fw_ext.FirewallRuleInUse(firewall_rule_id=id)
if 'source_port' in fwr:
src_port_min, src_port_max = self._get_min_max_ports_from_range(
fwr['source_port'])
@ -460,7 +461,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
dport = fwr.get('destination_port_range_min',
fwr_db['destination_port_range_min'])
if sport or dport:
raise firewall.FirewallRuleWithPortWithoutProtocolInvalid()
raise fw_ext.FirewallRuleWithPortWithoutProtocolInvalid()
fwr_db.update(fwr)
if fwr_db.firewall_policy_id:
fwp_db.audited = False
@ -471,7 +472,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
with context.session.begin(subtransactions=True):
fwr = self._get_firewall_rule(context, id)
if fwr.firewall_policy_id:
raise firewall.FirewallRuleInUse(firewall_rule_id=id)
raise fw_ext.FirewallRuleInUse(firewall_rule_id=id)
context.session.delete(fwr)
def get_firewall_rule(self, context, id, fields=None):
@ -492,7 +493,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
def _validate_insert_remove_rule_request(self, id, rule_info):
if not rule_info or 'firewall_rule_id' not in rule_info:
raise firewall.FirewallRuleInfoMissing()
raise fw_ext.FirewallRuleInfoMissing()
def insert_rule(self, context, id, rule_info):
LOG.debug("insert_rule() called")
@ -501,7 +502,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
insert_before = True
ref_firewall_rule_id = None
if not firewall_rule_id:
raise firewall.FirewallRuleNotFound(firewall_rule_id=None)
raise fw_ext.FirewallRuleNotFound(firewall_rule_id=None)
if 'insert_before' in rule_info:
ref_firewall_rule_id = rule_info['insert_before']
if not ref_firewall_rule_id and 'insert_after' in rule_info:
@ -512,7 +513,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
fwr_db = self._get_firewall_rule(context, firewall_rule_id)
fwp_db = self._get_firewall_policy(context, id)
if fwr_db.firewall_policy_id:
raise firewall.FirewallRuleInUse(firewall_rule_id=fwr_db['id'])
raise fw_ext.FirewallRuleInUse(firewall_rule_id=fwr_db['id'])
self._check_firewall_rule_conflict(fwr_db, fwp_db)
if ref_firewall_rule_id:
# If reference_firewall_rule_id is set, the new rule
@ -523,7 +524,7 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
ref_fwr_db = self._get_firewall_rule(
context, ref_firewall_rule_id)
if ref_fwr_db.firewall_policy_id != id:
raise firewall.FirewallRuleNotAssociatedWithPolicy(
raise fw_ext.FirewallRuleNotAssociatedWithPolicy(
firewall_rule_id=ref_fwr_db['id'],
firewall_policy_id=id)
if insert_before:
@ -545,11 +546,11 @@ class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
self._validate_insert_remove_rule_request(id, rule_info)
firewall_rule_id = rule_info['firewall_rule_id']
if not firewall_rule_id:
raise firewall.FirewallRuleNotFound(firewall_rule_id=None)
raise fw_ext.FirewallRuleNotFound(firewall_rule_id=None)
with context.session.begin(subtransactions=True):
fwr_db = self._get_firewall_rule(context, firewall_rule_id)
if fwr_db.firewall_policy_id != id:
raise firewall.FirewallRuleNotAssociatedWithPolicy(
raise fw_ext.FirewallRuleNotAssociatedWithPolicy(
firewall_rule_id=fwr_db['id'],
firewall_policy_id=id)
return self._process_rule_for_policy(context, id, fwr_db, None)

View File

@ -0,0 +1,99 @@
# Copyright 2015 Cisco Systems 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 sqlalchemy as sa
from neutron.common import log
from neutron.db import model_base
from oslo_log import log as logging
from neutron_fwaas.extensions import firewallrouterinsertion as fwrtrins
LOG = logging.getLogger(__name__)
class FirewallRouterAssociation(model_base.BASEV2):
"""Tracks FW Router Association"""
__tablename__ = 'firewall_router_associations'
fw_id = sa.Column(sa.String(36),
sa.ForeignKey('firewalls.id', ondelete="CASCADE"),
primary_key=True)
router_id = sa.Column(sa.String(36),
sa.ForeignKey('routers.id', ondelete="CASCADE"),
primary_key=True)
class FirewallRouterInsertionDbMixin(object):
"""Access methods for the firewall_router_associations table."""
@log.log
def set_routers_for_firewall(self, context, fw):
"""Sets the routers associated with the fw."""
with context.session.begin(subtransactions=True):
for r_id in fw['router_ids']:
fw_rtr_db = FirewallRouterAssociation(fw_id=fw['fw_id'],
router_id=r_id)
context.session.add(fw_rtr_db)
@log.log
def get_firewall_routers(self, context, fwid):
"""Gets all routers associated with a firewall."""
with context.session.begin(subtransactions=True):
fw_rtr_qry = context.session.query(
FirewallRouterAssociation.router_id)
fw_rtr_rows = fw_rtr_qry.filter_by(fw_id=fwid)
fw_rtrs = [entry.router_id for entry in fw_rtr_rows]
LOG.debug("get_firewall_routers(): fw_rtrs: %s", fw_rtrs)
return fw_rtrs
@log.log
def validate_firewall_routers_not_in_use(
self, context, router_ids, fwid=None):
"""Validate if router-ids not associated with any firewall.
If any of the router-ids in the list is already associated with
a firewall, raise an exception else just return.
"""
fw_rtr_qry = context.session.query(FirewallRouterAssociation.router_id)
fw_rtrs = fw_rtr_qry.filter(
FirewallRouterAssociation.router_id.in_(router_ids),
FirewallRouterAssociation.fw_id != fwid).all()
if fw_rtrs:
router_ids = [entry.router_id for entry in fw_rtrs]
raise fwrtrins.FirewallRouterInUse(router_ids=router_ids)
@log.log
def update_firewall_routers(self, context, fw):
"""Update the firewall with new routers.
This involves removing existing router associations and replacing
it with the new router associations provided in the update method.
"""
with context.session.begin(subtransactions=True):
fw_rtr_qry = context.session.query(FirewallRouterAssociation)
fw_rtr_qry.filter_by(fw_id=fw['fw_id']).delete()
if fw['router_ids']:
self.set_routers_for_firewall(context, fw)
# TODO(sridar): Investigate potential corner case if rpc failure
# happens on PENDING_UPDATE and agent did not restart. Evaluate
# complexity vs benefit of holding on to old entries until ack
# from agent.
return fw

View File

@ -0,0 +1,56 @@
# Copyright 2014 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.
#
"""FWaaS router insertion
Revision ID: 540142f314f4
Revises: 4202e3047e47
Create Date: 2015-02-06 17:02:24.279337
"""
# revision identifiers, used by Alembic.
revision = '540142f314f4'
down_revision = '4202e3047e47'
from alembic import op
import sqlalchemy as sa
SQL_STATEMENT = (
"insert into firewall_router_associations "
"select "
"f.id as fw_id, r.id as router_id "
"from firewalls f, routers r "
"where "
"f.tenant_id=r.tenant_id"
)
def upgrade():
op.create_table('firewall_router_associations',
sa.Column('fw_id', sa.String(length=36), nullable=False),
sa.Column('router_id', sa.String(length=36), nullable=False),
sa.ForeignKeyConstraint(['fw_id'], ['firewalls.id'],
ondelete='CASCADE'),
sa.ForeignKeyConstraint(['router_id'], ['routers.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('fw_id', 'router_id'),
)
op.execute(SQL_STATEMENT)
def downgrade():
op.drop_table('firewall_router_associations')

View File

@ -1 +1 @@
start_neutron_fwaas
540142f314f4

View File

@ -0,0 +1,82 @@
# Copyright 2015 Cisco Systems Inc.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.api import extensions
from neutron.api.v2 import attributes as attr
from neutron.common import exceptions as nexception
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
class FirewallRouterInUse(nexception.InUse):
message = _("Router(s) %(router_ids)s provided already associated with "
"other Firewall(s). ")
EXTENDED_ATTRIBUTES_2_0 = {
'firewalls': {
'router_ids': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_list': None},
'is_visible': True, 'default': attr.ATTR_NOT_SPECIFIED},
}
}
class Firewallrouterinsertion(extensions.ExtensionDescriptor):
"""Extension class supporting Firewall and Router(s) association.
The extension enables providing an option to specify router-ids of
routers where the firewall is to be installed. This is supported in
a manner so that the older version of the API continues to be supported.
On a CREATE, if the router_ids option is not specified then the firewall
is installed on all routers on the tenant. If the router-ids option is
provided with a list of routers then the firewall is installed on the
specified routers. If the router-ids option is provided with an empty
list then the firewall is created but put in an INACTIVE state to reflect
that no routers are associated. This firewall can be updated with a list
of routers which will then drive the state to ACTIVE after the agent
installs and acks back. UPDATE also supports the option in a similar
manner. If the router_ids option is not provided, then there is no change
to the existing association with the routers. When the router_is option is
provided with a list of routers or an empty list - this drives the new
set of routers that the firewall is associated with.
"""
@classmethod
def get_name(cls):
return "Firewall Router insertion"
@classmethod
def get_alias(cls):
return "fwaasrouterinsertion"
@classmethod
def get_description(cls):
return "Firewall Router insertion on specified set of routers"
@classmethod
def get_namespace(cls):
return ("http://docs.openstack.org/ext/neutron/fwaasrouterinsertion"
"/api/v1.0")
@classmethod
def get_updated(cls):
return "2015-01-27T10:00:00-00:00"
def get_extended_resources(self, version):
if version == "2.0":
return EXTENDED_ATTRIBUTES_2_0
else:
return {}

View File

@ -14,6 +14,7 @@
# under the License.
from neutron.agent.linux import ip_lib
from neutron.common import log
from neutron.common import topics
from neutron import context
from neutron.i18n import _LE
@ -30,7 +31,6 @@ LOG = logging.getLogger(__name__)
class FWaaSL3PluginApi(api.FWaaSPluginApiMixin):
"""Agent side of the FWaaS agent to FWaaS Plugin RPC API."""
def __init__(self, topic, host):
super(FWaaSL3PluginApi, self).__init__(topic, host)
@ -73,20 +73,39 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
self.fw_service = firewall_service.FirewallService(self)
self.event_observers.add(self.fw_service)
self.fwaas_driver = self.fw_service.load_device_drivers()
self.services_sync = False
self.services_sync_needed = False
# setup RPC to msg fwaas plugin
self.fwplugin_rpc = FWaaSL3PluginApi(topics.FIREWALL_PLUGIN,
conf.host)
super(FWaaSL3AgentRpcCallback, self).__init__(host=conf.host)
def _get_router_info_list_for_tenant(self, routers, tenant_id):
def _has_router_insertion_fields(self, fw):
return 'add-router-ids' in fw
def _get_router_ids_for_fw(self, context, fw, to_delete=False):
"""Return the router_ids either from fw dict or tenant routers."""
if self._has_router_insertion_fields(fw):
# it is a new version of plugin
return (fw['del-router-ids'] if to_delete
else fw['add-router-ids'])
else:
# we are in a upgrade and msg from older version of plugin
try:
routers = self.plugin_rpc.get_routers(context)
except Exception:
LOG.exception(
_LE("FWaaS RPC failure in _get_router_ids_for_fw "
"for firewall: %(fwid)s"),
{'fwid': fw['id']})
self.services_sync_needed = True
return [
router['id']
for router in routers
if router['tenant_id'] == fw['tenant_id']]
def _get_router_info_list_for_tenant(self, router_ids, tenant_id):
"""Returns the list of router info objects on which to apply the fw."""
root_ip = ip_lib.IPWrapper()
# Get the routers for the tenant
router_ids = [
router['id']
for router in routers
if router['tenant_id'] == tenant_id]
local_ns_list = (root_ip.get_namespaces()
if self.conf.use_namespaces else [])
@ -105,56 +124,6 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
router_info_list.append(self.router_info[rid])
return router_info_list
def _invoke_driver_for_plugin_api(self, context, fw, func_name):
"""Invoke driver method for plugin API and provide status back."""
LOG.debug("%(func_name)s from agent for fw: %(fwid)s",
{'func_name': func_name, 'fwid': fw['id']})
try:
routers = self.plugin_rpc.get_routers(context)
router_info_list = self._get_router_info_list_for_tenant(
routers,
fw['tenant_id'])
if not router_info_list:
LOG.debug('No Routers on tenant: %s', fw['tenant_id'])
# fw was created before any routers were added, and if a
# delete is sent then we need to ack so that plugin can
# cleanup.
if func_name == 'delete_firewall':
self.fwplugin_rpc.firewall_deleted(context, fw['id'])
return
LOG.debug("Apply fw on Router List: '%s'",
[ri.router['id'] for ri in router_info_list])
# call into the driver
try:
self.fwaas_driver.__getattribute__(func_name)(
self.conf.agent_mode,
router_info_list,
fw)
if fw['admin_state_up']:
status = constants.ACTIVE
else:
status = constants.DOWN
except fw_ext.FirewallInternalDriverError:
LOG.error(_LE("Firewall Driver Error for %(func_name)s "
"for fw: %(fwid)s"),
{'func_name': func_name, 'fwid': fw['id']})
status = constants.ERROR
# delete needs different handling
if func_name == 'delete_firewall':
if status in [constants.ACTIVE, constants.DOWN]:
self.fwplugin_rpc.firewall_deleted(context, fw['id'])
else:
self.fwplugin_rpc.set_firewall_status(
context,
fw['id'],
status)
except Exception:
LOG.exception(
_LE("FWaaS RPC failure in %(func_name)s for fw: %(fwid)s"),
{'func_name': func_name, 'fwid': fw['id']})
self.services_sync = True
return
def _invoke_driver_for_sync_from_plugin(self, ctx, router_info_list, fw):
"""Invoke the delete driver method for status of PENDING_DELETE and
update method for all other status to (re)apply on driver which is
@ -202,39 +171,50 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
def _process_router_add(self, ri):
"""On router add, get fw with rules from plugin and update driver."""
LOG.debug("Process router add, router_id: '%s'", ri.router['id'])
routers = []
routers.append(ri.router)
router_ids = ri.router['id']
router_info_list = self._get_router_info_list_for_tenant(
routers,
[router_ids],
ri.router['tenant_id'])
if router_info_list:
# Get the firewall with rules
# for the tenant the router is on.
ctx = context.Context('', ri.router['tenant_id'])
fw_list = self.fwplugin_rpc.get_firewalls_for_tenant(ctx)
LOG.debug("Process router add, fw_list: '%s'",
[fw['id'] for fw in fw_list])
for fw in fw_list:
if self._has_router_insertion_fields(fw):
# if router extension present apply only if router in fw
if (not (router_ids in fw['add-router-ids']) and
not (router_ids in fw['del-router-ids'])):
continue
self._invoke_driver_for_sync_from_plugin(
ctx,
router_info_list,
fw)
# router can be present only on one fw
return
def process_router_add(self, ri):
"""On router add, get fw with rules from plugin and update driver."""
"""On router add, get fw with rules from plugin and update driver.
Handles agent restart, when a router is added, query the plugin to
check if this router is in the router list for any firewall. If so
install firewall rules on this router.
"""
# avoid msg to plugin when fwaas is not configured
if not self.fwaas_enabled:
return
try:
# TODO(sridar): as per discussion with pc_m, we may want to hook
# this up to the l3 agent observer notification
self._process_router_add(ri)
except Exception:
LOG.exception(
_LE("FWaaS RPC info call failed for '%s'."),
ri.router['id'])
self.services_sync = True
self.services_sync_needed = True
def process_services_sync(self, ctx):
if not self.services_sync:
if not self.services_sync_needed:
return
"""On RPC issues sync with plugin and apply the sync data."""
@ -242,8 +222,6 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
if not self.fwaas_enabled:
return
try:
# get all routers
routers = self.plugin_rpc.get_routers(ctx)
# get the list of tenants with firewalls configured
# from the plugin
tenant_ids = self.fwplugin_rpc.get_tenants_with_firewalls(ctx)
@ -251,51 +229,174 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
for tenant_id in tenant_ids:
ctx = context.Context('', tenant_id)
fw_list = self.fwplugin_rpc.get_firewalls_for_tenant(ctx)
if fw_list:
# if fw present on tenant
router_info_list = self._get_router_info_list_for_tenant(
routers,
tenant_id)
if router_info_list:
LOG.debug("Router List: '%s'",
[ri.router['id'] for ri in router_info_list])
LOG.debug("fw_list: '%s'",
[fw['id'] for fw in fw_list])
# apply sync data on fw for this tenant
for fw in fw_list:
# fw, routers present on this host for tenant
# install
LOG.debug("Apply fw on Router List: '%s'",
[ri.router['id']
for ri in router_info_list])
# no need to apply sync data for ACTIVE fw
if fw['status'] != constants.ACTIVE:
self._invoke_driver_for_sync_from_plugin(
ctx,
router_info_list,
fw)
self.services_sync = False
for fw in fw_list:
if fw['status'] == constants.PENDING_DELETE:
self.delete_firewall(ctx, fw, self.host)
# no need to apply sync data for ACTIVE fw
elif fw['status'] != constants.ACTIVE:
self.update_firewall(ctx, fw, self.host)
self.services_sync_needed = False
except Exception:
LOG.exception(_LE("Failed fwaas process services sync"))
self.services_sync = True
self.services_sync_needed = True
@log.log
def create_firewall(self, context, firewall, host):
"""Handle Rpc from plugin to create a firewall."""
return self._invoke_driver_for_plugin_api(
context,
firewall,
'create_firewall')
router_ids = self._get_router_ids_for_fw(context, firewall)
if not router_ids:
return
router_info_list = self._get_router_info_list_for_tenant(
router_ids,
firewall['tenant_id'])
LOG.debug("Create: Add firewall on Router List: '%s'",
[ri.router['id'] for ri in router_info_list])
# call into the driver
try:
self.fwaas_driver.create_firewall(
self.conf.agent_mode,
router_info_list,
firewall)
if firewall['admin_state_up']:
status = constants.ACTIVE
else:
status = constants.DOWN
except fw_ext.FirewallInternalDriverError:
LOG.error(_LE("Firewall Driver Error for create_firewall "
"for firewall: %(fwid)s"),
{'fwid': firewall['id']})
status = constants.ERROR
try:
# send status back to plugin
self.fwplugin_rpc.set_firewall_status(
context,
firewall['id'],
status)
except Exception:
LOG.exception(
_LE("FWaaS RPC failure in create_firewall "
"for firewall: %(fwid)s"),
{'fwid': firewall['id']})
self.services_sync_needed = True
@log.log
def update_firewall(self, context, firewall, host):
"""Handle Rpc from plugin to update a firewall."""
return self._invoke_driver_for_plugin_api(
context,
firewall,
'update_firewall')
status = ""
if self._has_router_insertion_fields(firewall):
# with the router_ids extension, we may need to delete and add
# based on the list of routers. On the older version, we just
# update (add) all routers on the tenant - delete not needed.
router_ids = self._get_router_ids_for_fw(
context, firewall, to_delete=True)
if router_ids:
router_info_list = self._get_router_info_list_for_tenant(
router_ids,
firewall['tenant_id'])
# remove the firewall from this set of routers
# but no ack sent yet, check if we need to add
LOG.debug("Update: Delete firewall on Router List: '%s'",
[ri.router['id'] for ri in router_info_list])
try:
self.fwaas_driver.delete_firewall(
self.conf.agent_mode,
router_info_list,
firewall)
if firewall['last-router']:
status = constants.INACTIVE
elif firewall['admin_state_up']:
status = constants.ACTIVE
else:
status = constants.DOWN
except fw_ext.FirewallInternalDriverError:
LOG.error(_LE("Firewall Driver Error for "
"update_firewall for firewall: "
"%(fwid)s"),
{'fwid': firewall['id']})
status = constants.ERROR
# the add
if status not in (constants.ERROR, constants.INACTIVE):
router_ids = self._get_router_ids_for_fw(context, firewall)
if router_ids:
router_info_list = self._get_router_info_list_for_tenant(
router_ids,
firewall['tenant_id'])
LOG.debug("Update: Add firewall on Router List: '%s'",
[ri.router['id'] for ri in router_info_list])
# call into the driver
try:
self.fwaas_driver.update_firewall(
self.conf.agent_mode,
router_info_list,
firewall)
if firewall['admin_state_up']:
status = constants.ACTIVE
else:
status = constants.DOWN
except fw_ext.FirewallInternalDriverError:
LOG.error(_LE("Firewall Driver Error for "
"update_firewall for firewall: "
"%(fwid)s"),
{'fwid': firewall['id']})
status = constants.ERROR
try:
# send status back to plugin
self.fwplugin_rpc.set_firewall_status(
context,
firewall['id'],
status)
except Exception:
LOG.exception(
_LE("FWaaS RPC failure in update_firewall "
"for firewall: %(fwid)s"),
{'fwid': firewall['id']})
self.services_sync_needed = True
@log.log
def delete_firewall(self, context, firewall, host):
"""Handle Rpc from plugin to delete a firewall."""
return self._invoke_driver_for_plugin_api(
context,
firewall,
'delete_firewall')
router_ids = self._get_router_ids_for_fw(
context, firewall, to_delete=True)
if router_ids:
router_info_list = self._get_router_info_list_for_tenant(
router_ids,
firewall['tenant_id'])
LOG.debug("Delete: Delete firewall on Router List: '%s'",
[ri.router['id'] for ri in router_info_list])
# call into the driver
try:
self.fwaas_driver.delete_firewall(
self.conf.agent_mode,
router_info_list,
firewall)
if firewall['admin_state_up']:
status = constants.ACTIVE
else:
status = constants.DOWN
except fw_ext.FirewallInternalDriverError:
LOG.error(_LE("Firewall Driver Error for delete_firewall "
"for firewall: %(fwid)s"),
{'fwid': firewall['id']})
status = constants.ERROR
try:
# send status back to plugin
if status in [constants.ACTIVE, constants.DOWN]:
self.fwplugin_rpc.firewall_deleted(context, firewall['id'])
else:
self.fwplugin_rpc.set_firewall_status(
context,
firewall['id'],
status)
except Exception:
LOG.exception(
_LE("FWaaS RPC failure in delete_firewall "
"for firewall: %(fwid)s"),
{'fwid': firewall['id']})
self.services_sync_needed = True

View File

@ -13,17 +13,19 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron.common import exceptions as n_exception
from neutron.api.v2 import attributes as attr
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron import context as neutron_context
from neutron.i18n import _LW
from neutron import manager
from neutron.plugins.common import constants as const
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
from neutron_fwaas.db.firewall import firewall_db
from neutron_fwaas.db.firewall import firewall_router_insertion_db
from neutron_fwaas.extensions import firewall as fw_ext
@ -51,7 +53,7 @@ class FirewallCallbacks(object):
"not changing to %(status)s",
{'fw_id': firewall_id, 'status': status})
return False
if status in (const.ACTIVE, const.DOWN):
if status in (const.ACTIVE, const.DOWN, const.INACTIVE):
fw_db.status = status
return True
else:
@ -77,10 +79,19 @@ class FirewallCallbacks(object):
def get_firewalls_for_tenant(self, context, **kwargs):
"""Agent uses this to get all firewalls and rules for a tenant."""
LOG.debug("get_firewalls_for_tenant() called")
fw_list = [
self.plugin._make_firewall_dict_with_rules(context, fw['id'])
for fw in self.plugin.get_firewalls(context)
]
fw_list = []
for fw in self.plugin.get_firewalls(context):
fw_with_rules = self.plugin._make_firewall_dict_with_rules(
context, fw['id'])
if fw['status'] == const.PENDING_DELETE:
fw_with_rules['add-router-ids'] = []
fw_with_rules['del-router-ids'] = (
self.plugin.get_firewall_routers(context, fw['id']))
else:
fw_with_rules['add-router-ids'] = (
self.plugin.get_firewall_routers(context, fw['id']))
fw_with_rules['del-router-ids'] = []
fw_list.append(fw_with_rules)
return fw_list
def get_firewalls_for_tenant_without_rules(self, context, **kwargs):
@ -122,18 +133,9 @@ class FirewallAgentApi(object):
host=self.host)
class FirewallCountExceeded(n_exception.Conflict):
"""Reference implementation specific exception for firewall count.
Only one firewall is supported per tenant. When a second
firewall is tried to be created, this exception will be raised.
"""
message = _("Exceeded allowed count of firewalls for tenant "
"%(tenant_id)s. Only one firewall is supported per tenant.")
class FirewallPlugin(firewall_db.Firewall_db_mixin):
class FirewallPlugin(
firewall_db.Firewall_db_mixin,
firewall_router_insertion_db.FirewallRouterInsertionDbMixin):
"""Implementation of the Neutron Firewall Service Plugin.
@ -141,11 +143,10 @@ class FirewallPlugin(firewall_db.Firewall_db_mixin):
Most DB related works are implemented in class
firewall_db.Firewall_db_mixin.
"""
supported_extension_aliases = ["fwaas"]
supported_extension_aliases = ["fwaas", "fwaasrouterinsertion"]
def __init__(self):
"""Do the initialization for the firewall service plugin here."""
self.endpoints = [FirewallCallbacks(self)]
self.conn = n_rpc.create_connection(new=True)
@ -164,6 +165,11 @@ class FirewallPlugin(firewall_db.Firewall_db_mixin):
status_update)
fw_with_rules = self._make_firewall_dict_with_rules(context,
firewall_id)
# this is triggered on an update to fw rule or policy, no
# change in associated routers.
fw_with_rules['add-router-ids'] = self.get_firewall_routers(
context, id)
fw_with_rules['del-router-ids'] = []
self.agent_rpc.update_firewall(context, fw_with_rules)
def _rpc_update_firewall_policy(self, context, firewall_policy_id):
@ -192,28 +198,123 @@ class FirewallPlugin(firewall_db.Firewall_db_mixin):
self._ensure_update_firewall_policy(context,
fw_rule['firewall_policy_id'])
def _get_routers_for_create_firewall(self, tenant_id, context, firewall):
# pop router_id as this goes in the router association db
# and not firewall db
router_ids = firewall['firewall'].pop('router_ids', None)
if router_ids == attr.ATTR_NOT_SPECIFIED:
# old semantics router-ids keyword not specified pick up
# all routers on tenant.
l3_plugin = manager.NeutronManager.get_service_plugins().get(
const.L3_ROUTER_NAT)
ctx = neutron_context.get_admin_context()
routers = l3_plugin.get_routers(ctx)
router_ids = [
router['id']
for router in routers
if router['tenant_id'] == tenant_id]
# validation can still fail this if there is another fw
# which is associated with one of these routers.
self.validate_firewall_routers_not_in_use(context, router_ids)
return router_ids
else:
if not router_ids:
# This indicates that user specifies no routers.
return []
else:
# some router(s) provided.
self.validate_firewall_routers_not_in_use(context, router_ids)
return router_ids
def create_firewall(self, context, firewall):
LOG.debug("create_firewall() called")
tenant_id = self._get_tenant_id_for_create(context,
firewall['firewall'])
fw_count = self.get_firewalls_count(context,
filters={'tenant_id': [tenant_id]})
if fw_count:
raise FirewallCountExceeded(tenant_id=tenant_id)
fw = super(FirewallPlugin, self).create_firewall(context, firewall)
firewall['firewall'])
fw_new_rtrs = self._get_routers_for_create_firewall(
tenant_id, context, firewall)
if not fw_new_rtrs:
# no messaging to agent needed, and fw needs to go
# to INACTIVE(no associated rtrs) state.
status = const.INACTIVE
fw = super(FirewallPlugin, self).create_firewall(
context, firewall, status)
fw['router_ids'] = []
return fw
else:
fw = super(FirewallPlugin, self).create_firewall(
context, firewall)
fw['router_ids'] = fw_new_rtrs
fw_with_rules = (
self._make_firewall_dict_with_rules(context, fw['id']))
fw_with_rtrs = {'fw_id': fw['id'],
'router_ids': fw_new_rtrs}
self.set_routers_for_firewall(context, fw_with_rtrs)
fw_with_rules['add-router-ids'] = fw_new_rtrs
fw_with_rules['del-router-ids'] = []
self.agent_rpc.create_firewall(context, fw_with_rules)
return fw
def update_firewall(self, context, id, firewall):
LOG.debug("update_firewall() called")
self._ensure_update_firewall(context, id)
firewall['firewall']['status'] = const.PENDING_UPDATE
fw = super(FirewallPlugin, self).update_firewall(context, id, firewall)
# pop router_id as this goes in the router association db
# and not firewall db
router_ids = firewall['firewall'].pop('router_ids', None)
fw_current_rtrs = self.get_firewall_routers(context, id)
if router_ids is not None:
if router_ids == []:
# This indicates that user is indicating no routers.
fw_new_rtrs = []
else:
self.validate_firewall_routers_not_in_use(
context, router_ids, id)
fw_new_rtrs = router_ids
self.update_firewall_routers(context, {'fw_id': id,
'router_ids': fw_new_rtrs})
else:
# router-ids keyword not specified for update pick up
# existing routers.
fw_new_rtrs = self.get_firewall_routers(context, id)
if not fw_new_rtrs and not fw_current_rtrs:
# no messaging to agent needed, and we need to continue
# in INACTIVE state
firewall['firewall']['status'] = const.INACTIVE
fw = super(FirewallPlugin, self).update_firewall(
context, id, firewall)
fw['router_ids'] = []
return fw
else:
firewall['firewall']['status'] = const.PENDING_UPDATE
fw = super(FirewallPlugin, self).update_firewall(
context, id, firewall)
fw['router_ids'] = fw_new_rtrs
fw_with_rules = (
self._make_firewall_dict_with_rules(context, fw['id']))
# determine rtrs to add fw to and del from
fw_with_rules['add-router-ids'] = fw_new_rtrs
fw_with_rules['del-router-ids'] = list(
set(fw_current_rtrs).difference(set(fw_new_rtrs)))
# last-router drives agent to ack with status to set state to INACTIVE
fw_with_rules['last-router'] = not fw_new_rtrs
LOG.debug("update_firewall(): Add Routers: %s, Del Routers: %s",
fw_with_rules['add-router-ids'],
fw_with_rules['del-router-ids'])
self.agent_rpc.update_firewall(context, fw_with_rules)
return fw
def delete_db_firewall_object(self, context, id):
@ -228,7 +329,14 @@ class FirewallPlugin(firewall_db.Firewall_db_mixin):
status_update)
fw_with_rules = (
self._make_firewall_dict_with_rules(context, fw['id']))
self.agent_rpc.delete_firewall(context, fw_with_rules)
fw_with_rules['del-router-ids'] = self.get_firewall_routers(
context, id)
fw_with_rules['add-router-ids'] = []
if not fw_with_rules['del-router-ids']:
# no routers to delete on the agent side
self.delete_db_firewall_object(context, id)
else:
self.agent_rpc.delete_firewall(context, fw_with_rules)
def update_firewall_policy(self, context, id, firewall_policy):
LOG.debug("update_firewall_policy() called")
@ -263,3 +371,20 @@ class FirewallPlugin(firewall_db.Firewall_db_mixin):
self).remove_rule(context, id, rule_info)
self._rpc_update_firewall_policy(context, id)
return fwp
def get_firewalls(self, context, filters=None, fields=None):
LOG.debug("fwaas get_firewalls() called")
fw_list = super(FirewallPlugin, self).get_firewalls(
context, filters, fields)
for fw in fw_list:
fw_current_rtrs = self.get_firewall_routers(context, fw['id'])
fw['router_ids'] = fw_current_rtrs
return fw_list
def get_firewall(self, context, id, fields=None):
LOG.debug("fwaas get_firewall() called")
res = super(FirewallPlugin, self).get_firewall(
context, id, fields)
fw_current_rtrs = self.get_firewall_routers(context, id)
res['router_ids'] = fw_current_rtrs
return res

View File

@ -97,55 +97,15 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
test_agent_class(cfg.CONF)
def test_create_firewall(self):
fake_firewall = {'id': 0}
with mock.patch.object(
self.api,
'_invoke_driver_for_plugin_api'
) as mock_driver:
self.assertEqual(
self.api.create_firewall(
mock.sentinel.context,
fake_firewall,
'host'),
mock_driver.return_value)
def test_update_firewall(self):
fake_firewall = {'id': 0}
with mock.patch.object(
self.api,
'_invoke_driver_for_plugin_api'
) as mock_driver:
self.assertEqual(
self.api.update_firewall(
mock.sentinel.context,
fake_firewall,
'host'),
mock_driver.return_value)
def test_delete_firewall(self):
fake_firewall = {'id': 0}
with mock.patch.object(
self.api,
'_invoke_driver_for_plugin_api'
) as mock_driver:
self.assertEqual(
self.api.delete_firewall(
mock.sentinel.context,
fake_firewall,
'host'),
mock_driver.return_value)
def test_invoke_driver_for_plugin_api(self):
fake_firewall = {'id': 0, 'tenant_id': 1,
'admin_state_up': True}
'admin_state_up': True,
'add-router-ids': [1, 2]}
self.api.plugin_rpc = mock.Mock()
with contextlib.nested(
mock.patch.object(self.api.plugin_rpc, 'get_routers'),
mock.patch.object(self.api, '_get_router_info_list_for_tenant'),
mock.patch.object(self.api.fwaas_driver, 'create_firewall'),
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status')
) as (
mock_get_routers,
mock_get_router_info_list_for_tenant,
mock_driver_create_firewall,
mock_set_firewall_status):
@ -155,199 +115,144 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
context=mock.sentinel.context,
firewall=fake_firewall, host='host')
mock_get_routers.assert_called_once_with(
mock.sentinel.context)
mock_get_router_info_list_for_tenant.assert_called_once_with(
mock_get_routers.return_value, fake_firewall['tenant_id'])
fake_firewall['add-router-ids'], fake_firewall['tenant_id'])
mock_set_firewall_status.assert_called_once_with(
mock.sentinel.context,
fake_firewall['id'],
'ACTIVE')
def test_invoke_driver_for_plugin_api_admin_state_down(self):
def test_update_firewall_with_routers_added_and_deleted(self):
fake_firewall = {'id': 0, 'tenant_id': 1,
'admin_state_up': False}
'admin_state_up': True,
'add-router-ids': [1, 2],
'del-router-ids': [3, 4],
'last-router': False}
self.api.plugin_rpc = mock.Mock()
with contextlib.nested(
mock.patch.object(self.api.plugin_rpc, 'get_routers'),
mock.patch.object(self.api, '_get_router_info_list_for_tenant'),
mock.patch.object(self.api.fwaas_driver, 'update_firewall'),
mock.patch.object(self.api.fwplugin_rpc,
'get_firewalls_for_tenant'),
mock.patch.object(self.api.fwaas_driver, 'delete_firewall'),
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status')
) as (
mock_get_routers,
mock_get_router_info_list_for_tenant,
mock_driver_delete_firewall,
mock_driver_update_firewall,
mock_get_firewalls_for_tenant,
mock_set_firewall_status):
mock_driver_delete_firewall.return_value = True
mock_driver_update_firewall.return_value = True
calls = [mock.call(fake_firewall['del-router-ids'],
fake_firewall['tenant_id']),
mock.call(fake_firewall['add-router-ids'],
fake_firewall['tenant_id'])]
self.api.update_firewall(
context=mock.sentinel.context,
firewall=fake_firewall, host='host')
mock_get_routers.assert_called_once_with(
mock.sentinel.context)
self.assertEqual(
mock_get_router_info_list_for_tenant.call_args_list,
calls)
mock_set_firewall_status.assert_called_once_with(
mock.sentinel.context,
fake_firewall['id'],
'ACTIVE')
def test_update_firewall_with_routers_added_and_admin_state_down(self):
fake_firewall = {'id': 0, 'tenant_id': 1,
'admin_state_up': False,
'add-router-ids': [1, 2],
'del-router-ids': [],
'last-router': False}
self.api.plugin_rpc = mock.Mock()
with contextlib.nested(
mock.patch.object(self.api, '_get_router_info_list_for_tenant'),
mock.patch.object(self.api.fwaas_driver, 'update_firewall'),
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status')
) as (
mock_get_router_info_list_for_tenant,
mock_driver_update_firewall,
mock_set_firewall_status):
mock_driver_update_firewall.return_value = True
self.api.update_firewall(
context=mock.sentinel.context,
firewall=fake_firewall, host='host')
mock_get_router_info_list_for_tenant.assert_called_once_with(
mock_get_routers.return_value, fake_firewall['tenant_id'])
fake_firewall['add-router-ids'], fake_firewall['tenant_id'])
mock_set_firewall_status.assert_called_once_with(
mock.sentinel.context,
fake_firewall['id'],
'DOWN')
def test_invoke_driver_for_plugin_api_delete(self):
def test_update_firewall_with_all_routers_deleted(self):
fake_firewall = {'id': 0, 'tenant_id': 1,
'admin_state_up': True}
'admin_state_up': True,
'add-router-ids': [],
'del-router-ids': [3, 4],
'last-router': True}
self.api.plugin_rpc = mock.Mock()
with contextlib.nested(
mock.patch.object(self.api.plugin_rpc, 'get_routers'),
mock.patch.object(self.api, '_get_router_info_list_for_tenant'),
mock.patch.object(self.api.fwaas_driver, 'delete_firewall'),
mock.patch.object(self.api.fwplugin_rpc, 'firewall_deleted')
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status')
) as (
mock_get_routers,
mock_get_router_info_list_for_tenant,
mock_driver_delete_firewall,
mock_firewall_deleted):
mock_set_firewall_status):
mock_driver_delete_firewall.return_value = True
self.api.delete_firewall(
self.api.update_firewall(
context=mock.sentinel.context,
firewall=fake_firewall, host='host')
mock_get_routers.assert_called_once_with(
mock.sentinel.context)
mock_get_router_info_list_for_tenant.assert_called_once_with(
mock_get_routers.return_value, fake_firewall['tenant_id'])
mock_firewall_deleted.assert_called_once_with(
mock.sentinel.context,
fake_firewall['id'])
def test_delete_firewall_no_router(self):
fake_firewall = {'id': 0, 'tenant_id': 1}
self.api.plugin_rpc = mock.Mock()
with contextlib.nested(
mock.patch.object(self.api.plugin_rpc, 'get_routers'),
mock.patch.object(self.api, '_get_router_info_list_for_tenant'),
mock.patch.object(self.api.fwplugin_rpc, 'firewall_deleted')
) as (
mock_get_routers,
mock_get_router_info_list_for_tenant,
mock_firewall_deleted):
mock_get_router_info_list_for_tenant.return_value = []
self.api.delete_firewall(
context=mock.sentinel.context,
firewall=fake_firewall, host='host')
mock_get_routers.assert_called_once_with(
mock.sentinel.context)
mock_get_router_info_list_for_tenant.assert_called_once_with(
mock_get_routers.return_value, fake_firewall['tenant_id'])
mock_firewall_deleted.assert_called_once_with(
mock.sentinel.context,
fake_firewall['id'])
def test_process_router_add_fw_update(self):
fake_firewall_list = [{'id': 0, 'tenant_id': 1,
'status': constants.PENDING_UPDATE,
'admin_state_up': True}]
fake_router = {'id': 1111, 'tenant_id': 2}
self.api.plugin_rpc = mock.Mock()
agent_mode = 'legacy'
ri = mock.Mock()
ri.router = fake_router
routers = [ri.router]
with contextlib.nested(
mock.patch.object(self.api.plugin_rpc, 'get_routers'),
mock.patch.object(self.api, '_get_router_info_list_for_tenant'),
mock.patch.object(self.api.fwaas_driver, 'update_firewall'),
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status'),
mock.patch.object(self.api.fwplugin_rpc,
'get_firewalls_for_tenant'),
mock.patch.object(context, 'Context')
) as (
mock_get_routers,
mock_get_router_info_list_for_tenant,
mock_driver_update_firewall,
mock_set_firewall_status,
mock_get_firewalls_for_tenant,
mock_Context):
mock_driver_update_firewall.return_value = True
ctx = mock.sentinel.context
mock_Context.return_value = ctx
mock_get_router_info_list_for_tenant.return_value = routers
mock_get_firewalls_for_tenant.return_value = fake_firewall_list
self.api._process_router_add(ri)
mock_get_router_info_list_for_tenant.assert_called_with(
routers,
ri.router['tenant_id'])
mock_get_firewalls_for_tenant.assert_called_once_with(ctx)
mock_driver_update_firewall.assert_called_once_with(
agent_mode,
routers,
fake_firewall_list[0])
fake_firewall['del-router-ids'], fake_firewall['tenant_id'])
mock_set_firewall_status.assert_called_once_with(
ctx,
fake_firewall_list[0]['id'],
constants.ACTIVE)
mock.sentinel.context,
fake_firewall['id'],
'INACTIVE')
def test_delete_firewall(self):
fake_firewall = {'id': 0, 'tenant_id': 1,
'admin_state_up': True,
'add-router-ids': [],
'del-router-ids': [3, 4],
'last-router': True}
def test_process_router_add_fw_delete(self):
fake_firewall_list = [{'id': 0, 'tenant_id': 1,
'status': constants.PENDING_DELETE}]
fake_router = {'id': 1111, 'tenant_id': 2}
agent_mode = 'legacy'
self.api.plugin_rpc = mock.Mock()
ri = mock.Mock()
ri.router = fake_router
routers = [ri.router]
with contextlib.nested(
mock.patch.object(self.api.plugin_rpc, 'get_routers'),
mock.patch.object(self.api, '_get_router_info_list_for_tenant'),
mock.patch.object(self.api.fwaas_driver, 'delete_firewall'),
mock.patch.object(self.api.fwplugin_rpc, 'firewall_deleted'),
mock.patch.object(self.api.fwplugin_rpc,
'get_firewalls_for_tenant'),
mock.patch.object(context, 'Context')
mock.patch.object(self.api.fwplugin_rpc, 'firewall_deleted')
) as (
mock_get_routers,
mock_get_router_info_list_for_tenant,
mock_driver_delete_firewall,
mock_firewall_deleted,
mock_get_firewalls_for_tenant,
mock_Context):
mock_firewall_deleted):
mock_driver_delete_firewall.return_value = True
ctx = mock.sentinel.context
mock_Context.return_value = ctx
mock_get_router_info_list_for_tenant.return_value = routers
mock_get_firewalls_for_tenant.return_value = fake_firewall_list
self.api.delete_firewall(
context=mock.sentinel.context,
firewall=fake_firewall, host='host')
self.api._process_router_add(ri)
mock_get_router_info_list_for_tenant.assert_called_with(
routers,
ri.router['tenant_id'])
mock_get_firewalls_for_tenant.assert_called_once_with(ctx)
mock_driver_delete_firewall.assert_called_once_with(
agent_mode,
routers,
fake_firewall_list[0])
mock_get_router_info_list_for_tenant.assert_called_once_with(
fake_firewall['del-router-ids'], fake_firewall['tenant_id'])
mock_firewall_deleted.assert_called_once_with(
ctx,
fake_firewall_list[0]['id'])
mock.sentinel.context,
fake_firewall['id'])
def _prepare_router_data(self):
return router_info.RouterInfo(self.router_id,
@ -357,12 +262,13 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
self.conf.set_override('use_namespaces', use_namespaces)
ri = self._prepare_router_data()
routers = [ri.router]
router_ids = [router['id'] for router in routers]
self.api.router_info = {ri.router_id: ri}
with mock.patch.object(ip_lib.IPWrapper,
'get_namespaces') as mock_get_namespaces:
mock_get_namespaces.return_value = []
router_info_list = self.api._get_router_info_list_for_tenant(
routers,
router_ids,
ri.router['tenant_id'])
if use_namespaces:
mock_get_namespaces.assert_called_once_with()
@ -390,11 +296,12 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
self.api.router_info[ri.router_id] = ri
routers.append(ri.router)
ri_expected.append(ri)
router_ids = [router['id'] for router in routers]
with mock.patch.object(ip_lib.IPWrapper,
'get_namespaces') as mock_get_namespaces:
mock_get_namespaces.return_value = ri.ns_name
router_info_list = self.api._get_router_info_list_for_tenant(
routers,
router_ids,
ri.router['tenant_id'])
self.assertEqual(ri_expected, router_info_list)

View File

@ -17,22 +17,114 @@
import contextlib
import mock
from neutron.api.v2 import attributes as attr
from neutron import context
from neutron import manager
from neutron.plugins.common import constants as const
from neutron.tests.unit import test_l3_plugin
from neutron.tests.unit import testlib_plugin
from oslo_config import cfg
from webob import exc
import neutron_fwaas.extensions
from neutron_fwaas.extensions import firewall
from neutron_fwaas.extensions import firewallrouterinsertion
from neutron_fwaas.services.firewall import fwaas_plugin
from neutron_fwaas.tests import base
from neutron_fwaas.tests.unit.db.firewall import test_db_firewall
extensions_path = neutron_fwaas.extensions.__path__[0]
FW_PLUGIN_KLASS = (
"neutron_fwaas.services.firewall.fwaas_plugin.FirewallPlugin"
)
class TestFirewallCallbacks(test_db_firewall.FirewallPluginDbTestCase):
class FirewallTestExtensionManager(test_l3_plugin.L3TestExtensionManager):
def get_resources(self):
res = super(FirewallTestExtensionManager, self).get_resources()
firewall.RESOURCE_ATTRIBUTE_MAP['firewalls'].update(
firewallrouterinsertion.EXTENDED_ATTRIBUTES_2_0['firewalls'])
return res + firewall.Firewall.get_resources()
def get_actions(self):
return []
def get_request_extensions(self):
return []
class TestFirewallRouterInsertionBase(
test_db_firewall.FirewallPluginDbTestCase,
testlib_plugin.NotificationSetupHelper):
def setUp(self, core_plugin=None, fw_plugin=None, ext_mgr=None):
self.agentapi_del_fw_p = mock.patch(test_db_firewall.DELETEFW_PATH,
create=True, new=test_db_firewall.FakeAgentApi().delete_firewall)
self.agentapi_del_fw_p.start()
plugin = None
# the plugin without L3 support
if not plugin:
plugin = 'neutron.tests.unit.test_l3_plugin.TestNoL3NatPlugin'
# the L3 service plugin
l3_plugin = ('neutron.tests.unit.test_l3_plugin.'
'TestL3NatServicePlugin')
cfg.CONF.set_override('api_extensions_path', extensions_path)
self.saved_attr_map = {}
for resource, attrs in attr.RESOURCE_ATTRIBUTE_MAP.iteritems():
self.saved_attr_map[resource] = attrs.copy()
if not fw_plugin:
fw_plugin = FW_PLUGIN_KLASS
service_plugins = {'l3_plugin_name': l3_plugin,
'fw_plugin_name': fw_plugin}
if not ext_mgr:
ext_mgr = FirewallTestExtensionManager()
super(test_db_firewall.FirewallPluginDbTestCase, self).setUp(
plugin=plugin, service_plugins=service_plugins, ext_mgr=ext_mgr)
self.setup_notification_driver()
self.l3_plugin = manager.NeutronManager.get_service_plugins().get(
const.L3_ROUTER_NAT)
self.plugin = manager.NeutronManager.get_service_plugins().get(
const.FIREWALL)
self.callbacks = self.plugin.endpoints[0]
def restore_attribute_map(self):
# Remove the csrfirewallinsertion extension
firewall.RESOURCE_ATTRIBUTE_MAP['firewalls'].pop('router_ids')
# Restore the original RESOURCE_ATTRIBUTE_MAP
attr.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
def tearDown(self):
self.restore_attribute_map()
super(TestFirewallRouterInsertionBase, self).tearDown()
def _create_firewall(self, fmt, name, description, firewall_policy_id,
admin_state_up=True, expected_res_status=None,
**kwargs):
tenant_id = kwargs.get('tenant_id', self._tenant_id)
router_ids = kwargs.get('router_ids')
data = {'firewall': {'name': name,
'description': description,
'firewall_policy_id': firewall_policy_id,
'admin_state_up': admin_state_up,
'tenant_id': tenant_id}}
if router_ids is not None:
data['firewall']['router_ids'] = router_ids
firewall_req = self.new_create_request('firewalls', data, fmt)
firewall_res = firewall_req.get_response(self.ext_api)
if expected_res_status:
self.assertEqual(expected_res_status, firewall_res.status_int)
return firewall_res
class TestFirewallCallbacks(TestFirewallRouterInsertionBase):
def setUp(self):
super(TestFirewallCallbacks,
@ -144,6 +236,8 @@ class TestFirewallCallbacks(test_db_firewall.FirewallPluginDbTestCase):
self.plugin._make_firewall_dict_with_rules(ctx,
fw_id)
)
fw_rules['add-router-ids'] = []
fw_rules['del-router-ids'] = []
self.assertEqual(res[0], fw_rules)
self._compare_firewall_rule_lists(
fwp_id, fr, res[0]['firewall_rule_list'])
@ -158,6 +252,8 @@ class TestFirewallCallbacks(test_db_firewall.FirewallPluginDbTestCase):
with self.firewall(firewall_policy_id=fwp_id, tenant_id=tenant_id,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
) as fw:
# router_ids is not present in the firewall db
# but is added in the get_firewalls override by plugin
fw_list = [fw['firewall']]
f = self.callbacks.get_firewalls_for_tenant_without_rules
res = f(ctx, host='dummy')
@ -202,18 +298,67 @@ class TestFirewallAgentApi(base.BaseTestCase):
self._call_test_helper('delete_firewall')
class TestFirewallPluginBase(test_db_firewall.TestFirewallDBPlugin):
class TestFirewallPluginBase(TestFirewallRouterInsertionBase,
test_l3_plugin.L3NatTestCaseMixin):
def setUp(self):
super(TestFirewallPluginBase, self).setUp(fw_plugin=FW_PLUGIN_KLASS)
self.callbacks = self.plugin.endpoints[0]
def test_create_second_firewall_not_permitted(self):
with self.firewall():
res = self._create_firewall(
None, 'firewall2', description='test',
firewall_policy_id=None, admin_state_up=True)
self.assertEqual(res.status_int, exc.HTTPConflict.code)
def tearDown(self):
super(TestFirewallPluginBase, self).tearDown()
def test_create_firewall_routers_not_specified(self):
"""neutron firewall-create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id):
with self.router(name='router2', admin_state_up=True,
tenant_id=self._tenant_id):
with self.firewall() as fw1:
self.assertEqual(const.PENDING_CREATE,
fw1['firewall']['status'])
def test_create_firewall_routers_specified(self):
"""neutron firewall-create test-policy --router-ids "r1 r2" """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as router1:
with self.router(name='router2', admin_state_up=True,
tenant_id=self._tenant_id) as router2:
router_ids = [router1['router']['id'], router2['router']['id']]
with self.firewall(router_ids=router_ids) as fw1:
self.assertEqual(const.PENDING_CREATE,
fw1['firewall']['status'])
def test_create_firewall_routers_present_empty_list_specified(self):
"""neutron firewall-create test-policy --router-ids "" """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id):
with self.router(name='router2', admin_state_up=True,
tenant_id=self._tenant_id):
router_ids = []
with self.firewall(router_ids=router_ids) as fw1:
self.assertEqual(const.INACTIVE,
fw1['firewall']['status'])
def test_create_firewall_no_routers_empty_list_specified(self):
"""neutron firewall-create test-policy --router-ids "" """
router_ids = []
with self.firewall(router_ids=router_ids) as fw1:
self.assertEqual(const.INACTIVE,
fw1['firewall']['status'])
def test_create_second_firewall_on_same_tenant(self):
"""fw1 created with default routers, fw2 no routers on same tenant."""
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id):
with self.router(name='router2', admin_state_up=True,
tenant_id=self._tenant_id):
router_ids = []
with self.firewall() as fw1:
with self.firewall(router_ids=router_ids) as fw2:
self.assertEqual(const.PENDING_CREATE,
fw1['firewall']['status'])
self.assertEqual(const.INACTIVE,
fw2['firewall']['status'])
def test_create_firewall_admin_not_affected_by_other_tenant(self):
# Create fw with admin after creating fw with other tenant
@ -227,123 +372,158 @@ class TestFirewallPluginBase(test_db_firewall.TestFirewallDBPlugin):
name = "new_firewall1"
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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
) as firewall:
fw_id = firewall['firewall']['id']
res = self.callbacks.set_firewall_status(ctx, fw_id,
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as router1:
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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
router_ids=[router1['router']['id']]
) as firewall:
fw_id = firewall['firewall']['id']
res = self.callbacks.set_firewall_status(ctx, fw_id,
const.ACTIVE)
data = {'firewall': {'name': name}}
req = self.new_update_request('firewalls', data, fw_id)
res = self.deserialize(self.fmt,
data = {'firewall': {'name': name}}
req = self.new_update_request('firewalls', data, fw_id)
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
attrs = self._replace_firewall_status(attrs,
attrs = self._replace_firewall_status(attrs,
const.PENDING_CREATE,
const.PENDING_UPDATE)
for k, v in attrs.iteritems():
self.assertEqual(res['firewall'][k], v)
for k, v in attrs.iteritems():
self.assertEqual(res['firewall'][k], v)
def test_update_firewall_fails_when_firewall_pending(self):
name = "new_firewall1"
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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
) as firewall:
fw_id = firewall['firewall']['id']
data = {'firewall': {'name': name}}
req = self.new_update_request('firewalls', data, fw_id)
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, exc.HTTPConflict.code)
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as router1:
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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
router_ids=[router1['router']['id']]
) as firewall:
fw_id = firewall['firewall']['id']
data = {'firewall': {'name': name}}
req = self.new_update_request('firewalls', data, fw_id)
res = req.get_response(self.ext_api)
self.assertEqual(exc.HTTPConflict.code, res.status_int)
def test_update_firewall_with_router_when_firewall_inactive(self):
name = "firewall1"
attrs = self._get_test_firewall_attrs(name)
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as router1:
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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
router_ids=[]
) as firewall:
fw_id = firewall['firewall']['id']
data = {
'firewall': {'router_ids': [router1['router']['id']]}}
req = self.new_update_request('firewalls', data, fw_id)
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
attrs = self._replace_firewall_status(attrs,
const.PENDING_CREATE,
const.PENDING_UPDATE)
for k, v in attrs.iteritems():
self.assertEqual(res['firewall'][k], v)
def test_update_firewall_shared_fails_for_non_admin(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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
tenant_id='noadmin'
) as firewall:
fw_id = firewall['firewall']['id']
self.callbacks.set_firewall_status(ctx, fw_id,
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as router1:
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall(
firewall_policy_id=fwp_id,
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
tenant_id='noadmin',
router_ids=[router1['router']['id']]
) as firewall:
fw_id = firewall['firewall']['id']
self.callbacks.set_firewall_status(ctx, fw_id,
const.ACTIVE)
data = {'firewall': {'shared': True}}
req = self.new_update_request(
'firewalls', data, fw_id,
context=context.Context('', 'noadmin'))
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, exc.HTTPForbidden.code)
data = {'firewall': {'shared': True}}
req = self.new_update_request(
'firewalls', data, fw_id,
context=context.Context('', 'noadmin'))
res = req.get_response(self.ext_api)
self.assertEqual(exc.HTTPForbidden.code, res.status_int)
def test_update_firewall_policy_fails_when_firewall_pending(self):
name = "new_firewall1"
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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
):
data = {'firewall_policy': {'name': name}}
req = self.new_update_request('firewall_policies',
data, fwp_id)
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, exc.HTTPConflict.code)
def test_update_firewall_rule_fails_when_firewall_pending(self):
with self.firewall_rule(name='fwr1') as fr:
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id):
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
fr_id = fr['firewall_rule']['id']
fw_rule_ids = [fr_id]
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['firewall_policy_id'] = fwp_id
with self.firewall(
firewall_policy_id=fwp_id,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
):
data = {'firewall_rule': {'protocol': 'udp'}}
req = self.new_update_request('firewall_rules',
data, fr_id)
data = {'firewall_policy': {'name': name}}
req = self.new_update_request('firewall_policies',
data, fwp_id)
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, exc.HTTPConflict.code)
self.assertEqual(exc.HTTPConflict.code, res.status_int)
def test_delete_firewall(self):
def test_update_firewall_rule_fails_when_firewall_pending(self):
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id):
with self.firewall_rule(name='fwr1') as fr:
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
fr_id = fr['firewall_rule']['id']
fw_rule_ids = [fr_id]
data = {'firewall_policy':
{'firewall_rules': fw_rule_ids}}
req = self.new_update_request('firewall_policies', data,
fwp_id)
req.get_response(self.ext_api)
with self.firewall(
firewall_policy_id=fwp_id,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
):
data = {'firewall_rule': {'protocol': 'udp'}}
req = self.new_update_request('firewall_rules',
data, fr_id)
res = req.get_response(self.ext_api)
self.assertEqual(exc.HTTPConflict.code, res.status_int)
def test_delete_firewall_with_no_routers(self):
ctx = context.get_admin_context()
attrs = self._get_test_firewall_attrs()
# stop the AgentRPC patch for this one to test pending states
self.agentapi_delf_p.stop()
self.agentapi_del_fw_p.stop()
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,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
) as firewall:
fw_id = firewall['firewall']['id']
attrs = self._replace_firewall_status(attrs,
const.PENDING_CREATE,
const.PENDING_DELETE)
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
do_delete=False
) as fw:
fw_id = fw['firewall']['id']
req = self.new_delete_request('firewalls', fw_id)
req.get_response(self.ext_api)
fw_db = self.plugin._get_firewall(ctx, fw_id)
for k, v in attrs.iteritems():
self.assertEqual(fw_db[k], v)
# cleanup the pending firewall
self.plugin.endpoints[0].firewall_deleted(ctx, fw_id)
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
self.assertRaises(firewall.FirewallNotFound,
self.plugin.get_firewall,
ctx, fw_id)
def test_delete_firewall_after_agent_delete(self):
ctx = context.get_admin_context()
@ -376,7 +556,8 @@ class TestFirewallPluginBase(test_db_firewall.TestFirewallDBPlugin):
attrs['firewall_policy_id'] = fwp_id
with self.firewall(
firewall_policy_id=fwp_id,
admin_state_up=test_db_firewall.ADMIN_STATE_UP
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
router_ids=[]
) as fw:
fw_id = fw['firewall']['id']
fw_rules = (
@ -392,7 +573,7 @@ class TestFirewallPluginBase(test_db_firewall.TestFirewallDBPlugin):
with self.firewall() as fw:
fw_id = fw['firewall']['id']
fw_rules = self.plugin._make_firewall_dict_with_rules(ctx, fw_id)
self.assertEqual(fw_rules['firewall_rule_list'], [])
self.assertEqual([], fw_rules['firewall_rule_list'])
def test_list_firewalls(self):
with self.firewall_policy() as fwp: