Implements a plugable backend driver

This patch removes all related DB code from the FWaaS service plugin v2
and creates service driver interfaces that can be used by different
backend drivers.

The default backend driver still based on the Neutron DB model
and agent RPC interface (for l3 and l2 agents) and was moved
to 'service_drivers.agents.agents.FwaasAgentDriver'. It inherits from the
firewall backend driver DB interface
'service_drivers.driver_api.FwaasDriverDB' to maintain the DB. It
is in charge to implement all RPC API and messages.

If we need to implement a backend driver which depends on the Neutron DB
but not on the agent RPC service, we just have to inherit from the DB
interface and if we like to develop a backend driver which not depends
on the Neutron DB model, we can inherit from the base driver interface
'service_driver.driver_api.FwaasDriver'.

That patch only modifies the service plugin 'firewall_v2', it does not
modify the Firewall v1 service plugin.

The backend DB driver provides an interface composed to a pre and post
commit hooks for each FWaaSv2 API actions which permits to the driver to
be warn anytimes. All that commit hooks methods does not do anything by
default and the backend driver needs to overide needed hooks.
The driver does not needs to implements all of them,

Closes-Bug: #1702312
Change-Id: I4ebd24f1b13eb823c4d63452fd37cace5bcf5481
This commit is contained in:
Édouard Thuleau 2017-06-26 11:32:24 +02:00
parent ce626773ab
commit 9b353afde4
61 changed files with 2641 additions and 1886 deletions

View File

@ -43,6 +43,9 @@ function configure_fwaas_v1() {
function configure_fwaas_v2() {
# Add conf file
cp $NEUTRON_FWAAS_DIR/etc/neutron_fwaas.conf.sample $NEUTRON_FWAAS_CONF
inicomment $NEUTRON_FWAAS_CONF service_providers service_provider
iniadd $NEUTRON_FWAAS_CONF service_providers service_provider $NEUTRON_FWAAS_SERVICE_PROVIDERV2
neutron_fwaas_configure_driver fwaas_v2
iniset_multiline $Q_L3_CONF_FILE fwaas agent_version v2
iniset_multiline $Q_L3_CONF_FILE fwaas driver $FWAAS_DRIVER_V2

View File

@ -8,4 +8,5 @@ NEUTRON_FWAAS_DIR=$DEST/neutron-fwaas
NEUTRON_FWAAS_CONF_FILE=neutron_fwaas.conf
NEUTRON_FWAAS_CONF=$NEUTRON_CONF_DIR/$NEUTRON_FWAAS_CONF_FILE
neutron_server_config_add $NEUTRON_FWAAS_CONF
NEUTRON_FWAAS_SERVICE_PROVIDERV2=${NEUTRON_FWAAS_SERVICE_PROVIDERV2:-FIREWALL_V2:fwaas_db:neutron_fwaas.services.firewall.service_drivers.agents.agents.FirewallAgentDriver:default}

View File

@ -16,16 +16,16 @@
import copy
import netaddr
from neutron.db import _model_query as model_query
from neutron.db import api as db_api
from neutron.db import common_db_mixin as base_db
from neutron.db import common_db_mixin
from neutron_lib.api.definitions import constants as fw_const
from neutron_lib.api import validators
from neutron_lib import constants as nl_constants
from neutron_lib.db import constants as db_constants
from neutron_lib.db import model_base
from neutron_lib import exceptions
from neutron_lib.exceptions import firewall_v2 as f_exc
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_log import log as logging
from oslo_utils import uuidutils
@ -36,7 +36,6 @@ from sqlalchemy import orm
from sqlalchemy.orm import exc
from neutron_fwaas.common import fwaas_constants as const
from neutron_fwaas.extensions import firewall_v2 as fw_ext
LOG = logging.getLogger(__name__)
@ -86,7 +85,7 @@ class FirewallRuleV2(model_base.BASEV2, model_base.HasId, HasName,
class FirewallGroup(model_base.BASEV2, model_base.HasId, HasName,
HasDescription, model_base.HasProject):
__tablename__ = 'firewall_groups_v2'
ports = orm.relationship(
port_associations = orm.relationship(
'FirewallGroupPortAssociation',
backref=orm.backref('firewall_group_port_associations_v2',
cascade='all, delete'))
@ -162,7 +161,42 @@ class FirewallPolicy(model_base.BASEV2, model_base.HasId, HasName,
shared = sa.Column(sa.Boolean)
class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
def _list_firewall_groups_result_filter_hook(query, filters):
values = filters and filters.get('ports', [])
if values:
query = query.join(FirewallGroupPortAssociation)
query = query.filter(FirewallGroupPortAssociation.port_id.in_(values))
return query
def _list_firewall_policies_result_filter_hook(query, filters):
values = filters and filters.get('firewall_rules', [])
if values:
query = query.join(FirewallPolicyRuleAssociation)
query = query.filter(
FirewallPolicyRuleAssociation.firewall_rule_id.in_(values))
return query
class FirewallPluginDb(common_db_mixin.CommonDbMixin):
def __new__(cls, *args, **kwargs):
model_query.register_hook(
FirewallGroup,
"firewall_group_v2_filter_by_port_association",
query_hook=None,
filter_hook=None,
result_filters=_list_firewall_groups_result_filter_hook)
model_query.register_hook(
FirewallPolicy,
"firewall_policy_v2_filter_by_firewall_rule_association",
query_hook=None,
filter_hook=None,
result_filters=_list_firewall_policies_result_filter_hook)
return super(FirewallPluginDb, cls).__new__(cls, *args, **kwargs)
def _get_firewall_group(self, context, id):
try:
@ -267,22 +301,21 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
'shared': firewall_policy['shared']}
return self._fields(res, fields)
def _make_firewall_group_dict(self, firewall_group, fields=None):
fwg_ports = [
port_assoc.port_id for port_assoc in firewall_group['ports']
]
res = {'id': firewall_group['id'],
'tenant_id': firewall_group['tenant_id'],
'name': firewall_group['name'],
'description': firewall_group['description'],
def _make_firewall_group_dict(self, firewall_group_db, fields=None):
fwg_ports = [port_assoc.port_id for port_assoc in
firewall_group_db.port_associations]
res = {'id': firewall_group_db['id'],
'tenant_id': firewall_group_db['tenant_id'],
'name': firewall_group_db['name'],
'description': firewall_group_db['description'],
'ingress_firewall_policy_id':
firewall_group['ingress_firewall_policy_id'],
firewall_group_db['ingress_firewall_policy_id'],
'egress_firewall_policy_id':
firewall_group['egress_firewall_policy_id'],
'admin_state_up': firewall_group['admin_state_up'],
firewall_group_db['egress_firewall_policy_id'],
'admin_state_up': firewall_group_db['admin_state_up'],
'ports': fwg_ports,
'status': firewall_group['status'],
'shared': firewall_group['shared']}
'status': firewall_group_db['status'],
'shared': firewall_group_db['shared']}
return self._fields(res, fields)
def _get_policy_ordered_rules(self, context, policy_id):
@ -292,7 +325,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
.order_by(FirewallPolicyRuleAssociation.position))
return [self._make_firewall_rule_dict(rule) for rule in query]
def _make_firewall_group_dict_with_rules(self, context, firewall_group_id):
def make_firewall_group_dict_with_rules(self, context, firewall_group_id):
firewall_group = self.get_firewall_group(context, firewall_group_id)
ingress_policy_id = firewall_group['ingress_firewall_policy_id']
if ingress_policy_id:
@ -359,7 +392,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
def _get_policy_rule_association(self, context, firewall_policy_id,
firewall_rule_id):
"""Returns the association between a firewall rule and a firewall
policy. Throws an exception if the assocaition does not exist.
policy. Throws an exception if the assocition does not exist.
"""
try:
return self._get_policy_rule_association_query(
@ -374,7 +407,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
# configuration file makes sense. Can be done some time later
# 1. Drop any IPv4 packets for ingress traffic
in_fwr_v4 = {'firewall_rule': {
in_fwr_v4 = {
'description': 'default ingress rule for IPv4',
'name': 'default ingress ipv4 (deny all)',
'shared': False,
@ -387,28 +420,25 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
'source_ip_address': None,
'destination_port': None,
'destination_ip_address': None,
}}
}
# 2. Drop any IPv6 packets for ingress traffic
in_fwr_v6 = copy.deepcopy(in_fwr_v4)
in_fwr_v6[
'firewall_rule']['description'] = 'default ingress rule for IPv6'
in_fwr_v6['firewall_rule']['name'] = 'default ingress ipv6 (deny all)'
in_fwr_v6['firewall_rule']['ip_version'] = nl_constants.IP_VERSION_6
in_fwr_v6['description'] = 'default ingress rule for IPv6'
in_fwr_v6['name'] = 'default ingress ipv6 (deny all)'
in_fwr_v6['ip_version'] = nl_constants.IP_VERSION_6
# 3. Allow any IPv4 packets for egress traffic
eg_fwr_v4 = copy.deepcopy(in_fwr_v4)
eg_fwr_v4[
'firewall_rule']['description'] = 'default egress rule for IPv4'
eg_fwr_v4['firewall_rule']['action'] = fw_const.FWAAS_ALLOW
eg_fwr_v4['firewall_rule']['name'] = 'default egress ipv4 (allow all)'
eg_fwr_v4['description'] = 'default egress rule for IPv4'
eg_fwr_v4['action'] = fw_const.FWAAS_ALLOW
eg_fwr_v4['name'] = 'default egress ipv4 (allow all)'
# 4. Allow any IPv6 packets for egress traffic
eg_fwr_v6 = copy.deepcopy(in_fwr_v6)
eg_fwr_v6[
'firewall_rule']['description'] = 'default egress rule for IPv6'
eg_fwr_v6['firewall_rule']['name'] = 'default egress ipv6 (allow all)'
eg_fwr_v6['firewall_rule']['action'] = fw_const.FWAAS_ALLOW
eg_fwr_v6['description'] = 'default egress rule for IPv6'
eg_fwr_v6['name'] = 'default egress ipv6 (allow all)'
eg_fwr_v6['action'] = fw_const.FWAAS_ALLOW
return {
'in_ipv4': self.create_firewall_rule(context, in_fwr_v4)['id'],
@ -418,8 +448,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
}
def create_firewall_rule(self, context, firewall_rule):
LOG.debug("create_firewall_rule() called")
fwr = firewall_rule['firewall_rule']
fwr = firewall_rule
self._validate_fwr_protocol_parameters(fwr)
self._validate_fwr_src_dst_ip_version(fwr)
if not fwr['protocol'] and (fwr['source_port'] or
@ -450,8 +479,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
return self._make_firewall_rule_dict(fwr_db)
def update_firewall_rule(self, context, id, firewall_rule):
LOG.debug("update_firewall_rule() called")
fwr = firewall_rule['firewall_rule']
fwr = firewall_rule
fwr_db = self._get_firewall_rule(context, id)
self._validate_fwr_protocol_parameters(fwr, fwr_db=fwr_db)
self._validate_fwr_src_dst_ip_version(fwr, fwr_db=fwr_db)
@ -478,24 +506,21 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
raise f_exc.FirewallRuleWithPortWithoutProtocolInvalid()
fwr_db.update(fwr)
# if the rule on a policy, fix audited flag
fwp_ids = self._get_policies_with_rule(context, id)
fwp_ids = self.get_policies_with_rule(context, id)
for fwp_id in fwp_ids:
fwp_db = self._get_firewall_policy(context, fwp_id)
fwp_db['audited'] = False
return self._make_firewall_rule_dict(fwr_db)
def delete_firewall_rule(self, context, id):
LOG.debug("delete_firewall_rule() called")
with context.session.begin(subtransactions=True):
fwr = self._get_firewall_rule(context, id)
# make sure rule is not associated with any policy
if self._get_policies_with_rule(context, id):
if self.get_policies_with_rule(context, id):
raise f_exc.FirewallRuleInUse(firewall_rule_id=id)
context.session.delete(fwr)
def insert_rule(self, context, id, rule_info):
LOG.debug("insert_rule() called")
self._validate_insert_remove_rule_request(rule_info)
firewall_rule_id = rule_info['firewall_rule_id']
# ensure rule is not already assigned to the policy
self._ensure_rule_not_already_associated(context, id, firewall_rule_id)
@ -534,8 +559,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
position, None)
def remove_rule(self, context, id, rule_info):
LOG.debug("remove_rule() called")
self._validate_insert_remove_rule_request(rule_info)
firewall_rule_id = rule_info['firewall_rule_id']
with context.session.begin(subtransactions=True):
self._get_firewall_rule(context, firewall_rule_id)
@ -545,30 +568,15 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
None, fwpra_db)
def get_firewall_rule(self, context, id, fields=None):
LOG.debug("get_firewall_rule() called")
fwr = self._get_firewall_rule(context, id)
policies = self._get_policies_with_rule(context, id) or None
policies = self.get_policies_with_rule(context, id) or None
return self._make_firewall_rule_dict(fwr, fields, policies=policies)
def get_firewall_rules(self, context, filters=None, fields=None):
LOG.debug("get_firewall_rules() called")
return self._get_collection(context, FirewallRuleV2,
self._make_firewall_rule_dict,
filters=filters, fields=fields)
def _validate_insert_remove_rule_request(self, rule_info):
"""Validate rule_info dict
Check that all mandatory fields are present, otherwise raise
proper exception.
"""
if not rule_info or 'firewall_rule_id' not in rule_info:
raise f_exc.FirewallRuleInfoMissing()
# Validator doesn't return anything if the check passes
if validators.validate_uuid(rule_info['firewall_rule_id']):
raise f_exc.FirewallRuleNotFound(
firewall_rule_id=rule_info['firewall_rule_id'])
def _get_rules_in_policy(self, context, fwpid):
"""Gets rules in a firewall policy"""
with context.session.begin(subtransactions=True):
@ -578,7 +586,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
fwp_rules = [entry.firewall_rule_id for entry in fw_pol_rule_qry]
return fwp_rules
def _get_policies_with_rule(self, context, fwrid):
def get_policies_with_rule(self, context, fwrid):
"""Gets rules in a firewall policy"""
with context.session.begin(subtransactions=True):
fw_pol_rule_qry = context.session.query(
@ -644,7 +652,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
firewall_rule_id=fwr_db['id'],
firewall_policy_id=fwp_db['id'])
def _get_fwgs_with_policy(self, context, fwp_id):
def get_fwgs_with_policy(self, context, fwp_id):
with context.session.begin(subtransactions=True):
fwg_ing_pol_qry = context.session.query(
FirewallGroup).filter_by(
@ -719,18 +727,18 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
description = kwargs.get('description', '')
name = (const.DEFAULT_FWP_INGRESS
if policy_type == 'ingress' else const.DEFAULT_FWP_EGRESS)
firewall_policy = {'firewall_policy': {
firewall_policy = {
'name': name,
'description': description,
'audited': False,
'shared': False,
'firewall_rules': fwrs,
'tenant_id': tenant_id,
}}
}
return self._do_create_firewall_policy(context, firewall_policy)
def _do_create_firewall_policy(self, context, firewall_policy):
fwp = firewall_policy['firewall_policy']
fwp = firewall_policy
with context.session.begin(subtransactions=True):
fwp_db = FirewallPolicy(
id=uuidutils.generate_uuid(),
@ -744,13 +752,11 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
return self._make_firewall_policy_dict(fwp_db)
def create_firewall_policy(self, context, firewall_policy):
LOG.debug("create_firewall_policy() called")
self._ensure_not_default_resource(firewall_policy, 'firewall_policy')
return self._do_create_firewall_policy(context, firewall_policy)
def update_firewall_policy(self, context, id, firewall_policy):
LOG.debug("update_firewall_policy() called")
fwp = firewall_policy['firewall_policy']
fwp = firewall_policy
with context.session.begin(subtransactions=True):
fwp_db = self._get_firewall_policy(context, id)
self._ensure_not_default_resource(fwp_db, 'firewall_policy',
@ -772,7 +778,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
return self._make_firewall_policy_dict(fwp_db)
def delete_firewall_policy(self, context, id):
LOG.debug("delete_firewall_policy() called")
with context.session.begin(subtransactions=True):
fwp_db = self._get_firewall_policy(context, id)
# check if policy in use
@ -786,35 +791,14 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
context.session.delete(fwp_db)
def get_firewall_policy(self, context, id, fields=None):
LOG.debug("get_firewall_policy() called")
fwp = self._get_firewall_policy(context, id)
return self._make_firewall_policy_dict(fwp, fields)
def get_firewall_policies(self, context, filters=None, fields=None):
LOG.debug("get_firewall_policies() called")
return self._get_collection(context, FirewallPolicy,
self._make_firewall_policy_dict,
filters=filters, fields=fields)
def _validate_tenant_for_fwg_policies(self, context, fwg, fwg_tenant_id):
# On updates, all keys will not be present so fetch and validate.
if 'ingress_firewall_policy_id' in fwg:
fwp_id = fwg['ingress_firewall_policy_id']
if fwp_id is not None:
fwp = self._get_firewall_policy(context, fwp_id)
if fwg_tenant_id != fwp['tenant_id'] and not fwp['shared']:
raise f_exc.FirewallPolicyConflict(
firewall_policy_id=fwp_id)
if 'egress_firewall_policy_id' in fwg:
fwp_id = fwg['egress_firewall_policy_id']
if fwp_id is not None:
fwp = self._get_firewall_policy(context, fwp_id)
if fwg_tenant_id != fwp['tenant_id'] and not fwp['shared']:
raise f_exc.FirewallPolicyConflict(
firewall_policy_id=fwp_id)
return
def _set_ports_for_firewall_group(self, context, fwg_db, fwg):
port_id_list = fwg['ports']
if not port_id_list:
@ -833,7 +817,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
if exc_ports:
raise f_exc.FirewallGroupPortInUse(port_ids=exc_ports)
def _get_ports_in_firewall_group(self, context, firewall_group_id):
def get_ports_in_firewall_group(self, context, firewall_group_id):
"""Get the Ports associated with the firewall group."""
with context.session.begin(subtransactions=True):
fw_group_port_qry = context.session.query(
@ -852,27 +836,13 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
firewall_group_id=firewall_group_id).delete()
return
def _validate_if_firewall_group_on_ports(
self, context, port_ids, fwg_id=None):
"""Validate if ports are not associated with any firewall_group.
If any of the ports in the list is already associated with
a firewall_group, raise an exception else just return.
"""
fwg_port_qry = context.session.query(
FirewallGroupPortAssociation.port_id)
fwg_ports = fwg_port_qry.filter(
FirewallGroupPortAssociation.port_id.in_(port_ids),
FirewallGroupPortAssociation.firewall_group_id != fwg_id).all()
if fwg_ports:
port_ids = [entry.port_id for entry in fwg_ports]
raise f_exc.FirewallGroupPortInUse(port_ids=port_ids)
def _get_default_fwg_id(self, context, tenant_id):
"""Returns an id of default firewall group for given tenant or None"""
default_fwg = self._model_query(context, FirewallGroup).filter_by(
project_id=tenant_id, name=const.DEFAULT_FWG).first()
if default_fwg:
return default_fwg.id
return None
def _ensure_default_firewall_group(self, context, tenant_id):
"""Create a default firewall group if one doesn't exist for a tenant
@ -905,19 +875,18 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
context, tenant_id, 'egress', **egress_fwp)
fwg = {
'firewall_group':
{'name': const.DEFAULT_FWG,
'tenant_id': tenant_id,
'ingress_firewall_policy_id': ingress_fwp_db['id'],
'egress_firewall_policy_id': egress_fwp_db['id'],
'ports': [],
'shared': False,
'admin_state_up': True,
'description': 'Default firewall group'}
'name': const.DEFAULT_FWG,
'tenant_id': tenant_id,
'ingress_firewall_policy_id': ingress_fwp_db['id'],
'egress_firewall_policy_id': egress_fwp_db['id'],
'ports': [],
'shared': False,
'status': nl_constants.INACTIVE,
'admin_state_up': True,
'description': 'Default firewall group',
}
fwg_db = self._create_firewall_group(
context, fwg, status=nl_constants.INACTIVE,
default_fwg=True)
context, fwg, default_fwg=True)
context.session.add(DefaultFirewallGroup(
firewall_group_id=fwg_db['id'],
project_id=tenant_id))
@ -928,37 +897,36 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
LOG.debug("Default FWG was concurrently created")
return self._get_default_fwg_id(context, tenant_id)
def _create_firewall_group(self, context, firewall_group, status=None,
def _create_firewall_group(self, context, firewall_group,
default_fwg=False):
"""Create a firewall group
If default_fwg is True then a default firewall group is being created
for a given tenant.
"""
fwg = firewall_group['firewall_group']
fwg = firewall_group
tenant_id = fwg['tenant_id']
if not status:
status = (nl_constants.CREATED if cfg.CONF.router_distributed
else nl_constants.PENDING_CREATE)
if firewall_group.get('status') is None:
fwg['status'] = nl_constants.CREATED
if default_fwg:
# A default firewall group is being created.
default_fwg_id = self._get_default_fwg_id(context, tenant_id)
if default_fwg_id is not None:
# Default fwg for a given tenant exists, fetch it and return
return self.get_firewall_group(default_fwg_id)
return self.get_firewall_group(context, default_fwg_id)
else:
# An ordinary firewall group is being created BUT let's make sure
# that a default firewall group for given tenant exists
self._ensure_default_firewall_group(context, tenant_id)
self._validate_tenant_for_fwg_policies(context, fwg, tenant_id)
with context.session.begin(subtransactions=True):
fwg_db = FirewallGroup(
id=uuidutils.generate_uuid(),
tenant_id=tenant_id,
name=fwg['name'],
description=fwg['description'],
status=status,
status=fwg['status'],
ingress_firewall_policy_id=fwg['ingress_firewall_policy_id'],
egress_firewall_policy_id=fwg['egress_firewall_policy_id'],
admin_state_up=fwg['admin_state_up'],
@ -967,15 +935,14 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
self._set_ports_for_firewall_group(context, fwg_db, fwg)
return self._make_firewall_group_dict(fwg_db)
def create_firewall_group(self, context, firewall_group, status=None):
def create_firewall_group(self, context, firewall_group):
self._ensure_not_default_resource(firewall_group, 'firewall_group')
return self._create_firewall_group(context, firewall_group, status)
return self._create_firewall_group(context, firewall_group)
def update_firewall_group(self, context, id, firewall_group):
LOG.debug("update_firewall_group() called")
fwg = firewall_group['firewall_group']
fwg = firewall_group
# make sure that no group can be updated to have name=default
self._ensure_not_default_resource(firewall_group, 'firewall_group')
self._ensure_not_default_resource(fwg, 'firewall_group')
with context.session.begin(subtransactions=True):
fwg_db = self.get_firewall_group(context, id)
if _is_default(fwg_db):
@ -990,8 +957,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
raise FirewallDefaultObjectUpdateRestricted(
resource_type='Firewall Group',
resource_id=fwg_db['id'])
self._validate_tenant_for_fwg_policies(context,
fwg, fwg_db['tenant_id'])
if 'ports' in fwg:
LOG.debug("Ports are updated in Firewall Group")
self._delete_ports_in_firewall_group(context, id)
@ -1021,7 +986,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
def delete_firewall_group(self, context, id):
# Note: Plugin should ensure that it's okay to delete if the
# firewall is active
LOG.debug("delete_firewall_group() called")
with context.session.begin(subtransactions=True):
# if no such group exists -> don't raise an exception according to
@ -1077,12 +1041,10 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
resource_type='Firewall Policy', name=resource['name'])
def get_firewall_group(self, context, id, fields=None):
LOG.debug("get_firewall_group() called")
fw = self._get_firewall_group(context, id)
return self._make_firewall_group_dict(fw, fields)
def get_firewall_groups(self, context, filters=None, fields=None):
LOG.debug("get_firewall_groups() called")
if context.tenant_id:
tenant_id = filters.get('tenant_id') if filters else None
tenant_id = tenant_id[0] if tenant_id else context.tenant_id
@ -1091,48 +1053,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin):
self._make_firewall_group_dict,
filters=filters, fields=fields)
def get_firewall_group_for_port(self, context, port_id):
"""Get firewall group is associated with a port
:param context: context object
:param port_id: Port ID.
"""
filters = {'port_id': [port_id]}
fwg_port_binding = self._get_collection_query(
context, FirewallGroupPortAssociation, filters=filters).first()
if fwg_port_binding:
fwg_id = fwg_port_binding['firewall_group_id']
return self._make_firewall_group_dict_with_rules(context, fwg_id)
def _get_default_fwg(self, context, project_id):
query = self._model_query(context, DefaultFirewallGroup)
def_fwg_id = query.filter_by(
project_id=project_id).one().firewall_group_id
return self.get_firewall_group(context, def_fwg_id)
def set_port_for_default_firewall_group(self, context, port_id,
project_id):
"""Set a port into default firewall group
:param context: Context object
:param port_id: Port ID
:param project_id: ProjectID
"""
with context.session.begin(subtransactions=True):
def_fwg_db = self._get_default_fwg(context, project_id)
try:
self._set_ports_for_firewall_group(
context, def_fwg_db, {'ports': [port_id]})
except f_exc.FirewallGroupPortInUse:
LOG.warning("Port %s has been already associated with default "
"firewall group %s and skip association", port_id,
def_fwg_db['id'])
else:
# Update default fwg status to PENDING_UPDATE to wait updating
# from agent
self.update_firewall_group_status(
context, def_fwg_db['id'], nl_constants.PENDING_UPDATE)
def _is_default(fwg_db):
return fwg_db['name'] == const.DEFAULT_FWG

View File

@ -126,6 +126,7 @@ class Firewallv2PluginBase(service_base.ServicePluginBase):
def get_plugin_description(self):
return 'Firewall Service v2 Plugin'
# Firewall Group
@abc.abstractmethod
def create_firewall_group(self, context, firewall_group):
pass
@ -135,7 +136,7 @@ class Firewallv2PluginBase(service_base.ServicePluginBase):
pass
@abc.abstractmethod
def get_firewall_group(self, context, id):
def get_firewall_group(self, context, id, fields=None):
pass
@abc.abstractmethod
@ -146,24 +147,13 @@ class Firewallv2PluginBase(service_base.ServicePluginBase):
def update_firewall_group(self, context, id, firewall_group):
pass
# Firewall Policy
@abc.abstractmethod
def get_firewall_rules(self, context, filters=None, fields=None):
def create_firewall_policy(self, context, firewall_policy):
pass
@abc.abstractmethod
def get_firewall_rule(self, context, id, fields=None):
pass
@abc.abstractmethod
def create_firewall_rule(self, context, firewall_rule):
pass
@abc.abstractmethod
def update_firewall_rule(self, context, id, firewall_rule):
pass
@abc.abstractmethod
def delete_firewall_rule(self, context, id):
def delete_firewall_policy(self, context, id):
pass
@abc.abstractmethod
@ -174,16 +164,29 @@ class Firewallv2PluginBase(service_base.ServicePluginBase):
def get_firewall_policies(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def create_firewall_policy(self, context, firewall_policy):
pass
@abc.abstractmethod
def update_firewall_policy(self, context, id, firewall_policy):
pass
# Firewall Rule
@abc.abstractmethod
def delete_firewall_policy(self, context, id):
def create_firewall_rule(self, context, firewall_rule):
pass
@abc.abstractmethod
def delete_firewall_rule(self, context, id):
pass
@abc.abstractmethod
def get_firewall_rule(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_firewall_rules(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def update_firewall_rule(self, context, id, firewall_rule):
pass
@abc.abstractmethod

View File

@ -10,19 +10,25 @@
# License for the specific language governing permissions and limitations
# under the License.
import neutron.conf.services.provider_configuration
import neutron_fwaas.services.firewall.service_drivers.agents.\
firewall_agent_api
import neutron_fwaas.extensions.firewall
import neutron_fwaas.services.firewall.agents.firewall_agent_api
def list_agent_opts():
return [
('fwaas',
neutron_fwaas.services.firewall.agents.firewall_agent_api.FWaaSOpts)
neutron_fwaas.services.firewall.service_drivers.agents.
firewall_agent_api.FWaaSOpts),
]
def list_opts():
return [
('quotas',
neutron_fwaas.extensions.firewall.firewall_quota_opts)
neutron_fwaas.extensions.firewall.firewall_quota_opts),
('service_providers',
neutron.conf.services.provider_configuration.serviceprovider_opts),
]

View File

@ -12,238 +12,138 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron.common import rpc as n_rpc
from neutron.db import servicetype_db as st_db
from neutron.services import provider_configuration as provider_conf
from neutron.services import service_base
from neutron_lib.api.definitions import firewall_v2
from neutron_lib.api.definitions import portbindings as pb_def
from neutron_lib.api import validators
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import constants as nl_constants
from neutron_lib import context as neutron_context
from neutron_lib.exceptions import firewall_v2 as f_exc
from neutron_lib.plugins import constants as plugin_const
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_log import helpers as log_helpers
from oslo_log import log as logging
import oslo_messaging
from neutron_fwaas.common import exceptions
from neutron_fwaas.common import fwaas_constants
from neutron_fwaas.db.firewall.v2 import firewall_db_v2
from neutron_fwaas.extensions.firewall_v2 import Firewallv2PluginBase
LOG = logging.getLogger(__name__)
def add_provider_configuration(type_manager, service_type):
type_manager.add_provider_configuration(
service_type,
provider_conf.ProviderConfiguration('neutron_fwaas'))
class FirewallAgentApi(object):
"""Plugin side of plugin to agent RPC API."""
def __init__(self, topic, host):
self.host = host
target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target)
def create_firewall_group(self, context, firewall_group):
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'create_firewall_group',
firewall_group=firewall_group,
host=self.host)
def update_firewall_group(self, context, firewall_group):
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'update_firewall_group',
firewall_group=firewall_group,
host=self.host)
def delete_firewall_group(self, context, firewall_group):
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'delete_firewall_group',
firewall_group=firewall_group,
host=self.host)
class FirewallCallbacks(object):
target = oslo_messaging.Target(version='1.0')
def __init__(self, plugin):
super(FirewallCallbacks, self).__init__()
self.plugin = plugin
def set_firewall_group_status(self, context, fwg_id, status, **kwargs):
"""Agent uses this to set a firewall_group's status."""
LOG.debug("Setting firewall_group %s to status: %s",
fwg_id, status)
# Sanitize status first
if status in (nl_constants.ACTIVE, nl_constants.DOWN,
nl_constants.INACTIVE):
to_update = status
else:
to_update = nl_constants.ERROR
# ignore changing status if firewall_group expects to be deleted
# That case means that while some pending operation has been
# performed on the backend, neutron server received delete request
# and changed firewall status to PENDING_DELETE
updated = self.plugin.update_firewall_group_status(
context, fwg_id, to_update, not_in=(nl_constants.PENDING_DELETE,))
if updated:
LOG.debug("firewall %s status set: %s", fwg_id, to_update)
return updated and to_update != nl_constants.ERROR
def firewall_group_deleted(self, context, fwg_id, **kwargs):
"""Agent uses this to indicate firewall is deleted."""
LOG.debug("firewall_group_deleted() called")
try:
with context.session.begin(subtransactions=True):
fwg_db = self.plugin._get_firewall_group(context, fwg_id)
# allow to delete firewalls in ERROR state
if fwg_db.status in (nl_constants.PENDING_DELETE,
nl_constants.ERROR):
self.plugin.delete_db_firewall_group_object(context,
fwg_id)
return True
else:
LOG.warning(('Firewall %(fwg)s unexpectedly deleted by '
'agent, status was %(status)s'),
{'fwg': fwg_id, 'status': fwg_db.status})
fwg_db.update({"status": nl_constants.ERROR})
return False
except f_exc.FirewallGroupNotFound:
LOG.info('Firewall group %s already deleted', fwg_id)
return True
def get_firewall_groups_for_project(self, context, **kwargs):
"""Gets all firewall_groups and rules on a project."""
LOG.debug("get_firewall_groups_for_project() called")
fwg_list = []
for fwg in self.plugin.get_firewall_groups(context):
fwg_with_rules = self.plugin._make_firewall_group_dict_with_rules(
context, fwg['id'])
if fwg['status'] == nl_constants.PENDING_DELETE:
fwg_with_rules['add-port-ids'] = []
fwg_with_rules['del-port-ids'] = (
self.plugin._get_ports_in_firewall_group(context,
fwg['id']))
else:
fwg_with_rules['add-port-ids'] = (
self.plugin._get_ports_in_firewall_group(context,
fwg['id']))
fwg_with_rules['del-port-ids'] = []
fwg_list.append(fwg_with_rules)
return fwg_list
def get_projects_with_firewall_groups(self, context, **kwargs):
"""Get all projects that have firewall_groups."""
LOG.debug("get_projects_with_firewall_groups() called")
ctx = neutron_context.get_admin_context()
fwg_list = self.plugin.get_firewall_groups(ctx)
fwg_project_list = list(set(fwg['tenant_id'] for fwg in fwg_list))
return fwg_project_list
def get_firewall_group_for_port(self, context, **kwargs):
"""Get firewall_group is associated with a port."""
LOG.debug("get_firewall_group_for_port() called")
ctx = context.elevated()
return self.plugin.get_firewall_group_for_port(
ctx, kwargs.get('port_id'))
@registry.has_registry_receivers
class FirewallPluginV2(
firewall_db_v2.Firewall_db_mixin_v2):
"""Implementation of the Neutron Firewall Service Plugin.
class FirewallPluginV2(Firewallv2PluginBase):
"""Firewall v2 Neutron service plugin class"""
This class manages the workflow of FWaaS request/response.
Most DB related works are implemented in class
firewall_db_v2.Firewall_db_mixin_v2.
"""
supported_extension_aliases = ["fwaas_v2"]
supported_extension_aliases = [firewall_v2.ALIAS]
path_prefix = firewall_v2.API_PREFIX
def __init__(self):
super(FirewallPluginV2, self).__init__()
"""Do the initialization for the firewall service plugin here."""
self.service_type_manager = st_db.ServiceTypeManager.get_instance()
add_provider_configuration(
self.service_type_manager, plugin_const.FIREWALL)
self.start_rpc_listeners()
# Initialize the Firewall v2 service plugin
service_type_manager = st_db.ServiceTypeManager.get_instance()
service_type_manager.add_provider_configuration(
fwaas_constants.FIREWALL_V2,
provider_conf.ProviderConfiguration('neutron_fwaas'))
self.agent_rpc = FirewallAgentApi(
fwaas_constants.FW_AGENT,
cfg.CONF.host
)
# Load the default driver
drivers, default_provider = service_base.load_drivers(
fwaas_constants.FIREWALL_V2, self)
LOG.info("Firewall v2 Service Plugin using Service Driver: %s",
default_provider)
if len(drivers) > 1:
LOG.warning("Multiple drivers configured for Firewall v2, "
"although running multiple drivers in parallel is "
"not yet supported")
self.driver = drivers[default_provider]
@property
def _core_plugin(self):
return directory.get_plugin()
def start_rpc_listeners(self):
self.endpoints = [FirewallCallbacks(self)]
self.conn = n_rpc.Connection()
self.conn.create_consumer(
fwaas_constants.FIREWALL_PLUGIN, self.endpoints, fanout=False)
return self.conn.consume_in_threads()
def _rpc_update_firewall_group(self, context, fwg_id):
status_update = {"firewall_group": {"status":
nl_constants.PENDING_UPDATE}}
super(FirewallPluginV2, self).update_firewall_group(
context, fwg_id, status_update)
fwg_with_rules = self._make_firewall_group_dict_with_rules(context,
fwg_id)
# this is triggered on an update to fwg rule or policy, no
# change in associated ports.
fwg_with_rules['add-port-ids'] = self._get_ports_in_firewall_group(
context, fwg_id)
fwg_with_rules['del-port-ids'] = []
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, fwg_with_rules['add-port-ids'])
self.agent_rpc.update_firewall_group(context, fwg_with_rules)
def _rpc_update_firewall_policy(self, context, firewall_policy_id):
firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
if firewall_policy:
ing_fwg_ids, eg_fwg_ids = self._get_fwgs_with_policy(context,
firewall_policy_id)
for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)):
self._rpc_update_firewall_group(context, fwg_id)
def _ensure_update_firewall_group(self, context, fwg_id):
"""Checks if the firewall group can be updated
Raises FirewallGroupInPendingState if the firewall group is in pending
state.
:param context: neutron context
:param fwg_id: firewall group ID to check
:return: Firewall group dict
"""
fwg = self.get_firewall_group(context, fwg_id)
if fwg['status'] in [nl_constants.PENDING_CREATE,
nl_constants.PENDING_UPDATE,
nl_constants.PENDING_DELETE]:
raise f_exc.FirewallGroupInPendingState(firewall_id=fwg_id,
pending_state=fwg['status'])
raise f_exc.FirewallGroupInPendingState(
firewall_id=fwg_id, pending_state=fwg['status'])
return fwg
def _ensure_update_firewall_policy(self, context, firewall_policy_id):
firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
if firewall_policy:
ing_fwg_ids, eg_fwg_ids = self._get_fwgs_with_policy(
context, firewall_policy_id)
for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)):
self._ensure_update_firewall_group(context, fwg_id)
def _ensure_update_firewall_policy(self, context, fwp_id):
"""Checks if the firewall policy can be updated
Fetch firewall group associated to the policy and checks if they can be
updated.
:param context: neutron context
:param fwp_id: firewall policy ID to check
"""
fwp = self.get_firewall_policy(context, fwp_id)
ing_fwg_ids, eg_fwg_ids = self._get_fwgs_with_policy(context, fwp)
for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)):
self._ensure_update_firewall_group(context, fwg_id)
def _ensure_update_firewall_rule(self, context, fwr_id):
fwp_ids = self._get_policies_with_rule(context, fwr_id)
"""Checks if the firewall rule can be updated
Fetch firewall policy associated to the rule and checks if they can be
updated.
:param context: neutron context
:param fwr_id: firewall policy ID to check
"""
fwr = self.get_firewall_rule(context, fwr_id)
fwp_ids = self._get_policies_with_rule(context, fwr)
for fwp_id in fwp_ids:
self._ensure_update_firewall_policy(context, fwp_id)
def _validate_firewall_policies_for_firewall_group(self, context, fwg):
"""Validate firewall group and policy owner
Check if the firewall policy is not shared, it have the same project
owner than the friewall group.
:param context: neutron context
:param fwg: firewall group to validate
"""
for policy_type in ['ingress_firewall_policy_id',
'egress_firewall_policy_id']:
if fwg.get(policy_type):
fwp = self.get_firewall_policy(context, fwg[policy_type])
if fwg['tenant_id'] != fwp['tenant_id'] and not fwp['shared']:
raise f_exc.FirewallPolicyConflict(
firewall_policy_id=fwg[policy_type])
def _validate_ports_for_firewall_group(self, context, tenant_id,
fwg_ports):
"""Validate firewall group associated ports
Check if the firewall group associated ports have the same project
owner and is router interface type or a compute layer 2.
:param context: neutron context
:param tenant_id: firewall group project ID
:param fwg_ports: firewall group associated ports
"""
# TODO(sridar): elevated context and do we want to use public ?
for port_id in fwg_ports:
port_db = self._core_plugin._get_port(context, port_id)
if port_db['tenant_id'] != tenant_id:
port = self._core_plugin.get_port(context, port_id)
if port['tenant_id'] != tenant_id:
raise f_exc.FirewallGroupPortInvalidProject(
port_id=port_id, project_id=port_db['tenant_id'])
device_owner = port_db.get('device_owner', '')
port_id=port_id, project_id=port['tenant_id'])
device_owner = port.get('device_owner', '')
if (device_owner not in [nl_constants.DEVICE_OWNER_ROUTER_INTF] and
not device_owner.startswith(
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX)):
@ -253,6 +153,8 @@ class FirewallPluginV2(
self._is_supported_by_fw_l2_driver(context, port_id)):
raise exceptions.FirewallGroupPortNotSupported(port_id=port_id)
# TODO(ethuleau): move that check in the driver. Each driver can have
# different support
def _is_supported_by_fw_l2_driver(self, context, port_id):
"""Whether this port is supported by firewall l2 driver"""
@ -277,49 +179,80 @@ class FirewallPluginV2(
LOG.warning("Doesn't support vif type %s", port[pb_def.VIF_TYPE])
return False
def _check_no_need_pending(self, context, fwg_id, fwg_body):
fwg_db = self._get_firewall_group(context, fwg_id)
fwp_req_in = fwg_body.get('ingress_firewall_policy_id', None)
fwp_req_eg = fwg_body.get('egress_firewall_policy_id', None)
def _validate_if_firewall_group_on_ports(self, context, firewall_group,
id=None):
"""Validate if ports are not associated with any firewall_group.
if ((not fwg_db.ingress_firewall_policy_id and
fwp_req_in is fwg_db.ingress_firewall_policy_id) and
(not fwg_db.egress_firewall_policy_id and
fwp_req_eg is fwg_db.ingress_firewall_policy_id)):
return True
return False
If any of the ports in the list is already associated with
a firewall group, raise an exception else just return.
:param context: neutron context
:param fwg: firewall group to validate
"""
if 'ports' not in firewall_group or not firewall_group['ports']:
return
def _get_fwg_port_details(self, context, fwg_ports):
"""Returns a dictionary list of port details. """
port_details = {}
for port_id in fwg_ports:
port_db = self._core_plugin.get_port(context, port_id)
# Add more parameters below based on requirement.
device_owner = port_db['device_owner']
port_details[port_id] = {
'device_owner': device_owner,
'device': port_db['id'],
'network_id': port_db['network_id'],
'fixed_ips': port_db['fixed_ips'],
'allowed_address_pairs':
port_db.get('allowed_address_pairs', []),
'port_security_enabled':
port_db.get('port_security_enabled', True),
'id': port_db['id']
}
if device_owner.startswith(
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX):
port_details[port_id].update(
{'host': port_db[pb_def.HOST_ID]})
return port_details
filters = {
'tenant_id': [firewall_group['tenant_id']],
'ports': firewall_group['ports'],
}
ports_in_use = set()
for fwg in self.get_firewall_groups(context, filters=filters):
if id is not None and fwg['id'] == id:
continue
ports_in_use |= set(fwg.get('ports', [])) & \
set(firewall_group['ports'])
if ports_in_use:
raise f_exc.FirewallGroupPortInUse(port_ids=list(ports_in_use))
def get_project_id_from_port_id(self, context, port_id):
"""Returns an ID of project for specified port_id. """
return self._core_plugin.get_port(context, port_id)['project_id']
def _get_fwgs_with_policy(self, context, firewall_policy):
"""List firewall group IDs which use a firewall policy
List all firewall group IDs which have the given firewall policy as
ingress or egress.
:param context: neutron context
:param firewall_policy: firewall policy to filter
"""
filters = {
'tenant_id': [firewall_policy['tenant_id']],
'ingress_firewall_policy_id': [firewall_policy['id']],
}
ingress_fwp_ids = [fwg['id']
for fwg in self.get_firewall_groups(
context, filters=filters)]
filters = {
'tenant_id': [firewall_policy['tenant_id']],
'egress_firewall_policy_id': [firewall_policy['id']],
}
egress_fwp_ids = [fwg['id']
for fwg in self.get_firewall_groups(
context, filters=filters)]
return ingress_fwp_ids, egress_fwp_ids
def _get_policies_with_rule(self, context, firewall_rule):
filters = {
'tenant_id': [firewall_rule['tenant_id']],
'firewall_rules': [firewall_rule['id']],
}
return [fwp['id'] for fwp in self.get_firewall_policies(
context, filters=filters)]
def _validate_insert_remove_rule_request(self, rule_info):
"""Validate rule_info dict
Check that all mandatory fields are present, otherwise raise
proper exception.
"""
if not rule_info or 'firewall_rule_id' not in rule_info:
raise f_exc.FirewallRuleInfoMissing()
# Validator doesn't return anything if the check passes
if validators.validate_uuid(rule_info['firewall_rule_id']):
raise f_exc.FirewallRuleNotFound(
firewall_rule_id=rule_info['firewall_rule_id'])
@registry.receives(resources.PORT, [events.AFTER_UPDATE])
def handle_update_port(self, resource, event, trigger, **kwargs):
updated_port = kwargs['port']
if not updated_port['device_owner'].startswith(
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX):
@ -340,169 +273,145 @@ class FirewallPluginV2(
return
project_id = updated_port['project_id']
LOG.debug("Try to associate port %s at %s", port_id, project_id)
self.set_port_for_default_firewall_group(context, port_id, project_id)
fwgs = self.get_firewall_groups(
context,
filters={
'tenant_id': [project_id],
'name': [fwaas_constants.DEFAULT_FWG],
},
fields=['id', 'ports'],
)
if len(fwgs) != 1:
# Cannot found default Firewall Group, abandon
LOG.warning("Cannot found default firewall group of project %s",
project_id)
return
default_fwg = fwgs[0]
# Add default firewall group to the port
port_ids = default_fwg.get('ports', []) + [port_id]
try:
self.update_firewall_group(context, default_fwg['id'],
{'firewall_group': {'ports': port_ids}})
except f_exc.FirewallGroupPortInUse:
LOG.warning("Port %s has been already associated with default "
"firewall group %s and skip association", port_id,
default_fwg['id'])
# Firewall Group
@log_helpers.log_method_call
def create_firewall_group(self, context, firewall_group):
LOG.debug("create_firewall_group() called")
fwgrp = firewall_group['firewall_group']
fwg_ports = fwgrp['ports']
firewall_group = firewall_group['firewall_group']
ports = firewall_group.get('ports', [])
if not fwg_ports:
# no messaging to agent needed, and fw needs to go
# to INACTIVE(no associated ports) state.
status = nl_constants.INACTIVE
fwg = super(FirewallPluginV2, self).create_firewall_group(
context, firewall_group, status)
fwg['ports'] = []
return fwg
else:
# Validate ports
self._validate_ports_for_firewall_group(context,
firewall_group['firewall_group']['tenant_id'], fwg_ports)
self._validate_firewall_policies_for_firewall_group(context,
firewall_group)
# Validate ports owner type and project
self._validate_ports_for_firewall_group(context,
firewall_group['tenant_id'],
ports)
if (not fwgrp['ingress_firewall_policy_id'] and
not fwgrp['egress_firewall_policy_id']):
# No policy configured
status = nl_constants.INACTIVE
fwg = super(FirewallPluginV2, self).create_firewall_group(
context, firewall_group, status)
return fwg
self._validate_if_firewall_group_on_ports(context, firewall_group)
fwg = super(FirewallPluginV2, self).create_firewall_group(
context, firewall_group)
fwg['ports'] = fwg_ports
fwg_with_rules = (
self._make_firewall_group_dict_with_rules(context, fwg['id']))
fwg_with_rules['add-port-ids'] = fwg_ports
fwg_with_rules['del-port-ids'] = []
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, fwg_ports)
self.agent_rpc.create_firewall_group(context, fwg_with_rules)
return fwg
def update_firewall_group(self, context, id, firewall_group):
LOG.debug("update_firewall_group() called on firewall_group %s", id)
self._ensure_update_firewall_group(context, id)
# TODO(sridar): need closure on status when no policy associated.
fwg_current_ports = fwg_new_ports = self._get_ports_in_firewall_group(
context, id)
if 'ports' in firewall_group['firewall_group']:
fwg_new_ports = firewall_group['firewall_group']['ports']
if len(fwg_new_ports) > 0:
self._validate_ports_for_firewall_group(
context, context.project_id, fwg_new_ports)
if ((not fwg_new_ports and not fwg_current_ports) or
self._check_no_need_pending(context,
id, firewall_group['firewall_group'])):
# no messaging to agent needed, and we need to continue
# in INACTIVE state
firewall_group['firewall_group']['status'] = nl_constants.INACTIVE
fwg = super(FirewallPluginV2, self).update_firewall_group(
context, id, firewall_group)
if fwg_new_ports:
fwg['ports'] = fwg_new_ports
elif not fwg_new_ports and fwg_current_ports:
fwg['ports'] = fwg_current_ports
else:
fwg['ports'] = []
return fwg
else:
firewall_group['firewall_group']['status'] = (nl_constants.
PENDING_UPDATE)
fwg = super(FirewallPluginV2, self).update_firewall_group(
context, id, firewall_group)
fwg['ports'] = fwg_new_ports
fwg_with_rules = (
self._make_firewall_group_dict_with_rules(context, fwg['id']))
# determine ports to add fw to and del from
fwg_with_rules['add-port-ids'] = fwg_new_ports
fwg_with_rules['del-port-ids'] = list(
set(fwg_current_ports).difference(set(fwg_new_ports)))
# last-port drives agent to ack with status to set state to INACTIVE
fwg_with_rules['last-port'] = not fwg_new_ports
LOG.debug("update_firewall_group %s: Add Ports: %s, Del Ports: %s",
fwg['id'],
fwg_with_rules['add-port-ids'],
fwg_with_rules['del-port-ids'])
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, fwg_with_rules['del-port-ids'])
fwg_with_rules['port_details'].update(self._get_fwg_port_details(
context, fwg_with_rules['add-port-ids']))
self.agent_rpc.update_firewall_group(context, fwg_with_rules)
return fwg
def delete_db_firewall_group_object(self, context, id):
super(FirewallPluginV2, self).delete_firewall_group(context, id)
return self.driver.create_firewall_group(context, firewall_group)
@log_helpers.log_method_call
def delete_firewall_group(self, context, id):
LOG.debug("delete_firewall_group() called on firewall_group %s", id)
# if no such group exists -> don't raise an exception according to
# 80fe2ba1, return None
try:
fwg = self.get_firewall_group(context, id)
except f_exc.FirewallGroupNotFound:
return
fwg_db = self._get_firewall_group(context, id)
if fwg_db['status'] == nl_constants.ACTIVE:
if fwg['status'] == nl_constants.ACTIVE:
raise f_exc.FirewallGroupInUse(firewall_id=id)
fwg_with_rules = (
self._make_firewall_group_dict_with_rules(context, id))
fwg_with_rules['del-port-ids'] = self._get_ports_in_firewall_group(
context, id)
fwg_with_rules['add-port-ids'] = []
if not fwg_with_rules['del-port-ids']:
# no ports, no need to talk to the agent
self.delete_db_firewall_group_object(context, id)
else:
status = {"firewall_group": {"status":
nl_constants.PENDING_DELETE}}
super(FirewallPluginV2, self).update_firewall_group(
context, id, status)
# Reflect state change in fwg_with_rules
fwg_with_rules['status'] = status['firewall_group']['status']
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, fwg_with_rules['del-port-ids'])
self.agent_rpc.delete_firewall_group(context, fwg_with_rules)
self.driver.delete_firewall_group(context, id)
@log_helpers.log_method_call
def get_firewall_group(self, context, id, fields=None):
return self.driver.get_firewall_group(context, id, fields=fields)
@log_helpers.log_method_call
def get_firewall_groups(self, context, filters=None, fields=None):
return self.driver.get_firewall_groups(context, filters, fields)
@log_helpers.log_method_call
def update_firewall_group(self, context, id, firewall_group):
firewall_group = firewall_group['firewall_group']
ports = firewall_group.get('ports', [])
old_firewall_group = self._ensure_update_firewall_group(context, id)
firewall_group['tenant_id'] = old_firewall_group['tenant_id']
self._validate_firewall_policies_for_firewall_group(context,
firewall_group)
# Validate ports owner type and project
self._validate_ports_for_firewall_group(context,
firewall_group['tenant_id'],
ports)
self._validate_if_firewall_group_on_ports(context, firewall_group,
id=id)
return self.driver.update_firewall_group(context, id, firewall_group)
# Firewall Policy
@log_helpers.log_method_call
def create_firewall_policy(self, context, firewall_policy):
firewall_policy = firewall_policy['firewall_policy']
return self.driver.create_firewall_policy(context, firewall_policy)
@log_helpers.log_method_call
def delete_firewall_policy(self, context, id):
self.driver.delete_firewall_policy(context, id)
@log_helpers.log_method_call
def get_firewall_policy(self, context, id, fields=None):
return self.driver.get_firewall_policy(context, id, fields)
@log_helpers.log_method_call
def get_firewall_policies(self, context, filters=None, fields=None):
return self.driver.get_firewall_policies(context, filters, fields)
@log_helpers.log_method_call
def update_firewall_policy(self, context, id, firewall_policy):
LOG.debug("update_firewall_policy() called")
firewall_policy = firewall_policy['firewall_policy']
self._ensure_update_firewall_policy(context, id)
fwp = super(FirewallPluginV2,
self).update_firewall_policy(context, id, firewall_policy)
self._rpc_update_firewall_policy(context, id)
return fwp
return self.driver.update_firewall_policy(context, id, firewall_policy)
# Firewall Rule
@log_helpers.log_method_call
def create_firewall_rule(self, context, firewall_rule):
firewall_rule = firewall_rule['firewall_rule']
return self.driver.create_firewall_rule(context, firewall_rule)
@log_helpers.log_method_call
def delete_firewall_rule(self, context, id):
self.driver.delete_firewall_rule(context, id)
@log_helpers.log_method_call
def get_firewall_rule(self, context, id, fields=None):
return self.driver.get_firewall_rule(context, id, fields)
@log_helpers.log_method_call
def get_firewall_rules(self, context, filters=None, fields=None):
return self.driver.get_firewall_rules(context, filters, fields)
@log_helpers.log_method_call
def update_firewall_rule(self, context, id, firewall_rule):
LOG.debug("update_firewall_rule() called")
firewall_rule = firewall_rule['firewall_rule']
self._ensure_update_firewall_rule(context, id)
fwr = super(FirewallPluginV2,
self).update_firewall_rule(context, id, firewall_rule)
fwp_ids = self._get_policies_with_rule(context, id)
for fwp_id in fwp_ids:
self._rpc_update_firewall_policy(context, fwp_id)
return fwr
return self.driver.update_firewall_rule(context, id, firewall_rule)
def insert_rule(self, context, id, rule_info):
LOG.debug("insert_rule() called")
self._ensure_update_firewall_policy(context, id)
fwp = super(FirewallPluginV2, self).insert_rule(context, id, rule_info)
self._rpc_update_firewall_policy(context, id)
return fwp
@log_helpers.log_method_call
def insert_rule(self, context, policy_id, rule_info):
self._ensure_update_firewall_policy(context, policy_id)
self._validate_insert_remove_rule_request(rule_info)
return self.driver.insert_rule(context, policy_id, rule_info)
def remove_rule(self, context, id, rule_info):
LOG.debug("remove_rule() called")
self._ensure_update_firewall_policy(context, id)
fwp = super(FirewallPluginV2, self).remove_rule(context, id, rule_info)
self._rpc_update_firewall_policy(context, id)
return fwp
@log_helpers.log_method_call
def remove_rule(self, context, policy_id, rule_info):
self._ensure_update_firewall_policy(context, policy_id)
self._validate_insert_remove_rule_request(rule_info)
return self.driver.remove_rule(context, policy_id, rule_info)

View File

@ -0,0 +1,355 @@
# Copyright (c) 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.
from neutron.common import rpc as neutron_rpc
from neutron_lib.api.definitions import portbindings as pb_def
from neutron_lib import constants as nl_constants
from neutron_lib import context as neutron_context
from neutron_lib.exceptions import firewall_v2 as f_exc
from oslo_config import cfg
from oslo_log import helpers as log_helpers
from oslo_log import log as logging
import oslo_messaging
from neutron_fwaas.common import fwaas_constants as constants
from neutron_fwaas.services.firewall.service_drivers import driver_api
LOG = logging.getLogger(__name__)
class FirewallAgentCallbacks(object):
target = oslo_messaging.Target(version='1.0')
def __init__(self, firewall_db):
self.firewall_db = firewall_db
@log_helpers.log_method_call
def set_firewall_group_status(self, context, fwg_id, status, **kwargs):
"""Agent uses this to set a firewall_group's status."""
# Sanitize status first
if status in (nl_constants.ACTIVE, nl_constants.DOWN,
nl_constants.INACTIVE):
to_update = status
else:
to_update = nl_constants.ERROR
# ignore changing status if firewall_group expects to be deleted
# That case means that while some pending operation has been
# performed on the backend, neutron server received delete request
# and changed firewall status to PENDING_DELETE
updated = self.firewall_db.update_firewall_group_status(
context, fwg_id, to_update, not_in=(nl_constants.PENDING_DELETE,))
if updated:
LOG.debug("firewall %s status set: %s", fwg_id, to_update)
return updated and to_update != nl_constants.ERROR
@log_helpers.log_method_call
def firewall_group_deleted(self, context, fwg_id, **kwargs):
"""Agent uses this to indicate firewall is deleted."""
try:
fwg = self.firewall_db.get_firewall_group(context, fwg_id)
# allow to delete firewalls in ERROR state
if fwg['status'] in (nl_constants.PENDING_DELETE,
nl_constants.ERROR):
self.firewall_db.delete_firewall_group(context, fwg_id)
return True
LOG.warning('Firewall %(fwg)s unexpectedly deleted by agent, '
'status was %(status)s',
{'fwg': fwg_id, 'status': fwg['status']})
fwg['status'] = nl_constants.ERROR
self.firewall_db.update_firewall_group(context, fwg_id, fwg)
return False
except f_exc.FirewallGroupNotFound:
LOG.info('Firewall group %s already deleted', fwg_id)
return True
@log_helpers.log_method_call
def get_firewall_groups_for_project(self, context, **kwargs):
"""Gets all firewall_groups and rules on a project."""
fwg_list = []
for fwg in self.firewall_db.get_firewall_groups(context):
fwg_with_rules =\
self.firewall_db.make_firewall_group_dict_with_rules(
context, fwg['id'])
if fwg['status'] == nl_constants.PENDING_DELETE:
fwg_with_rules['add-port-ids'] = []
fwg_with_rules['del-port-ids'] = (
self.firewall_db.get_ports_in_firewall_group(
context, fwg['id']))
else:
fwg_with_rules['add-port-ids'] = (
self.firewall_db.get_ports_in_firewall_group(
context, fwg['id']))
fwg_with_rules['del-port-ids'] = []
fwg_list.append(fwg_with_rules)
return fwg_list
@log_helpers.log_method_call
def get_projects_with_firewall_groups(self, context, **kwargs):
"""Get all projects that have firewall_groups."""
ctx = neutron_context.get_admin_context()
fwg_list = self.firewall_db.get_firewall_groups(ctx)
fwg_project_list = list(set(fwg['tenant_id'] for fwg in fwg_list))
return fwg_project_list
@log_helpers.log_method_call
def get_firewall_group_for_port(self, context, **kwargs):
"""Get firewall_group is associated with a port."""
ctx = context.elevated()
# Only one Firewall Group can be associated to a port at a time
fwg_port_binding = self.firewall_db.get_firewall_groups(
ctx, filters={'ports': [kwargs.get('port_id')]})
if len(fwg_port_binding) != 1:
return
fwg = fwg_port_binding[0]
fwg['ingress_rule_list'] = []
for rule_id in self.firewall_db.get_firewall_policy(
context, fwg['ingress_firewall_policy_id'],
fields=['firewall_rules'])['firewall_rules']:
fwg['ingress_rule_list'].append(
self.firewall_db.get_firewall_rule(context, rule_id))
fwg['egress_rule_list'] = []
for rule_id in self.firewall_db.get_firewall_policy(
context, fwg['egress_firewall_policy_id'],
fields=['firewall_rules'])['firewall_rules']:
fwg['egress_rule_list'].append(
self.firewall_db.get_firewall_rule(context, rule_id))
return fwg
class FirewallAgentApi(object):
"""Plugin side of plugin to agent RPC API"""
def __init__(self, topic, host):
self.host = host
target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = neutron_rpc.get_client(target)
def create_firewall_group(self, context, firewall_group):
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'create_firewall_group',
firewall_group=firewall_group, host=self.host)
def update_firewall_group(self, context, firewall_group):
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'update_firewall_group',
firewall_group=firewall_group, host=self.host)
def delete_firewall_group(self, context, firewall_group):
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'delete_firewall_group',
firewall_group=firewall_group, host=self.host)
class FirewallAgentDriver(driver_api.FirewallDriverDB):
"""Firewall driver to implement agent messages and callback methods
Implement RPC Firewall v2 API and callback methods for agents based on
Neutron DB model.
"""
def __init__(self, service_plugin):
super(FirewallAgentDriver, self).__init__(service_plugin)
self.agent_rpc = FirewallAgentApi(constants.FW_AGENT, cfg.CONF.host)
self.start_rpc_listeners()
def start_rpc_listeners(self):
self.endpoints = [FirewallAgentCallbacks(self.firewall_db)]
self.rpc_connection = neutron_rpc.Connection()
self.rpc_connection.create_consumer(constants.FIREWALL_PLUGIN,
self.endpoints, fanout=False)
self.rpc_connection.consume_in_threads()
def _rpc_update_firewall_group(self, context, fwg_id):
status_update = {"status": nl_constants.PENDING_UPDATE}
self.update_firewall_group(context, fwg_id, status_update)
fwg_with_rules = self.firewall_db.make_firewall_group_dict_with_rules(
context, fwg_id)
# this is triggered on an update to fwg rule or policy, no
# change in associated ports.
fwg_with_rules['add-port-ids'] = \
self.firewall_db.get_ports_in_firewall_group(context, fwg_id)
fwg_with_rules['del-port-ids'] = []
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, fwg_with_rules['add-port-ids'])
self.agent_rpc.update_firewall_group(context, fwg_with_rules)
def _rpc_update_firewall_policy(self, context, firewall_policy_id):
firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
if firewall_policy:
ing_fwg_ids, eg_fwg_ids = self.firewall_db.get_fwgs_with_policy(
context, firewall_policy_id)
for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)):
self._rpc_update_firewall_group(context, fwg_id)
def _get_fwg_port_details(self, context, fwg_ports):
"""Returns a dictionary list of port details. """
port_details = {}
for port_id in fwg_ports:
port_db = self._core_plugin.get_port(context, port_id)
# Add more parameters below based on requirement.
device_owner = port_db['device_owner']
port_details[port_id] = {
'device_owner': device_owner,
'device': port_db['id'],
'network_id': port_db['network_id'],
'fixed_ips': port_db['fixed_ips'],
'allowed_address_pairs':
port_db.get('allowed_address_pairs', []),
'port_security_enabled':
port_db.get('port_security_enabled', True),
'id': port_db['id'],
'status': port_db['status'],
}
if device_owner.startswith(
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX):
port_details[port_id].update(
{'host': port_db[pb_def.HOST_ID]})
return port_details
def create_firewall_group_precommit(self, context, firewall_group):
ports = firewall_group['ports']
if (not ports or (not firewall_group['ingress_firewall_policy_id'] and
not firewall_group['egress_firewall_policy_id'])):
# no messaging to agent needed and fw needs to go to INACTIVE state
# as no associated ports and/or no policy configured.
status = nl_constants.INACTIVE
else:
status = (nl_constants.CREATED if cfg.CONF.router_distributed
else nl_constants.PENDING_CREATE)
firewall_group['status'] = status
def create_firewall_group_postcommit(self, context, firewall_group):
if firewall_group['status'] != nl_constants.INACTIVE:
fwg_with_rules =\
self.firewall_db.make_firewall_group_dict_with_rules(
context, firewall_group['id'])
fwg_with_rules['add-port-ids'] = firewall_group['ports']
fwg_with_rules['del-ports-id'] = []
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, firewall_group['ports'])
self.agent_rpc.create_firewall_group(context, fwg_with_rules)
def delete_firewall_group_precommit(self, context, firewall_group):
if firewall_group['status'] == nl_constants.ACTIVE:
raise f_exc.FirewallGroupInUse(firewall_id=firewall_group['id'])
elif firewall_group['status'] != nl_constants.INACTIVE:
# Firewall group is in inconsistent state, remove it
return
if not firewall_group['ports']:
# No associated port, can safety remove it
return
# Need to prevent agent to delete the firewall group before delete it
self.firewall_db.update_firewall_group_status(
context, firewall_group['id'], nl_constants.PENDING_DELETE)
firewall_group['status'] = nl_constants.PENDING_DELETE
fwg_with_rules = self.firewall_db.make_firewall_group_dict_with_rules(
context, firewall_group['id'])
fwg_with_rules['del-port-ids'] = firewall_group['ports']
fwg_with_rules['add-port-ids'] = []
# Reflect state change in fwg_with_rules
fwg_with_rules['status'] = nl_constants.PENDING_DELETE
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, fwg_with_rules['del-port-ids'])
self.agent_rpc.delete_firewall_group(context, fwg_with_rules)
def _need_pending_update(self, old_firewall_group, new_firewall_group):
port_updated = (set(new_firewall_group['ports']) !=
set(old_firewall_group['ports']))
policies_updated = (
new_firewall_group['ingress_firewall_policy_id'] !=
old_firewall_group['ingress_firewall_policy_id'] or
new_firewall_group['egress_firewall_policy_id'] !=
old_firewall_group['egress_firewall_policy_id']
)
if (port_updated and
(new_firewall_group['ingress_firewall_policy_id'] or
new_firewall_group['egress_firewall_policy_id'])):
return True
if policies_updated and new_firewall_group['ports']:
return True
return False
def update_firewall_group_precommit(self, context, old_firewall_group,
new_firewall_group):
if self._need_pending_update(old_firewall_group, new_firewall_group):
new_firewall_group['status'] = nl_constants.PENDING_UPDATE
def update_firewall_group_postcommit(self, context, old_firewall_group,
new_firewall_group):
if not self._need_pending_update(old_firewall_group,
new_firewall_group):
return
fwg_with_rules = self.firewall_db.make_firewall_group_dict_with_rules(
context, new_firewall_group['id'])
# determine ports to add fw to and del from
fwg_with_rules['add-port-ids'] = list(
set(new_firewall_group['ports']) - set(old_firewall_group['ports'])
)
fwg_with_rules['del-port-ids'] = list(
set(old_firewall_group['ports']) - set(new_firewall_group['ports'])
)
# last-port drives agent to ack with status to set state to INACTIVE
fwg_with_rules['last-port'] = not (
set(new_firewall_group['ports']) - set(old_firewall_group['ports'])
)
LOG.debug("update_firewall_group %s: Add Ports: %s, Del Ports: %s",
new_firewall_group['id'],
fwg_with_rules['add-port-ids'],
fwg_with_rules['del-port-ids'])
fwg_with_rules['port_details'] = self._get_fwg_port_details(
context, fwg_with_rules['del-port-ids'])
fwg_with_rules['port_details'].update(self._get_fwg_port_details(
context, fwg_with_rules['add-port-ids']))
if (new_firewall_group['name'] == constants.DEFAULT_FWG and
len(fwg_with_rules['add-port-ids']) == 1 and
not fwg_with_rules['del-port-ids']):
port_id = fwg_with_rules['add-port-ids'][0]
if (fwg_with_rules['port_details'][port_id].get('status') !=
nl_constants.ACTIVE):
# If port not yet active, just associate to default firewall
# group. When agent will set it to UP, it'll found FG
# association and enforce default policies
return
# Warn agents Firewall Group port list updated
self.agent_rpc.update_firewall_group(context, fwg_with_rules)
def update_firewall_policy_postcommit(self, context, old_firewall_policy,
new_firewall_group):
self._rpc_update_firewall_policy(context, new_firewall_group['id'])
def update_firewall_rule_postcommit(self, context, old_firewall_rule,
new_firewall_rule):
firewall_policy_ids = self.firewall_db.get_policies_with_rule(
context, new_firewall_rule['id'])
for firewall_policy_id in firewall_policy_ids:
self._rpc_update_firewall_policy(context, firewall_policy_id)
def insert_rule_postcommit(self, context, policy_id, rule_info):
self._rpc_update_firewall_policy(context, policy_id)
def remove_rule_postcommit(self, context, policy_id, rule_info):
self._rpc_update_firewall_policy(context, policy_id)

View File

@ -29,7 +29,7 @@ def load_and_init_conntrack_driver(*args, **kwargs):
driver = cfg.CONF.fwaas.conntrack_driver
try:
conntrack_driver_cls = runtime.load_class_by_alias_or_classname(
'neutron_fwaas.services.firewall.drivers.linux', driver)
'neutron.agent.l3.firewall_drivers', driver)
except ImportError:
with excutils.save_and_reraise_exception():
LOG.exception("Driver '%s' not found.", driver)

View File

@ -20,8 +20,10 @@ from neutron_lib.exceptions import firewall_v1 as f_exc
from oslo_log import log as logging
from neutron_fwaas.common import fwaas_constants as f_const
from neutron_fwaas.services.firewall.drivers import conntrack_base
from neutron_fwaas.services.firewall.drivers import fwaas_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\
conntrack_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\
fwaas_base
LOG = logging.getLogger(__name__)

View File

@ -19,8 +19,10 @@ from neutron_lib import constants
from neutron_lib.exceptions import firewall_v2 as fw_ext
from oslo_log import log as logging
from neutron_fwaas.services.firewall.drivers import conntrack_base
from neutron_fwaas.services.firewall.drivers import fwaas_base_v2
from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\
conntrack_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\
fwaas_base_v2
LOG = logging.getLogger(__name__)
FWAAS_DRIVER_NAME = 'Fwaas iptables driver'

View File

@ -14,7 +14,8 @@
from oslo_log import helpers as log_helpers
from neutron_fwaas.services.firewall.drivers.linux.l2 import driver_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2\
import driver_base
class NoopFirewallL2Driver(driver_base.FirewallL2DriverBase):

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import firewall
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import firewall
OVSFirewallDriver = firewall.OVSFirewallDriver

View File

@ -24,13 +24,14 @@ from neutron.common import constants
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \
as ovs_consts
from neutron_fwaas.services.firewall.drivers.linux.l2 import driver_base
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import constants as fwaas_ovs_consts
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import exceptions
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import rules
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2\
import driver_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import constants as fwaas_ovs_consts
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import exceptions
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import rules
LOG = logging.getLogger(__name__)

View File

@ -14,14 +14,15 @@
# under the License.
import netaddr
from neutron_lib import constants as n_consts
from oslo_log import log as logging
from neutron.common import utils
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \
as ovs_consts
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import constants as fwaas_ovs_consts
from neutron_lib import constants as n_consts
from oslo_log import log as logging
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import constants as fwaas_ovs_consts
LOG = logging.getLogger(__name__)

View File

@ -17,8 +17,8 @@ from neutron.agent.linux import utils as linux_utils
from neutron_lib import constants
from oslo_log import log as logging
from neutron_fwaas.services.firewall.drivers import conntrack_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\
conntrack_base
LOG = logging.getLogger(__name__)

View File

@ -17,7 +17,8 @@ from neutron_lib import constants
from oslo_log import log as logging
from neutron_fwaas.privileged import netlink_lib as nl_lib
from neutron_fwaas.services.firewall.drivers import conntrack_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\
conntrack_base
LOG = logging.getLogger(__name__)

View File

@ -28,7 +28,8 @@ from neutron_lib.utils import net as nl_net
from neutron_fwaas._i18n import _
from neutron_fwaas.common import fwaas_constants as consts
from neutron_fwaas.services.firewall.agents import firewall_agent_api as api
from neutron_fwaas.services.firewall.service_drivers.agents import\
firewall_agent_api as api
LOG = logging.getLogger(__name__)

View File

@ -24,8 +24,10 @@ from oslo_log import log as logging
from neutron_fwaas.common import fwaas_constants
from neutron_fwaas.common import resources as f_resources
from neutron_fwaas.services.firewall.agents import firewall_agent_api as api
from neutron_fwaas.services.firewall.agents import firewall_service
from neutron_fwaas.services.firewall.service_drivers.agents \
import firewall_agent_api as api
from neutron_fwaas.services.firewall.service_drivers.agents \
import firewall_service
LOG = logging.getLogger(__name__)

View File

@ -25,8 +25,10 @@ from oslo_log import log as logging
from neutron_fwaas.common import fwaas_constants
from neutron_fwaas.common import resources as f_resources
from neutron_fwaas.services.firewall.agents import firewall_agent_api as api
from neutron_fwaas.services.firewall.agents import firewall_service
from neutron_fwaas.services.firewall.service_drivers.agents import\
firewall_agent_api as api
from neutron_fwaas.services.firewall.service_drivers.agents import\
firewall_service
LOG = logging.getLogger(__name__)

View File

@ -0,0 +1,435 @@
# Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
# 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 abc
import copy
import six
from neutron_lib import constants as nl_constants
from neutron_lib.plugins import directory
from oslo_log import log as logging
from neutron_fwaas.db.firewall.v2 import firewall_db_v2
LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class FirewallDriver(object):
"""Firewall v2 interface for driver
That driver interface does not persist Firewall v2 data in any database.
The driver needs to do it by itself.
"""
def __init__(self, service_plugin):
self.service_plugin = service_plugin
@property
def _core_plugin(self):
return directory.get_plugin()
# Firewall Group
@abc.abstractmethod
def create_firewall_group(self, context, firewall_group):
pass
@abc.abstractmethod
def delete_firewall_group(self, context, id):
pass
@abc.abstractmethod
def get_firewall_group(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_firewall_groups(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def update_firewall_group(self, context, id, firewall_group):
pass
# Firewall Policy
@abc.abstractmethod
def create_firewall_policy(self, context, firewall_policy):
pass
@abc.abstractmethod
def delete_firewall_policy(self, context, id):
pass
@abc.abstractmethod
def get_firewall_policy(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_firewall_policies(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def update_firewall_policy(self, context, id, firewall_policy):
pass
# Firewall Rule
@abc.abstractmethod
def create_firewall_rule(self, context, firewall_rule):
pass
@abc.abstractmethod
def delete_firewall_rule(self, context, id):
pass
@abc.abstractmethod
def get_firewall_rule(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_firewall_rules(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def update_firewall_rule(self, context, id, firewall_rule):
pass
@abc.abstractmethod
def insert_rule(self, context, policy_id, rule_info):
pass
@abc.abstractmethod
def remove_rule(self, context, policy_id, rule_info):
pass
@six.add_metaclass(abc.ABCMeta)
class FirewallDriverDBMixin(FirewallDriver):
"""FirewallDriverDB mixin to provision the database on behalf of the driver
That driver interface persists Firewall data in its database and forwards
the result to pre and post commit methods.
"""
def __init__(self, *args, **kwargs):
super(FirewallDriverDBMixin, self).__init__(*args, **kwargs)
self.firewall_db = firewall_db_v2.FirewallPluginDb()
@staticmethod
def _update_resource_status(context, resource_type, resource_dict):
with context.session.begin(subtransactions=True):
context.session.query(resource_type).\
filter_by(id=resource_dict['id']).\
update({'status': resource_dict['status']})
# Firewall Group
def create_firewall_group(self, context, firewall_group):
with context.session.begin(subtransactions=True):
firewall_group = self.firewall_db.create_firewall_group(
context, firewall_group)
self.create_firewall_group_precommit(context, firewall_group)
self._update_resource_status(context, firewall_db_v2.FirewallGroup,
firewall_group)
self.create_firewall_group_postcommit(context, firewall_group)
return firewall_group
@abc.abstractmethod
def create_firewall_group_precommit(self, context, firewall_group):
pass
@abc.abstractmethod
def create_firewall_group_postcommit(self, context, firewall_group):
pass
def delete_firewall_group(self, context, id):
firewall_group = self.firewall_db.get_firewall_group(context, id)
if firewall_group['status'] == nl_constants.PENDING_DELETE:
firewall_group['status'] = nl_constants.ERROR
self.delete_firewall_group_precommit(context, firewall_group)
if firewall_group['status'] != nl_constants.PENDING_DELETE:
# lets driver deleting firewall group later
self.firewall_db.delete_firewall_group(context, id)
self.delete_firewall_group_postcommit(context, firewall_group)
@abc.abstractmethod
def delete_firewall_group_precommit(self, context, firewall_group):
pass
@abc.abstractmethod
def delete_firewall_group_postcommit(self, context, firewall_group):
pass
def get_firewall_group(self, context, id, fields=None):
return self.firewall_db.get_firewall_group(context, id, fields=fields)
def get_firewall_groups(self, context, filters=None, fields=None):
return self.firewall_db.get_firewall_groups(context, filters, fields)
def update_firewall_group(self, context, id, firewall_group_delta):
old_firewall_group = self.firewall_db.get_firewall_group(context, id)
new_firewall_group = copy.deepcopy(old_firewall_group)
new_firewall_group.update(firewall_group_delta)
self.update_firewall_group_precommit(context, old_firewall_group,
new_firewall_group)
firewall_group_delta['status'] = new_firewall_group['status']
firewall_group = self.firewall_db.update_firewall_group(
context, id, firewall_group_delta)
self.update_firewall_group_postcommit(context, old_firewall_group,
firewall_group)
return firewall_group
@abc.abstractmethod
def update_firewall_group_precommit(self, context, old_firewall_group,
new_firewall_group):
pass
@abc.abstractmethod
def update_firewall_group_postcommit(self, context, old_firewall_group,
new_firewall_group):
pass
# Firewall Policy
def create_firewall_policy(self, context, firewall_policy):
with context.session.begin(subtransactions=True):
firewall_policy = self.firewall_db.create_firewall_policy(
context, firewall_policy)
self.create_firewall_policy_precommit(context, firewall_policy)
self.create_firewall_policy_postcommit(context, firewall_policy)
return firewall_policy
@abc.abstractmethod
def create_firewall_policy_precommit(self, context, firewall_policy):
pass
@abc.abstractmethod
def create_firewall_policy_postcommit(self, context, firewall_policy):
pass
def delete_firewall_policy(self, context, id):
firewall_policy = self.firewall_db.get_firewall_policy(context, id)
self.delete_firewall_policy_precommit(context, firewall_policy)
self.firewall_db.delete_firewall_policy(context, id)
self.delete_firewall_policy_postcommit(context, firewall_policy)
@abc.abstractmethod
def delete_firewall_policy_precommit(self, context, firewall_policy):
pass
@abc.abstractmethod
def delete_firewall_policy_postcommit(self, context, firewall_policy):
pass
def get_firewall_policy(self, context, id, fields=None):
return self.firewall_db.get_firewall_policy(context, id, fields)
def get_firewall_policies(self, context, filters=None, fields=None):
return self.firewall_db.get_firewall_policies(context, filters, fields)
def update_firewall_policy(self, context, id, firewall_policy_delta):
old_firewall_policy = self.firewall_db.get_firewall_policy(context, id)
new_firewall_policy = copy.deepcopy(old_firewall_policy)
new_firewall_policy.update(firewall_policy_delta)
self.update_firewall_policy_precommit(context, old_firewall_policy,
new_firewall_policy)
firewall_policy = self.firewall_db.update_firewall_policy(
context, id, firewall_policy_delta)
self.update_firewall_policy_postcommit(context, old_firewall_policy,
firewall_policy)
return firewall_policy
@abc.abstractmethod
def update_firewall_policy_precommit(self, context, old_firewall_policy,
new_firewall_policy):
pass
@abc.abstractmethod
def update_firewall_policy_postcommit(self, context, old_firewall_policy,
new_firewall_policy):
pass
# Firewall Rule
def create_firewall_rule(self, context, firewall_rule):
with context.session.begin(subtransactions=True):
firewall_rule = self.firewall_db.create_firewall_rule(
context, firewall_rule)
self.create_firewall_rule_precommit(context, firewall_rule)
self.create_firewall_rule_postcommit(context, firewall_rule)
return firewall_rule
@abc.abstractmethod
def create_firewall_rule_precommit(self, context, firewall_rule):
pass
@abc.abstractmethod
def create_firewall_rule_postcommit(self, context, firewall_rule):
pass
def delete_firewall_rule(self, context, id):
firewall_rule = self.firewall_db.get_firewall_rule(context, id)
self.delete_firewall_rule_precommit(context, firewall_rule)
self.firewall_db.delete_firewall_rule(context, id)
self.delete_firewall_rule_postcommit(context, firewall_rule)
@abc.abstractmethod
def delete_firewall_rule_precommit(self, context, firewall_rule):
pass
@abc.abstractmethod
def delete_firewall_rule_postcommit(self, context, firewall_rule):
pass
def get_firewall_rule(self, context, id, fields=None):
return self.firewall_db.get_firewall_rule(context, id, fields)
def get_firewall_rules(self, context, filters=None, fields=None):
return self.firewall_db.get_firewall_rules(context, filters, fields)
def update_firewall_rule(self, context, id, firewall_rule_delta):
old_firewall_rule = self.firewall_db.get_firewall_rule(context, id)
new_firewall_rule = copy.deepcopy(old_firewall_rule)
new_firewall_rule.update(firewall_rule_delta)
self.update_firewall_rule_precommit(context, old_firewall_rule,
new_firewall_rule)
firewall_rule = self.firewall_db.update_firewall_rule(
context, id, firewall_rule_delta)
self.update_firewall_rule_postcommit(context, old_firewall_rule,
firewall_rule)
return firewall_rule
@abc.abstractmethod
def update_firewall_rule_precommit(self, context, old_firewall_rule,
new_firewall_rule):
pass
@abc.abstractmethod
def update_firewall_rule_postcommit(self, context, old_firewall_rule,
new_firewall_rule):
pass
def insert_rule(self, context, policy_id, rule_info):
self.insert_rule_precommit(context, policy_id, rule_info)
firewall_policy = self.firewall_db.insert_rule(context, policy_id,
rule_info)
self.insert_rule_postcommit(context, policy_id, rule_info)
return firewall_policy
@abc.abstractmethod
def insert_rule_precommit(self, context, policy_id, rule_info):
pass
@abc.abstractmethod
def insert_rule_postcommit(self, context, policy_id, rule_info):
pass
def remove_rule(self, context, policy_id, rule_info):
self.remove_rule_precommit(context, policy_id, rule_info)
firewall_policy = self.firewall_db.remove_rule(context, policy_id,
rule_info)
self.remove_rule_postcommit(context, policy_id, rule_info)
return firewall_policy
@abc.abstractmethod
def remove_rule_precommit(self, context, policy_id, rule_info):
pass
@abc.abstractmethod
def remove_rule_postcommit(self, context, policy_id, rule_info):
pass
class FirewallDriverDB(FirewallDriverDBMixin):
"""FirewallDriverDBMixin interface for driver with database.
Each firewall backend driver that needs a database persistency should
inherit from this driver.
It can overload needed methods from the following pre/postcommit methods.
Any exception raised during a precommit method will result in not having
related records in the databases.
"""
#Firewal Group
def create_firewall_group_precommit(self, context, firewall_group):
pass
def create_firewall_group_postcommit(self, context, firewall_group):
pass
def update_firewall_group_precommit(self, context, old_firewall_group,
new_firewall_group):
pass
def update_firewall_group_postcommit(self, context, old_firewall_group,
new_firewall_group):
pass
def delete_firewall_group_precommit(self, context, firewall_group):
pass
def delete_firewall_group_postcommit(self, context, firewall_group):
pass
#Firewall Policy
def create_firewall_policy_precommit(self, context, firewall_policy):
pass
def create_firewall_policy_postcommit(self, context, firewall_policy):
pass
def update_firewall_policy_precommit(self, context, old_firewall_policy,
new_firewall_policy):
pass
def update_firewall_policy_postcommit(self, context, old_firewall_policy,
new_firewall_policy):
pass
def delete_firewall_policy_precommit(self, context, firewall_policy):
pass
def delete_firewall_policy_postcommit(self, context, firewall_policy):
pass
#Firewall Rule
def create_firewall_rule_precommit(self, context, firewall_rule):
pass
def create_firewall_rule_postcommit(self, context, firewall_rule):
pass
def update_firewall_rule_precommit(self, context, old_firewall_rule,
new_firewall_rule):
pass
def update_firewall_rule_postcommit(self, context, old_firewall_rule,
new_firewall_rule):
pass
def delete_firewall_rule_precommit(self, context, firewall_rule):
pass
def delete_firewall_rule_postcommit(self, context, firewall_rule):
pass
def insert_rule_precommit(self, context, policy_id, rule_info):
pass
def insert_rule_postcommit(self, context, policy_id, rule_info):
pass
def remove_rule_precommit(self, context, policy_id, rule_info):
pass
def remove_rule_postcommit(self, context, policy_id, rule_info):
pass

View File

@ -13,387 +13,26 @@
# License for the specific language governing permissions and limitations
# under the License.
import contextlib
import mock
from neutron.api import extensions as api_ext
from neutron.common import config
from neutron_lib.api.definitions import firewall_v2
from neutron_lib import constants as nl_constants
from neutron_lib import context
from neutron_lib.exceptions import firewall_v2 as f_exc
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_utils import importutils
from oslo_utils import uuidutils
import six
import testtools
import webob.exc
from neutron_lib import constants as nl_constants
from neutron_lib.exceptions import firewall_v2 as f_exc
from oslo_utils import uuidutils
from neutron_fwaas.common import fwaas_constants as constants
from neutron_fwaas.db.firewall.v2 import firewall_db_v2 as fdb
from neutron_fwaas import extensions
from neutron_fwaas.services.firewall import fwaas_plugin_v2
from neutron_fwaas.tests import base
from neutron_fwaas.tests.unit.services.firewall import test_fwaas_plugin_v2
DB_FW_PLUGIN_KLASS = (
"neutron_fwaas.db.firewall.v2.firewall_db_v2.Firewall_db_mixin_v2"
)
FWAAS_PLUGIN = 'neutron_fwaas.services.firewall.fwaas_plugin_v2'
DELETEFW_PATH = FWAAS_PLUGIN + '.FirewallAgentApi.delete_firewall_group'
extensions_path = ':'.join(extensions.__path__)
DESCRIPTION = 'default description'
PROTOCOL = 'tcp'
IP_VERSION = 4
SOURCE_IP_ADDRESS_RAW = '1.1.1.1'
DESTINATION_IP_ADDRESS_RAW = '2.2.2.2'
SOURCE_PORT = '55000:56000'
DESTINATION_PORT = '56000:57000'
ACTION = 'allow'
AUDITED = True
ENABLED = True
ADMIN_STATE_UP = True
SHARED = True
class TestFirewallDBPluginV2(test_fwaas_plugin_v2.FirewallPluginV2TestCase):
class FakeAgentApi(fwaas_plugin_v2.FirewallCallbacks):
"""
This class used to mock the AgentAPI delete method inherits from
FirewallCallbacks because it needs access to the firewall_deleted method.
The delete_firewall method belongs to the FirewallAgentApi, which has
no access to the firewall_deleted method normally because it's not
responsible for deleting the firewall from the DB. However, it needs
to in the unit tests since there is no agent to call back.
"""
def __init__(self):
pass
def delete_firewall_group(self, context, firewall_group, **kwargs):
self.plugin = directory.get_plugin('FIREWALL_V2')
self.firewall_group_deleted(context, firewall_group['id'], **kwargs)
class FirewallPluginV2DbTestCase(base.NeutronDbPluginV2TestCase):
resource_prefix_map = dict(
(k, firewall_v2.API_PREFIX)
for k in firewall_v2.RESOURCE_ATTRIBUTE_MAP.keys()
)
def setUp(self, core_plugin=None, fw_plugin=None, ext_mgr=None):
self.agentapi_delf_p = mock.patch(
DELETEFW_PATH, create=True,
new=FakeAgentApi().delete_firewall_group)
self.agentapi_delf_p.start()
if not fw_plugin:
fw_plugin = DB_FW_PLUGIN_KLASS
service_plugins = {'fw_plugin_name': fw_plugin}
fdb.Firewall_db_mixin_v2.supported_extension_aliases = ["fwaas_v2"]
fdb.Firewall_db_mixin_v2.path_prefix = firewall_v2.API_PREFIX
super(FirewallPluginV2DbTestCase, self).setUp(
ext_mgr=ext_mgr,
service_plugins=service_plugins
)
if not ext_mgr:
self.plugin = importutils.import_object(fw_plugin)
ext_mgr = api_ext.PluginAwareExtensionManager(
extensions_path,
{'FIREWALL': self.plugin}
)
app = config.load_paste_app('extensions_test_app')
self.ext_api = api_ext.ExtensionMiddleware(app, ext_mgr=ext_mgr)
router_distributed_opts = [
cfg.BoolOpt(
'router_distributed',
default=False,
help=("System-wide flag to determine the type of router "
"that tenants can create. Only admin can override.")),
]
cfg.CONF.register_opts(router_distributed_opts)
def _get_admin_context(self):
# FIXME NOTE(ivasilevskaya) seems that test framework treats context
# with user_id=None/tenant_id=None (return value of
# context._get_admin_context() method) in a somewhat special way.
# So as a workaround to have the framework behave properly right now
# let's implement our own _get_admin_context method and look into the
# matter some other time.
return context.Context(user_id='admin',
tenant_id='admin-tenant',
is_admin=True)
def _get_nonadmin_context(self, user_id=None, tenant_id=None):
return context.Context(user_id=user_id or 'non-admin',
tenant_id=tenant_id or 'tenant1')
def _test_list_resources(self, resource, items,
neutron_context=None,
query_params=None):
if resource.endswith('y'):
resource_plural = resource.replace('y', 'ies')
else:
resource_plural = resource + 's'
res = self._list(resource_plural,
neutron_context=neutron_context,
query_params=query_params)
resource = resource.replace('-', '_')
self.assertEqual(
sorted([i[resource]['id'] for i in items]),
sorted([i['id'] for i in res[resource_plural]]))
def _list_req(self, resource_plural, ctx=None):
if not ctx:
ctx = self._get_admin_context()
req = self.new_list_request(resource_plural)
req.environ['neutron.context'] = ctx
return self.deserialize(
self.fmt, req.get_response(self.ext_api))[resource_plural]
def _show_req(self, resource_plural, obj_id, ctx=None):
req = self.new_show_request(resource_plural, obj_id, fmt=self.fmt)
if not ctx:
ctx = self._get_admin_context()
req.environ['neutron.context'] = ctx
res = self.deserialize(
self.fmt, req.get_response(self.ext_api))
return res
def _build_default_fwg(self, ctx=None, is_one=True):
res = self._list_req('firewall_groups', ctx=ctx)
if is_one:
self.assertEqual(1, len(res))
return res[0]
return res
def _get_test_firewall_rule_attrs(self, name='firewall_rule1'):
attrs = {'name': name,
'tenant_id': self._tenant_id,
'project_id': self._tenant_id,
'protocol': PROTOCOL,
'ip_version': IP_VERSION,
'source_ip_address': SOURCE_IP_ADDRESS_RAW,
'destination_ip_address': DESTINATION_IP_ADDRESS_RAW,
'source_port': SOURCE_PORT,
'destination_port': DESTINATION_PORT,
'action': ACTION,
'enabled': ENABLED,
'shared': SHARED}
return attrs
def _get_test_firewall_policy_attrs(self, name='firewall_policy1',
audited=AUDITED):
attrs = {'name': name,
'description': DESCRIPTION,
'tenant_id': self._tenant_id,
'project_id': self._tenant_id,
'firewall_rules': [],
'audited': audited,
'shared': SHARED}
return attrs
def _get_test_firewall_group_attrs(self, name='firewall_1',
status='PENDING_CREATE'):
attrs = {'name': name,
'tenant_id': self._tenant_id,
'project_id': self._tenant_id,
'admin_state_up': ADMIN_STATE_UP,
'status': status}
return attrs
def _create_firewall_policy(self, fmt, name, description, shared,
firewall_rules, audited,
expected_res_status=None, **kwargs):
tenant_id = kwargs.get('tenant_id', self._tenant_id)
data = {'firewall_policy': {'name': name,
'description': description,
'tenant_id': tenant_id,
'project_id': tenant_id,
'firewall_rules': firewall_rules,
'audited': audited,
'shared': shared}}
fw_policy_req = self.new_create_request('firewall_policies', data, fmt)
fw_policy_res = fw_policy_req.get_response(self.ext_api)
if expected_res_status:
self.assertEqual(expected_res_status, fw_policy_res.status_int)
return fw_policy_res
def _replace_firewall_status(self, attrs, old_status, new_status):
if attrs['status'] is old_status:
attrs['status'] = new_status
return attrs
@contextlib.contextmanager
def firewall_policy(self, fmt=None, name='firewall_policy1',
description=DESCRIPTION, shared=SHARED,
firewall_rules=None, audited=True,
do_delete=True, **kwargs):
if firewall_rules is None:
firewall_rules = []
if not fmt:
fmt = self.fmt
res = self._create_firewall_policy(fmt, name, description, shared,
firewall_rules, audited, **kwargs)
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
firewall_policy = self.deserialize(fmt or self.fmt, res)
yield firewall_policy
if do_delete:
self._delete('firewall_policies',
firewall_policy['firewall_policy']['id'])
def _create_firewall_rule(self, fmt, name, shared, protocol,
ip_version, source_ip_address,
destination_ip_address, source_port,
destination_port, action, enabled,
expected_res_status=None, **kwargs):
tenant_id = kwargs.get('tenant_id', self._tenant_id)
data = {'firewall_rule': {'name': name,
'tenant_id': tenant_id,
'project_id': tenant_id,
'protocol': protocol,
'ip_version': ip_version,
'source_ip_address': source_ip_address,
'destination_ip_address':
destination_ip_address,
'source_port': source_port,
'destination_port': destination_port,
'action': action,
'enabled': enabled,
'shared': shared}}
fw_rule_req = self.new_create_request('firewall_rules', data, fmt)
fw_rule_res = fw_rule_req.get_response(self.ext_api)
if expected_res_status:
self.assertEqual(expected_res_status, fw_rule_res.status_int)
return fw_rule_res
@contextlib.contextmanager
def firewall_rule(self, fmt=None, name='firewall_rule1',
shared=SHARED, protocol=PROTOCOL, ip_version=IP_VERSION,
source_ip_address=SOURCE_IP_ADDRESS_RAW,
destination_ip_address=DESTINATION_IP_ADDRESS_RAW,
source_port=SOURCE_PORT,
destination_port=DESTINATION_PORT,
action=ACTION, enabled=ENABLED,
do_delete=True, **kwargs):
if not fmt:
fmt = self.fmt
res = self._create_firewall_rule(fmt, name, shared, protocol,
ip_version, source_ip_address,
destination_ip_address,
source_port, destination_port,
action, enabled, **kwargs)
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
firewall_rule = self.deserialize(fmt or self.fmt, res)
yield firewall_rule
if do_delete:
self._delete('firewall_rules',
firewall_rule['firewall_rule']['id'])
def _create_firewall_group(self, fmt, name, description,
ingress_firewall_policy_id,
egress_firewall_policy_id,
ports=None, admin_state_up=True,
expected_res_status=None, **kwargs):
tenant_id = kwargs.get('tenant_id', self._tenant_id)
if ingress_firewall_policy_id is None:
default_policy = kwargs.get('default_policy', True)
if default_policy:
res = self._create_firewall_policy(fmt, 'fwp',
description=DESCRIPTION,
shared=SHARED,
firewall_rules=[],
audited=AUDITED)
firewall_policy = self.deserialize(fmt or self.fmt, res)
fwp_id = firewall_policy["firewall_policy"]["id"]
ingress_firewall_policy_id = fwp_id
data = {'firewall_group': {'name': name,
'description': description,
'ingress_firewall_policy_id': ingress_firewall_policy_id,
'egress_firewall_policy_id': egress_firewall_policy_id,
'admin_state_up': admin_state_up}}
ctx = kwargs.get('context', None)
if ctx is None or ctx.is_admin:
data['firewall_group'].update({'tenant_id': tenant_id})
data['firewall_group'].update({'project_id': tenant_id})
if ports is not None:
data['firewall_group'].update({'ports': ports})
firewall_req = self.new_create_request('firewall_groups', data, fmt,
context=ctx)
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
@contextlib.contextmanager
def firewall_group(self, fmt=None, name='firewall_1',
description=DESCRIPTION,
ingress_firewall_policy_id=None,
egress_firewall_policy_id=None,
ports=None, admin_state_up=True,
do_delete=True, **kwargs):
if not fmt:
fmt = self.fmt
res = self._create_firewall_group(fmt, name, description,
ingress_firewall_policy_id,
egress_firewall_policy_id,
ports=ports,
admin_state_up=admin_state_up,
**kwargs)
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
firewall_group = self.deserialize(fmt or self.fmt, res)
yield firewall_group
if do_delete:
self._delete('firewall_groups',
firewall_group['firewall_group']['id'])
def _rule_action(self, action, id, firewall_rule_id, insert_before=None,
insert_after=None, expected_code=webob.exc.HTTPOk.code,
expected_body=None, body_data=None):
# We intentionally do this check for None since we want to distinguish
# from empty dictionary
if body_data is None:
if action == 'insert':
body_data = {'firewall_rule_id': firewall_rule_id,
'insert_before': insert_before,
'insert_after': insert_after}
else:
body_data = {'firewall_rule_id': firewall_rule_id}
req = self.new_action_request('firewall_policies',
body_data, id,
"%s_rule" % action)
res = req.get_response(self.ext_api)
self.assertEqual(expected_code, res.status_int)
response = self.deserialize(self.fmt, res)
if expected_body:
self.assertEqual(expected_body, response)
return response
def _compare_firewall_rule_lists(self, firewall_policy_id,
observed_list, expected_list):
position = 0
for r1, r2 in zip(observed_list, expected_list):
rule = r1['firewall_rule']
rule['firewall_policy_id'] = firewall_policy_id
position += 1
rule['position'] = position
for k in rule:
self.assertEqual(r2[k], rule[k])
class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def setUp(self):
provider = ('neutron_fwaas.services.firewall.service_drivers.'
'driver_api.FirewallDriverDB')
super(TestFirewallDBPluginV2, self).setUp(service_provider=provider)
self.db = self.plugin.driver.firewall_db
def test_get_policy_ordered_rules(self):
with self.firewall_rule(name='alone'), \
@ -405,7 +44,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
with self.firewall_policy(firewall_rules=expected_ids) as fwp:
ctx = self._get_admin_context()
fwp_id = fwp['firewall_policy']['id']
observeds = self.plugin._get_policy_ordered_rules(ctx, fwp_id)
observeds = self.db._get_policy_ordered_rules(ctx, fwp_id)
observed_ids = [r['id'] for r in observeds]
self.assertEqual(expected_ids, observed_ids)
@ -413,8 +52,8 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
name = "firewall_policy1"
attrs = self._get_test_firewall_policy_attrs(name)
with self.firewall_policy(name=name, shared=SHARED,
firewall_rules=None, audited=AUDITED
with self.firewall_policy(name=name, shared=self.SHARED,
firewall_rules=None, audited=self.AUDITED
) as firewall_policy:
for k, v in six.iteritems(attrs):
self.assertEqual(v, firewall_policy['firewall_policy'][k])
@ -429,49 +68,29 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
fr = [fwr1, fwr2, fwr3]
fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
attrs['firewall_rules'] = fw_rule_ids
with self.firewall_policy(name=name, shared=SHARED,
with self.firewall_policy(name=name, shared=self.SHARED,
firewall_rules=fw_rule_ids,
audited=AUDITED) as fwp:
audited=self.AUDITED) as fwp:
for k, v in six.iteritems(attrs):
self.assertEqual(v, fwp['firewall_policy'][k])
def test_create_admin_firewall_policy_with_other_tenant_rules(self):
with self.firewall_rule(shared=False) as fr:
fw_rule_ids = [fr['firewall_rule']['id']]
res = self._create_firewall_policy(None, 'firewall_policy1',
description=DESCRIPTION,
shared=SHARED,
firewall_rules=fw_rule_ids,
audited=AUDITED,
tenant_id='admin-tenant')
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
def test_create_firewall_policy_with_previously_associated_rule(self):
with self.firewall_rule() as fwr:
fw_rule_ids = [fwr['firewall_rule']['id']]
with self.firewall_policy(firewall_rules=fw_rule_ids):
with self.firewall_policy(shared=SHARED,
with self.firewall_policy(shared=self.SHARED,
firewall_rules=fw_rule_ids) as fwp2:
self.assertEqual(
fwr['firewall_rule']['id'],
fwp2['firewall_policy']['firewall_rules'][0])
def test_create_shared_firewall_policy_with_nonshared_rule(self):
with self.firewall_rule(shared=False) as fwr:
fw_rule_ids = [fwr['firewall_rule']['id']]
res = self._create_firewall_policy(None, 'firewall_policy1',
description=DESCRIPTION,
shared=SHARED,
firewall_rules=fw_rule_ids,
audited=AUDITED)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
def test_show_firewall_policy(self):
name = "firewall_policy1"
attrs = self._get_test_firewall_policy_attrs(name)
with self.firewall_policy(name=name, shared=SHARED,
firewall_rules=None, audited=AUDITED) as fwp:
with self.firewall_policy(name=name, shared=self.SHARED,
firewall_rules=None,
audited=self.AUDITED) as fwp:
res = self._show_req('firewall_policies',
fwp['firewall_policy']['id'])
for k, v in six.iteritems(attrs):
@ -490,8 +109,8 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
name = "new_firewall_policy1"
attrs = self._get_test_firewall_policy_attrs(name, audited=False)
with self.firewall_policy(shared=SHARED, firewall_rules=None,
audited=AUDITED) as fwp:
with self.firewall_policy(shared=self.SHARED, firewall_rules=None,
audited=self.AUDITED) as fwp:
data = {'firewall_policy': {'name': name}}
req = self.new_update_request('firewall_policies', data,
fwp['firewall_policy']['id'])
@ -501,7 +120,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def _test_update_firewall_policy(self, with_audited):
with self.firewall_policy(name='firewall_policy1', description='fwp',
audited=AUDITED) as fwp:
audited=self.AUDITED) as fwp:
attrs = self._get_test_firewall_policy_attrs(audited=with_audited)
data = {'firewall_policy':
{'description': 'fw_p1'}}
@ -658,7 +277,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
with self.firewall_policy(shared=False) as fwp:
fw_rule_ids = [fr['firewall_rule']['id']]
# update shared policy with shared attr and nonshared rule
data = {'firewall_policy': {'shared': SHARED,
data = {'firewall_policy': {'shared': self.SHARED,
'firewall_rules': fw_rule_ids}}
req = self.new_update_request('firewall_policies', data,
fwp['firewall_policy']['id'])
@ -671,14 +290,15 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
with self.firewall_policy(shared=False,
firewall_rules=fw_rule_ids) as fwp:
# update policy with shared attr
data = {'firewall_policy': {'shared': SHARED}}
data = {'firewall_policy': {'shared': self.SHARED}}
req = self.new_update_request('firewall_policies', data,
fwp['firewall_policy']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPConflict.code, res.status_int)
def test_update_firewall_policy_assoc_with_other_tenant_firewall(self):
with self.firewall_policy(shared=SHARED, tenant_id='tenant1') as fwp:
with self.firewall_policy(shared=self.SHARED,
tenant_id='tenant1') as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id):
@ -790,13 +410,11 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
self.assertIsNone(fw_rule['ingress_firewall_policy_id'])
def test_delete_firewall_policy_with_firewall_group_association(self):
attrs = self._get_test_firewall_group_attrs()
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
attrs['firewall_policy_id'] = fwp_id
with self.firewall_group(
ingress_firewall_policy_id=fwp_id,
admin_state_up=ADMIN_STATE_UP):
admin_state_up=self.ADMIN_STATE_UP):
req = self.new_delete_request('firewall_policies', fwp_id)
res = req.get_response(self.ext_api)
self.assertEqual(409, res.status_int)
@ -832,20 +450,20 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def test_create_firewall_src_port_illegal_range(self):
attrs = self._get_test_firewall_rule_attrs()
attrs['source_port'] = '65535:1024'
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
def test_create_firewall_dest_port_illegal_range(self):
attrs = self._get_test_firewall_rule_attrs()
attrs['destination_port'] = '65535:1024'
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
def test_create_firewall_rule_icmp_with_port(self):
attrs = self._get_test_firewall_rule_attrs()
attrs['protocol'] = 'icmp'
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
def test_create_firewall_rule_icmp_without_port(self):
attrs = self._get_test_firewall_rule_attrs()
@ -862,28 +480,28 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def test_create_firewall_without_source(self):
attrs = self._get_test_firewall_rule_attrs()
attrs['source_ip_address'] = None
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(201, res.status_int)
attrs['expected_res_status'] = 201
self._create_firewall_rule(self.fmt, **attrs)
def test_create_firewall_rule_without_destination(self):
attrs = self._get_test_firewall_rule_attrs()
attrs['destination_ip_address'] = None
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(201, res.status_int)
attrs['expected_res_status'] = 201
self._create_firewall_rule(self.fmt, **attrs)
def test_create_firewall_rule_without_protocol_with_dport(self):
attrs = self._get_test_firewall_rule_attrs()
attrs['protocol'] = None
attrs['source_port'] = None
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
def test_create_firewall_rule_without_protocol_with_sport(self):
attrs = self._get_test_firewall_rule_attrs()
attrs['protocol'] = None
attrs['destination_port'] = None
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
def test_show_firewall_rule_with_fw_policy_not_associated(self):
attrs = self._get_test_firewall_rule_attrs()
@ -916,22 +534,22 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
attrs['source_ip_address'] = '::/0'
attrs['destination_ip_address'] = '2001:db8:3::/64'
attrs['ip_version'] = 4
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
attrs = self._get_test_firewall_rule_attrs()
attrs['source_ip_address'] = None
attrs['destination_ip_address'] = '2001:db8:3::/64'
attrs['ip_version'] = 4
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
attrs = self._get_test_firewall_rule_attrs()
attrs['source_ip_address'] = '::/0'
attrs['destination_ip_address'] = None
attrs['ip_version'] = 4
res = self._create_firewall_rule(self.fmt, **attrs)
self.assertEqual(400, res.status_int)
attrs['expected_res_status'] = 400
self._create_firewall_rule(self.fmt, **attrs)
def test_list_firewall_rules(self):
with self.firewall_rule(name='fwr1') as fwr1, \
@ -950,7 +568,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
attrs['destination_port'] = '30:40'
with self.firewall_rule() as fwr:
data = {'firewall_rule': {'name': name,
'protocol': PROTOCOL,
'protocol': self.PROTOCOL,
'source_port': '10:20',
'destination_port': '30:40'}}
req = self.new_update_request('firewall_rules', data,
@ -964,7 +582,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
attrs['destination_port'] = '80'
with self.firewall_rule() as fwr:
data = {'firewall_rule': {'name': name,
'protocol': PROTOCOL,
'protocol': self.PROTOCOL,
'source_port': 10000,
'destination_port': 80}}
req = self.new_update_request('firewall_rules', data,
@ -978,7 +596,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
attrs['destination_port'] = '80'
with self.firewall_rule() as fwr:
data = {'firewall_rule': {'name': name,
'protocol': PROTOCOL,
'protocol': self.PROTOCOL,
'source_port': '10000',
'destination_port': '80'}}
req = self.new_update_request('firewall_rules', data,
@ -1095,7 +713,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
@testtools.skip('bug/1614680')
def test_update_firewall_rule_associated_with_other_tenant_policy(self):
with self.firewall_rule(shared=SHARED, tenant_id='tenant1') as fwr:
with self.firewall_rule(shared=self, tenant_id='tenant1') as fwr:
fwr_id = [fwr['firewall_rule']['id']]
with self.firewall_policy(shared=False, firewall_rules=fwr_id):
data = {'firewall_rule': {'shared': False}}
@ -1138,21 +756,6 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
res = req.get_response(self.ext_api)
self.assertEqual(409, res.status_int)
def _test_create_firewall_group(self, attrs):
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
attrs['ingress_firewall_policy_id'] = fwp_id
attrs['egress_firewall_policy_id'] = fwp_id
with self.firewall_group(
name=attrs['name'],
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id,
admin_state_up=ADMIN_STATE_UP,
ports=attrs['ports'] if 'ports' in attrs else None,
) as firewall_group:
for k, v in six.iteritems(attrs):
self.assertEqual(v, firewall_group['firewall_group'][k])
def test_create_firewall_group(self):
attrs = self._get_test_firewall_group_attrs("firewall1")
self._test_create_firewall_group(attrs)
@ -1247,11 +850,6 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
attrs = self._get_test_firewall_group_attrs("firewall1")
self._test_create_firewall_group(attrs)
def test_create_firewall_group_with_dvr(self):
cfg.CONF.set_override('router_distributed', True)
attrs = self._get_test_firewall_group_attrs("firewall1", "CREATED")
self._test_create_firewall_group(attrs)
def test_create_firewall_group_with_fwp_does_not_exist(self):
fmt = self.fmt
fwg_name = "firewall1"
@ -1260,7 +858,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
self._create_firewall_group(fmt, fwg_name,
description, not_found_fwp_id,
not_found_fwp_id, ports=None,
admin_state_up=ADMIN_STATE_UP,
admin_state_up=self.ADMIN_STATE_UP,
expected_res_status=404)
def test_create_firewall_group_with_fwp_on_different_tenant(self):
@ -1296,10 +894,12 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
fwp_id = fwp['firewall_policy']['id']
ctx = self._get_admin_context()
target_tenant = 'tenant1'
with self.firewall_group(name=fwg_name,
ingress_firewall_policy_id=fwp_id,
tenant_id=target_tenant, context=ctx,
admin_state_up=ADMIN_STATE_UP) as fwg:
with self.firewall_group(
name=fwg_name,
ingress_firewall_policy_id=fwp_id,
tenant_id=target_tenant,
context=ctx,
admin_state_up=self.ADMIN_STATE_UP) as fwg:
self.assertEqual(target_tenant,
fwg['firewall_group']['tenant_id'])
@ -1308,13 +908,12 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
fwp_id = fwp['firewall_policy']['id']
attrs['ingress_firewall_policy_id'] = fwp_id
attrs['egress_firewall_policy_id'] = fwp_id
attrs['status'] = 'PENDING_CREATE'
with self.firewall_group(
name=attrs['name'],
ports=attrs['ports'] if 'ports' in attrs else None,
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id,
admin_state_up=ADMIN_STATE_UP) as firewall_group:
admin_state_up=self.ADMIN_STATE_UP) as firewall_group:
res = self._show_req('firewall_groups',
firewall_group['firewall_group']['id'])
for k, v in six.iteritems(attrs):
@ -1362,7 +961,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
ingress_firewall_policy_id=fwp_id,
admin_state_up=ADMIN_STATE_UP) as firewall:
admin_state_up=self.ADMIN_STATE_UP) as firewall:
data = {'firewall_group': {'name': name}}
req = self.new_update_request('firewall_groups', data,
firewall['firewall_group']['id'])
@ -1385,7 +984,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def_fwg_id = self._build_default_fwg(ctx=ctx)['id']
with self.port(
device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF,
ctx=ctx) as dummy_port:
tenant_id=ctx.project_id) as dummy_port:
port_id = dummy_port['port']['id']
success_cases = [
{'ports': [port_id]},
@ -1406,7 +1005,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def_fwg_id = self._build_default_fwg(ctx=ctx)['id']
with self.port(
device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF,
ctx=ctx) as dummy_port:
tenant_id=ctx.project_id) as dummy_port:
port_id = dummy_port['port']['id']
conflict_cases = [
{'name': ''},
@ -1432,7 +1031,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
ctx = self._get_admin_context()
with self.port(
device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF,
ctx=ctx) as dummy_port:
tenant_id=ctx.project_id) as dummy_port:
port_id = dummy_port['port']['id']
def_fwg_id = self._build_default_fwg(ctx=ctx)['id']
success_cases = [
@ -1457,7 +1056,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
ctx = self._get_admin_context()
with self.port(
device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF,
ctx=ctx) as dummy_port:
tenant_id=ctx.project_id) as dummy_port:
port_id = dummy_port['port']['id']
def_fwg_id = self._build_default_fwg(ctx=ctx)['id']
conflict_cases = [
@ -1547,26 +1146,29 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
self.assertEqual(404, res.status_int)
def test_update_firewall_group_fwp_not_found_on_different_tenant(self):
with self.firewall_policy(name='fwp1', tenant_id='tenant1',
do_delete=False) as fwp1, \
self.firewall_policy(name='fwp2', shared=False,
tenant_id='tenant2') as fwp2:
ctx_tenant1 = self._get_nonadmin_context(tenant_id='tenant1')
ctx_tenant2 = self._get_nonadmin_context(tenant_id='tenant2')
fwps = [fwp1, fwp2]
# create firewall using fwp1 exists the same tenant.
fwp1_id = fwps[0]['firewall_policy']['id']
fwp2_id = fwps[1]['firewall_policy']['id']
ctx = self._get_nonadmin_context()
with self.firewall_group(ingress_firewall_policy_id=fwp1_id,
context=ctx) as firewall:
fw_id = firewall['firewall_group']['id']
fw_db = self.plugin._get_firewall_group(ctx, fw_id)
fw_db['status'] = nl_constants.ACTIVE
# update firewall from fwp1 to fwp2(different tenant)
data = {'firewall_group':
{'ingress_firewall_policy_id': fwp2_id}}
req = self.new_update_request('firewall_groups', data, fw_id,
context=ctx)
with self.firewall_policy(name='fwp1', context=ctx_tenant1,
shared=False, do_delete=False) as fwp1, \
self.firewall_group(
ingress_firewall_policy_id=fwp1['firewall_policy']['id'],
context=ctx_tenant1, do_delete=False) as fwg:
fwg_id = fwg['firewall_group']['id']
# fw_db = self.db._get_firewall_group(ctx_tenant1, fwg_id)
# fw_db['status'] = nl_constants.ACTIVE
# update firewall from fwp1 to fwp2 (different tenant)
with self.firewall_policy(name='fwp2', context=ctx_tenant2,
shared=False) as fwp2:
data = {
'firewall_group': {
'ingress_firewall_policy_id':
fwp2['firewall_policy']['id'],
},
}
req = self.new_update_request('firewall_groups', data, fwg_id,
context=ctx_tenant1)
res = req.get_response(self.ext_api)
self.assertEqual(404, res.status_int)
@ -1586,11 +1188,11 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def test_delete_firewall_group_already_deleted(self):
ctx = self._get_admin_context()
deleted_id = uuidutils.generate_uuid()
with self.firewall_group(do_delete=False) as fwg:
with self.firewall_group(do_delete=False, context=ctx) as fwg:
fwg_id = fwg['firewall_group']['id']
self.assertIsNone(self.plugin.delete_firewall_group(ctx, fwg_id))
self.assertIsNone(self.plugin.delete_firewall_group(ctx, deleted_id))
# No error raise is fwg not found on delete
self.assertIsNone(self.plugin.delete_firewall_group(ctx, fwg_id))
def test_delete_default_firewall_group_with_admin(self):
ctx_a = self._get_admin_context()
@ -1980,45 +1582,36 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase):
def test_set_port_in_use_for_firewall_group(self):
fwg_db = {'id': 'fake_id'}
new_ports = {'ports': ['fake_port1', 'fake_port2']}
m_context = context.get_admin_context()
m_context = self._get_admin_context()
with mock.patch.object(m_context.session, 'add',
side_effect=[None, f_exc.FirewallGroupPortInUse(
port_ids=['fake_port2'])]):
self.assertRaises(f_exc.FirewallGroupPortInUse,
self.plugin._set_ports_for_firewall_group,
self.db._set_ports_for_firewall_group,
m_context,
fwg_db,
new_ports)
def test_set_port_for_default_firewall_group(self):
ctx = self._get_nonadmin_context()
self._build_default_fwg(ctx=ctx)
with self.port(project_id=ctx.tenant_id) as port1, \
self.port(project_id=ctx.tenant_id) as port2:
default_fwg = self._build_default_fwg(ctx=ctx)
port_args = {
'tenant_id': ctx.tenant_id,
'device_owner': 'compute:nova',
'binding:vif_type': 'ovs',
}
self.plugin._is_supported_by_fw_l2_driver = mock.Mock(
return_value=True)
with self.port(**port_args) as port1, self.port(**port_args) as port2:
port1_id = port1['port']['id']
port2_id = port2['port']['id']
port_ids = [port1_id, port2_id]
project_id = ctx.tenant_id
self.plugin.set_port_for_default_firewall_group(
ctx, port1_id, project_id)
self.plugin.set_port_for_default_firewall_group(
ctx, port2_id, project_id)
def_fwg_db = self.plugin._get_default_fwg(ctx, project_id)
self.assertEqual('PENDING_UPDATE', def_fwg_db['status'])
self.assertEqual(sorted(port_ids), sorted(def_fwg_db['ports']))
def test_set_port_for_default_firewall_group_raised_port_in_use(self):
ctx = self._get_nonadmin_context()
self._build_default_fwg(ctx=ctx)
self.plugin.update_firewall_group_status = mock.Mock()
with self.port(project_id=ctx.tenant_id) as port1:
port1_id = port1['port']['id']
port_ids = [port1_id]
self.plugin._set_ports_for_firewall_group = mock.Mock(
side_effect=f_exc.FirewallGroupPortInUse(port_ids=port_ids))
project_id = ctx.tenant_id
self.plugin.set_port_for_default_firewall_group(
ctx, port1_id, project_id)
self.plugin.update_firewall_group_status.assert_not_called()
self.plugin.update_firewall_group(
ctx,
default_fwg['id'],
{'firewall_group': {'ports': port_ids}},
)
default_fwg = self.plugin.get_firewall_group(ctx,
default_fwg['id'])
self.assertEqual(sorted(port_ids), sorted(default_fwg['ports']))

View File

@ -16,7 +16,8 @@
import mock
from neutron import manager
from neutron_fwaas.services.firewall.drivers.linux.l2.noop import noop_driver
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
noop import noop_driver
from neutron_fwaas.tests import base

View File

@ -24,12 +24,12 @@ from neutron.plugins.ml2.drivers.openvswitch.agent import \
ovs_agent_extension_api as ovs_ext_api
from neutron.tests import base
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import constants as fwaas_ovs_consts
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import exceptions
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import firewall as ovsfw
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import constants as fwaas_ovs_consts
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import exceptions
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import firewall as ovsfw
TESTING_VLAN_TAG = 1

View File

@ -20,12 +20,12 @@ from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \
as ovs_consts
from neutron.tests import base
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import constants as fwaas_ovs_consts
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import firewall as ovsfw
from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \
import rules
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import constants as fwaas_ovs_consts
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import firewall as ovsfw
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\
openvswitch_firewall import rules
TESTING_VLAN_TAG = 1

View File

@ -19,7 +19,8 @@ import mock
from neutron.tests import base
from neutron.tests.unit.api.v2 import test_base as test_api_v2
import neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas as fwaas
import neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.\
iptables_fwaas as fwaas
_uuid = test_api_v2._uuid

View File

@ -19,7 +19,8 @@ import mock
from neutron.tests import base
from neutron.tests.unit.api.v2 import test_base as test_api_v2
import neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas_v2 as fwaas
import neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.\
iptables_fwaas_v2 as fwaas
_uuid = test_api_v2._uuid

View File

@ -17,7 +17,8 @@ import mock
import testtools
from neutron.tests import base
from neutron_fwaas.services.firewall.drivers.linux import legacy_conntrack
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux \
import legacy_conntrack
from neutron_lib import constants
@ -128,8 +129,8 @@ class ConntrackLegacyTestCase(base.BaseTestCase):
def test_delete_entries(self):
list_entries_mock = mock.patch(
'neutron_fwaas.services.firewall.drivers.linux'
'.legacy_conntrack.ConntrackLegacy.list_entries')
'neutron_fwaas.services.firewall.service_drivers.agents.drivers.'
'linux.legacy_conntrack.ConntrackLegacy.list_entries')
self.list_entries = list_entries_mock.start()
self.conntrack_driver.list_entries.return_value = [

View File

@ -15,7 +15,8 @@
import mock
from neutron_fwaas.services.firewall.drivers.linux import netlink_conntrack
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux \
import netlink_conntrack
from neutron_fwaas.tests import base
FW_RULES = [

View File

@ -21,9 +21,10 @@ from neutron_lib.exceptions import firewall_v2 as f_exc
from oslo_config import cfg
from neutron_fwaas.common import fwaas_constants as consts
from neutron_fwaas.services.firewall.agents.l2 import fwaas_v2
from neutron_fwaas.services.firewall.service_drivers.agents.l2 import fwaas_v2
from neutron_fwaas.tests import base
from neutron_fwaas.tests.unit.services.firewall.agents.l2 import fake_data
from neutron_fwaas.tests.unit.services.firewall.service_drivers.agents.l2\
import fake_data
class TestFWaasV2AgentExtensionBase(base.BaseTestCase):

View File

@ -24,11 +24,12 @@ from oslo_utils import uuidutils
import testtools
from neutron_fwaas.common import fwaas_constants
from neutron_fwaas.services.firewall.agents import firewall_agent_api
from neutron_fwaas.services.firewall.agents.l3reference \
from neutron_fwaas.services.firewall.service_drivers.agents \
import firewall_agent_api
from neutron_fwaas.services.firewall.service_drivers.agents.l3reference \
import firewall_l3_agent
from neutron_fwaas.tests import base
from neutron_fwaas.tests.unit.services.firewall.agents \
from neutron_fwaas.tests.unit.services.firewall.service_drivers.agents \
import test_firewall_agent_api

View File

@ -23,13 +23,14 @@ from oslo_config import cfg
from oslo_utils import uuidutils
from neutron_fwaas.common import fwaas_constants
from neutron_fwaas.services.firewall.agents import firewall_agent_api
from neutron_fwaas.services.firewall.agents.l3reference \
import firewall_l3_agent_v2
from neutron_fwaas.services.firewall.drivers.linux \
from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux \
import iptables_fwaas_v2
from neutron_fwaas.services.firewall.service_drivers.agents \
import firewall_agent_api
from neutron_fwaas.services.firewall.service_drivers.agents.l3reference \
import firewall_l3_agent_v2
from neutron_fwaas.tests import base
from neutron_fwaas.tests.unit.services.firewall.agents \
from neutron_fwaas.tests.unit.services.firewall.service_drivers.agents \
import test_firewall_agent_api

View File

@ -0,0 +1,654 @@
# Copyright 2016
# 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 mock
import six
from neutron import extensions as neutron_extensions
from neutron.tests.unit.extensions import test_l3
from neutron_lib import constants as nl_constants
from neutron_lib import context
from neutron_lib.exceptions import firewall_v2 as f_exc
from neutron_lib.plugins import directory
from oslo_config import cfg
from neutron_fwaas._i18n import _
from neutron_fwaas.db.firewall.v2.firewall_db_v2 import FirewallGroup
from neutron_fwaas.services.firewall.service_drivers.agents import agents
from neutron_fwaas.tests import base
from neutron_fwaas.tests.unit.services.firewall import test_fwaas_plugin_v2
FIREWALL_AGENT_PLUGIN = ('neutron_fwaas.services.firewall.service_drivers.'
'agents.agents')
FIREWALL_AGENT_PLUGIN_KLASS = FIREWALL_AGENT_PLUGIN + '.FirewallAgentDriver'
DELETEFW_PATH = (FIREWALL_AGENT_PLUGIN + '.FirewallAgentApi.'
'delete_firewall_group')
class FakeAgentApi(agents.FirewallAgentCallbacks):
"""
This class used to mock the AgentAPI delete method inherits from
FirewallCallbacks because it needs access to the firewall_deleted method.
The delete_firewall method belongs to the FirewallAgentApi, which has
no access to the firewall_deleted method normally because it's not
responsible for deleting the firewall from the DB. However, it needs
to in the unit tests since there is no agent to call back.
"""
def __init__(self):
return
def delete_firewall_group(self, context, firewall_group, **kwargs):
self.plugin = directory.get_plugin('FIREWALL_V2')
self.firewall_db = self.plugin.driver.firewall_db
self.firewall_group_deleted(context, firewall_group['id'], **kwargs)
class TestFirewallAgentApi(base.BaseTestCase):
def setUp(self):
super(TestFirewallAgentApi, self).setUp()
self.api = agents.FirewallAgentApi('topic', 'host')
def test_init(self):
self.assertEqual('topic', self.api.client.target.topic)
self.assertEqual('host', self.api.host)
def _call_test_helper(self, method_name):
with mock.patch.object(self.api.client, 'cast') as rpc_mock, \
mock.patch.object(self.api.client, 'prepare') as prepare_mock:
prepare_mock.return_value = self.api.client
getattr(self.api, method_name)(mock.sentinel.context, 'test')
prepare_args = {'fanout': True}
prepare_mock.assert_called_once_with(**prepare_args)
rpc_mock.assert_called_once_with(mock.sentinel.context, method_name,
firewall_group='test', host='host')
def test_create_firewall_group(self):
self._call_test_helper('create_firewall_group')
def test_update_firewall_group(self):
self._call_test_helper('update_firewall_group')
def test_delete_firewall_group(self):
self._call_test_helper('delete_firewall_group')
class TestAgentDriver(test_fwaas_plugin_v2.FirewallPluginV2TestCase,
test_l3.L3NatTestCaseMixin):
def setUp(self):
self.agentapi_del_fw_p = mock.patch(
DELETEFW_PATH, create=True,
new=FakeAgentApi().delete_firewall_group,
).start()
mock.patch.object(agents.neutron_rpc, 'get_client').start()
mock.patch.object(agents.neutron_rpc, 'Connection').start()
l3_plugin_str = ('neutron.tests.unit.extensions.test_l3.'
'TestL3NatServicePlugin')
l3_plugin = {'l3_plugin_name': l3_plugin_str}
super(TestAgentDriver, self).setUp(
service_provider=FIREWALL_AGENT_PLUGIN_KLASS,
extra_service_plugins=l3_plugin,
extra_extension_paths=neutron_extensions.__path__)
self.callbacks = self.plugin.driver.endpoints[0]
self.db = self.plugin.driver.firewall_db
router_distributed_opts = [
cfg.BoolOpt(
'router_distributed',
default=False,
help=_("System-wide flag to determine the type of router "
"that tenants can create. Only admin can override.")),
]
cfg.CONF.register_opts(router_distributed_opts)
@property
def _self_context(self):
return context.Context('', self._tenant_id)
def _get_test_firewall_group_attrs(self, name,
status=nl_constants.INACTIVE):
return super(TestAgentDriver, self)._get_test_firewall_group_attrs(
name, status=status)
def test_set_firewall_group_status(self):
ctx = context.get_admin_context()
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
ingress_firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP
) as fwg:
fwg_id = fwg['firewall_group']['id']
res = self.callbacks.set_firewall_group_status(ctx, fwg_id,
nl_constants.ACTIVE)
fwg_db = self.plugin.get_firewall_group(ctx, fwg_id)
self.assertEqual(nl_constants.ACTIVE, fwg_db['status'])
self.assertTrue(res)
res = self.callbacks.set_firewall_group_status(ctx, fwg_id,
nl_constants.ERROR)
fwg_db = self.plugin.get_firewall_group(ctx, fwg_id)
self.assertEqual(nl_constants.ERROR, fwg_db['status'])
self.assertFalse(res)
def test_firewall_group_deleted(self):
ctx = context.get_admin_context()
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
ingress_firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP,
do_delete=False
) as fwg:
fwg_id = fwg['firewall_group']['id']
with ctx.session.begin(subtransactions=True):
fwg_db = self.db._get_firewall_group(ctx, fwg_id)
fwg_db['status'] = nl_constants.PENDING_DELETE
observed = self.callbacks.firewall_group_deleted(ctx, fwg_id)
self.assertTrue(observed)
self.assertRaises(f_exc.FirewallGroupNotFound,
self.plugin.get_firewall_group,
ctx, fwg_id)
def test_firewall_group_deleted_concurrently(self):
ctx = context.get_admin_context()
alt_ctx = context.get_admin_context()
_get_firewall_group = self.db._get_firewall_group
def getdelete(context, fwg_id):
fwg_db = _get_firewall_group(context, fwg_id)
# NOTE(cby): Use a different session to simulate a concurrent del
with alt_ctx.session.begin(subtransactions=True):
alt_ctx.session.query(FirewallGroup).filter_by(
id=fwg_id).delete()
return fwg_db
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP,
do_delete=False
) as fwg:
fwg_id = fwg['firewall_group']['id']
with ctx.session.begin(subtransactions=True):
fwg_db = self.db._get_firewall_group(ctx, fwg_id)
fwg_db['status'] = nl_constants.PENDING_DELETE
ctx.session.flush()
with mock.patch.object(
self.db, '_get_firewall_group', side_effect=getdelete
):
observed = self.callbacks.firewall_group_deleted(
ctx, fwg_id)
self.assertTrue(observed)
self.assertRaises(f_exc.FirewallGroupNotFound,
self.plugin.get_firewall_group,
ctx, fwg_id)
def test_firewall_group_deleted_not_found(self):
ctx = context.get_admin_context()
observed = self.callbacks.firewall_group_deleted(
ctx, 'notfound')
self.assertTrue(observed)
def test_firewall_group_deleted_error(self):
ctx = context.get_admin_context()
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP,
) as fwg:
fwg_id = fwg['firewall_group']['id']
observed = self.callbacks.firewall_group_deleted(
ctx, fwg_id)
self.assertFalse(observed)
fwg_db = self.db._get_firewall_group(ctx, fwg_id)
self.assertEqual(nl_constants.ERROR, fwg_db['status'])
def test_create_firewall_group_ports_not_specified(self):
"""neutron firewall-create test-policy """
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
def test_create_firewall_group_with_ports(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
def test_create_firewall_group_with_ports_on_diff_routers(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r2, \
self.subnet() as s3:
body = self._router_interface_action(
'add',
r2['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
fwg_ports = [port_id1, port_id2, port_id3]
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
def test_create_firewall_group_with_ports_no_policy(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
def test_update_firewall_group_with_new_ports_no_policy(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2, \
self.subnet(cidr='30.0.0.0/24') as s3:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
data = {'firewall_group': {'ports': [port_id2, port_id3]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context)
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(sorted([port_id2, port_id3]),
sorted(res['firewall_group']['ports']))
self.assertEqual(nl_constants.INACTIVE,
res['firewall_group']['status'])
def test_update_firewall_group_with_new_ports_status_pending(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2, \
self.subnet(cidr='30.0.0.0/24') as s3:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
body = self._router_interface_action(
'add',
r['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
data = {'firewall_group': {'ports': [port_id2, port_id3]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(409, res.status_int)
def test_update_firewall_group_with_new_ports_status_active(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2, \
self.subnet(cidr='30.0.0.0/24') as s3:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
body = self._router_interface_action(
'add',
r['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
ctx = context.get_admin_context()
self.callbacks.set_firewall_group_status(ctx,
fwg1['firewall_group']['id'], nl_constants.ACTIVE)
data = {'firewall_group': {'ports': [port_id2, port_id3]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context)
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(sorted([port_id2, port_id3]),
sorted(res['firewall_group']['ports']))
def test_update_firewall_rule_on_active_fwg(self):
name = "new_firewall_rule1"
attrs = self._get_test_firewall_rule_attrs(name)
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
with self.firewall_rule() as fwr:
with self.firewall_policy(
firewall_rules=[fwr['firewall_rule']['id']]) as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=[port_id1],
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
ctx = context.get_admin_context()
self.callbacks.set_firewall_group_status(ctx,
fwg1['firewall_group']['id'], nl_constants.ACTIVE)
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))
for k, v in six.iteritems(attrs):
self.assertEqual(v, res['firewall_rule'][k])
def test_update_firewall_rule_on_pending_create_fwg(self):
"""update should fail"""
name = "new_firewall_rule1"
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
with self.firewall_rule() as fwr:
with self.firewall_policy(
firewall_rules=[fwr['firewall_rule']['id']]) as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=[port_id1],
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
data = {'firewall_rule': {'name': name}}
req = self.new_update_request('firewall_rules', data,
fwr['firewall_rule']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(409, res.status_int)
def test_update_firewall_group_with_non_exist_ports(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet(cidr='30.0.0.0/24') as s:
body = self._router_interface_action(
'add',
r['router']['id'],
s['subnet']['id'],
None)
port_id1 = body['port_id']
foo_port_id = 'caef152d-b118-4b9b-bc77-800661bf082d'
fwg_ports = [port_id1]
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
data = {'firewall_group': {'ports': [foo_port_id]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'])
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual('PortNotFound',
res['NeutronError']['type'])
def test_update_firewall_group_with_ports_and_policy(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r,\
self.subnet() as s1,\
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_rule() as fwr:
with self.firewall_policy(
firewall_rules=[fwr['firewall_rule']['id']]) as fwp:
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
fwp_id = fwp["firewall_policy"]["id"]
data = {'firewall_group': {'ports': fwg_ports}}
req = (self.
new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context))
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(nl_constants.INACTIVE,
res['firewall_group']['status'])
data = {'firewall_group': {
'ingress_firewall_policy_id': fwp_id}}
req = (self.
new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context))
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(nl_constants.PENDING_UPDATE,
res['firewall_group']['status'])
def test_create_firewall_group_with_dvr(self):
cfg.CONF.set_override('router_distributed', True)
attrs = self._get_test_firewall_group_attrs("firewall1")
self._test_create_firewall_group(attrs)
def test_create_firewall_group(self):
attrs = self._get_test_firewall_group_attrs("firewall1")
self._test_create_firewall_group(attrs)
def test_create_firewall_group_with_empty_ports(self):
attrs = self._get_test_firewall_group_attrs("fwg1")
attrs['ports'] = []
self._test_create_firewall_group(attrs)

View File

@ -15,9 +15,12 @@
import mock
from neutron_fwaas.services.firewall.agents import firewall_agent_api as api
from neutron_fwaas.services.firewall.drivers import fwaas_base
from neutron_fwaas.services.firewall.drivers import fwaas_base_v2
from neutron_fwaas.services.firewall.service_drivers.agents.drivers \
import fwaas_base
from neutron_fwaas.services.firewall.service_drivers.agents.drivers \
import fwaas_base_v2
from neutron_fwaas.services.firewall.service_drivers.agents \
import firewall_agent_api as api
from neutron_fwaas.tests import base

View File

@ -16,10 +16,12 @@
from neutron.tests import base
from oslo_config import cfg
from neutron_fwaas.services.firewall.agents import firewall_service
from neutron_fwaas.services.firewall.service_drivers.agents import\
firewall_service
FWAAS_NOP_DEVICE = ('neutron_fwaas.tests.unit.services.firewall.agents.'
'test_firewall_agent_api.NoopFwaasDriver')
FWAAS_NOP_DEVICE = ('neutron_fwaas.tests.unit.services.firewall.'
'service_drivers.agents.test_firewall_agent_api.'
'NoopFwaasDriver')
class TestFirewallDeviceDriverLoading(base.BaseTestCase):

View File

@ -34,9 +34,9 @@ setup-hooks =
firewall_drivers =
# These are for backwards compat with Juno firewall service provider
# configuration values
neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas:IptablesFwaasDriver
iptables = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas:IptablesFwaasDriver
iptables_v2 = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas_v2:IptablesFwaasDriver
neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.iptables_fwaas:IptablesFwaasDriver
iptables = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.iptables_fwaas:IptablesFwaasDriver
iptables_v2 = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.iptables_fwaas_v2:IptablesFwaasDriver
neutron.service_plugins =
firewall = neutron_fwaas.services.firewall.fwaas_plugin:FirewallPlugin
firewall_v2 = neutron_fwaas.services.firewall.fwaas_plugin_v2:FirewallPluginV2
@ -50,16 +50,16 @@ oslo.config.opts =
neutron.fwaas = neutron_fwaas.opts:list_opts
firewall.agent = neutron_fwaas.opts:list_agent_opts
neutron.agent.l2.extensions =
fwaas_v2 = neutron_fwaas.services.firewall.agents.l2.fwaas_v2:FWaaSV2AgentExtension
fwaas_v2 = neutron_fwaas.services.firewall.service_drivers.agents.l2.fwaas_v2:FWaaSV2AgentExtension
neutron.agent.l2.firewall_drivers =
noop = neutron_fwaas.services.firewall.drivers.linux.l2.noop.noop_driver:NoopFirewallL2Driver
ovs = neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall.firewall:OVSFirewallDriver
noop = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.noop.noop_driver:NoopFirewallL2Driver
ovs = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.openvswitch_firewall.firewall:OVSFirewallDriver
neutron.agent.l3.extensions =
fwaas = neutron_fwaas.services.firewall.agents.l3reference.firewall_l3_agent:L3WithFWaaS
fwaas_v2 = neutron_fwaas.services.firewall.agents.l3reference.firewall_l3_agent_v2:L3WithFWaaS
neutron_fwaas.services.firewall.drivers.linux =
conntrack = neutron_fwaas.services.firewall.drivers.linux.legacy_conntrack:ConntrackLegacy
netlink_conntrack = neutron_fwaas.services.firewall.drivers.linux.netlink_conntrack:ConntrackNetlink
fwaas = neutron_fwaas.services.firewall.service_drivers.agents.l3reference.firewall_l3_agent:L3WithFWaaS
fwaas_v2 = neutron_fwaas.services.firewall.service_drivers.agents.l3reference.firewall_l3_agent_v2:L3WithFWaaS
neutron.agent.l3.firewall_drivers =
conntrack = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.legacy_conntrack:ConntrackLegacy
netlink_conntrack = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.netlink_conntrack:ConntrackNetlink
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext