Removing FWaaS v1 source code
As German Eichberger's email at https://markmail.org/message/2kva4b3lwgddyeau. So This patch intend to removes source code related FWaaS V1. Change-Id: I4e440c854e5aa11193d38946e659481f4fefded2
This commit is contained in:
parent
d2adcdec83
commit
0e968fa0c7
@ -14,21 +14,17 @@
|
|||||||
- neutron-fwaas-networking-midonet-cross-py35:
|
- neutron-fwaas-networking-midonet-cross-py35:
|
||||||
voting: false
|
voting: false
|
||||||
- legacy-neutron-fwaas-v2-dsvm-tempest
|
- legacy-neutron-fwaas-v2-dsvm-tempest
|
||||||
- legacy-neutron-fwaas-v1-dsvm-tempest
|
|
||||||
- legacy-neutron-fwaas-dsvm-functional
|
- legacy-neutron-fwaas-dsvm-functional
|
||||||
- legacy-grenade-dsvm-neutron-fwaas-multinode:
|
- legacy-grenade-dsvm-neutron-fwaas-multinode:
|
||||||
voting: false
|
voting: false
|
||||||
irrelevant-files:
|
irrelevant-files:
|
||||||
- ^(test-|)requirements.txt$
|
- ^(test-|)requirements.txt$
|
||||||
- ^setup.cfg$
|
- ^setup.cfg$
|
||||||
- legacy-neutron-fwaas-v1-dsvm-tempest-multinode:
|
|
||||||
voting: false
|
|
||||||
- legacy-neutron-fwaas-v2-dsvm-tempest-multinode:
|
- legacy-neutron-fwaas-v2-dsvm-tempest-multinode:
|
||||||
voting: false
|
voting: false
|
||||||
gate:
|
gate:
|
||||||
jobs:
|
jobs:
|
||||||
- legacy-neutron-fwaas-v2-dsvm-tempest
|
- legacy-neutron-fwaas-v2-dsvm-tempest
|
||||||
- legacy-neutron-fwaas-v1-dsvm-tempest
|
|
||||||
- legacy-neutron-fwaas-dsvm-functional
|
- legacy-neutron-fwaas-dsvm-functional
|
||||||
experimental:
|
experimental:
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -6,10 +6,8 @@ This is setup as a DevStack plugin. For more information on DevStack plugins,
|
|||||||
see the `DevStack Plugins documentation
|
see the `DevStack Plugins documentation
|
||||||
<https://docs.openstack.org/devstack/latest/plugins.html>`_.
|
<https://docs.openstack.org/devstack/latest/plugins.html>`_.
|
||||||
|
|
||||||
Please note that the old 'q-fwaas' keyword still exists, and will run FWaaS V1.
|
Please note that the old 'q-fwaas' keyword still exists, You can specify
|
||||||
This default will be changed during the Ocata cycle. The introduction of two
|
enable_service q-fwaas or enable_service q-fwaas-v2 in local.conf
|
||||||
new keywords, 'q-fwaas-v1' and 'q-fwaas-v2' allow you to explicitly select the
|
|
||||||
version you with to run.
|
|
||||||
|
|
||||||
How to run FWaaS V2 in DevStack
|
How to run FWaaS V2 in DevStack
|
||||||
===============================
|
===============================
|
||||||
@ -32,25 +30,3 @@ testing.
|
|||||||
[[local|localrc]]
|
[[local|localrc]]
|
||||||
enable_plugin neutron-fwaas https://review.openstack.org/p/openstack/neutron-fwaas refs/changes/50/214350/14
|
enable_plugin neutron-fwaas https://review.openstack.org/p/openstack/neutron-fwaas refs/changes/50/214350/14
|
||||||
enable_service q-fwaas-v2
|
enable_service q-fwaas-v2
|
||||||
|
|
||||||
How to run FWaaS V1 in DevStack
|
|
||||||
===============================
|
|
||||||
|
|
||||||
Add the following to the localrc section of your local.conf to configure
|
|
||||||
FWaaS v1.
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[[local|localrc]]
|
|
||||||
enable_plugin neutron-fwaas https://git.openstack.org/openstack/neutron-fwaas
|
|
||||||
enable_service q-fwaas-v1
|
|
||||||
|
|
||||||
To check a specific patchset that is currently under development, use a form
|
|
||||||
like the below example, which is checking out change 214350 patch set 14 for
|
|
||||||
testing.
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[[local|localrc]]
|
|
||||||
enable_plugin neutron-fwaas https://review.openstack.org/p/openstack/neutron-fwaas refs/changes/50/214350/14
|
|
||||||
enable_service q-fwaas-v1
|
|
||||||
|
@ -38,14 +38,6 @@ function install_fwaas() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function configure_fwaas_v1() {
|
|
||||||
cp $NEUTRON_FWAAS_DIR/etc/neutron_fwaas.conf.sample $NEUTRON_FWAAS_CONF
|
|
||||||
neutron_fwaas_configure_driver fwaas
|
|
||||||
iniset_multiline $Q_L3_CONF_FILE fwaas agent_version v1
|
|
||||||
iniset_multiline $Q_L3_CONF_FILE fwaas conntrack_driver conntrack
|
|
||||||
iniset_multiline $Q_L3_CONF_FILE fwaas driver $FWAAS_DRIVER_V1
|
|
||||||
}
|
|
||||||
|
|
||||||
function configure_fwaas_v2() {
|
function configure_fwaas_v2() {
|
||||||
# Add conf file
|
# Add conf file
|
||||||
cp $NEUTRON_FWAAS_DIR/etc/neutron_fwaas.conf.sample $NEUTRON_FWAAS_CONF
|
cp $NEUTRON_FWAAS_DIR/etc/neutron_fwaas.conf.sample $NEUTRON_FWAAS_CONF
|
||||||
@ -93,13 +85,7 @@ function cleanup_fwaas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function neutron_fwaas_configure_common {
|
function neutron_fwaas_configure_common {
|
||||||
if is_service_enabled q-fwaas-v1 neutron-fwaas-v1; then
|
neutron_service_plugin_class_add $FWAAS_PLUGIN_V2
|
||||||
neutron_service_plugin_class_add $FWAAS_PLUGIN_V1
|
|
||||||
elif is_service_enabled q-fwaas-v2 neutron-fwaas-v2; then
|
|
||||||
neutron_service_plugin_class_add $FWAAS_PLUGIN_V2
|
|
||||||
else
|
|
||||||
neutron_service_plugin_class_add $FWAAS_PLUGIN_V1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function neutron_fwaas_configure_driver {
|
function neutron_fwaas_configure_driver {
|
||||||
@ -109,7 +95,7 @@ function neutron_fwaas_configure_driver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# check for service enabled
|
# check for service enabled
|
||||||
if is_service_enabled q-svc neutron-api && is_service_enabled q-fwaas q-fwaas-v1 q-fwaas-v2 neutron-fwaas-v1 neutron-fwaas-v2; then
|
if is_service_enabled q-svc neutron-api && is_service_enabled q-fwaas q-fwaas-v2 neutron-fwaas-v2; then
|
||||||
|
|
||||||
if [[ "$1" == "stack" && "$2" == "install" ]]; then
|
if [[ "$1" == "stack" && "$2" == "install" ]]; then
|
||||||
# Perform installation of service source
|
# Perform installation of service source
|
||||||
@ -120,19 +106,11 @@ if is_service_enabled q-svc neutron-api && is_service_enabled q-fwaas q-fwaas-v1
|
|||||||
# Configure after the other layer 1 and 2 services have been configured
|
# Configure after the other layer 1 and 2 services have been configured
|
||||||
neutron_fwaas_configure_common
|
neutron_fwaas_configure_common
|
||||||
neutron_fwaas_generate_config_files
|
neutron_fwaas_generate_config_files
|
||||||
if is_service_enabled q-fwaas-v1 neutron-fwaas-v1; then
|
echo_summary "Configuring neutron-fwaas for FWaaS v2"
|
||||||
echo_summary "Configuring neutron-fwaas for FWaaS v1"
|
configure_fwaas_v2
|
||||||
configure_fwaas_v1
|
if is_service_enabled q-log neutron-log; then
|
||||||
elif is_service_enabled q-fwaas-v2 neutron-fwaas-v2; then
|
echo_summary "Configuring FwaaS V2 packet log for l3 extension"
|
||||||
echo_summary "Configuring neutron-fwaas for FWaaS v2"
|
configure_l3_log_fwaas_v2
|
||||||
configure_fwaas_v2
|
|
||||||
if is_service_enabled q-log neutron-log; then
|
|
||||||
echo_summary "Configuring FwaaS V2 packet log for l3 extension"
|
|
||||||
configure_l3_log_fwaas_v2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo_summary "Configuring neutron-fwaas for FWaaS v1"
|
|
||||||
configure_fwaas_v1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
FWAAS_DRIVER_V1=${FWAAS_DRIVER_V1:-iptables}
|
|
||||||
FWAAS_DRIVER_V2=${FWAAS_DRIVER_V2:-iptables_v2}
|
FWAAS_DRIVER_V2=${FWAAS_DRIVER_V2:-iptables_v2}
|
||||||
FW_L2_DRIVER=${FW_L2_DRIVER:-noop}
|
FW_L2_DRIVER=${FW_L2_DRIVER:-noop}
|
||||||
FWAAS_PLUGIN_V1=${FWAAS_PLUGIN:-firewall}
|
|
||||||
FWAAS_PLUGIN_V2=${FWAAS_PLUGIN:-firewall_v2}
|
FWAAS_PLUGIN_V2=${FWAAS_PLUGIN:-firewall_v2}
|
||||||
|
|
||||||
NEUTRON_FWAAS_DIR=$DEST/neutron-fwaas
|
NEUTRON_FWAAS_DIR=$DEST/neutron-fwaas
|
||||||
|
@ -13,38 +13,13 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import operator
|
|
||||||
|
|
||||||
from neutron.db import common_db_mixin as base_db
|
|
||||||
from neutron.db.models import agent as agent_model
|
|
||||||
from neutron.db.models import l3agent as l3agent_model
|
|
||||||
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.db import model_base
|
from neutron_lib.db import model_base
|
||||||
from neutron_lib.exceptions import firewall_v1 as f_exc
|
|
||||||
from neutron_lib.exceptions import l3
|
|
||||||
from neutron_lib.plugins import directory
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import log as logging
|
|
||||||
from oslo_utils import uuidutils
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.ext.orderinglist import ordering_list
|
from sqlalchemy.ext.orderinglist import ordering_list
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
from sqlalchemy.orm import exc
|
|
||||||
|
|
||||||
import netaddr
|
|
||||||
|
|
||||||
from neutron_fwaas.common import fwaas_constants
|
|
||||||
from neutron_fwaas.db.firewall import firewall_router_insertion_db \
|
|
||||||
as fw_r_ins_db
|
|
||||||
from neutron_fwaas.extensions import firewall as fw_ext
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
|
# Note(annp): Keep firewall db v1 structure for migration
|
||||||
class FirewallRule(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
class FirewallRule(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
||||||
"""Represents a Firewall rule."""
|
"""Represents a Firewall rule."""
|
||||||
__tablename__ = 'firewall_rules'
|
__tablename__ = 'firewall_rules'
|
||||||
@ -100,558 +75,15 @@ class FirewallPolicy(model_base.BASEV2, model_base.HasId,
|
|||||||
firewalls = orm.relationship(Firewall, backref='firewall_policies')
|
firewalls = orm.relationship(Firewall, backref='firewall_policies')
|
||||||
|
|
||||||
|
|
||||||
class Firewall_db_mixin(fw_ext.FirewallPluginBase, base_db.CommonDbMixin):
|
class FirewallRouterAssociation(model_base.BASEV2):
|
||||||
"""Mixin class for Firewall DB implementation."""
|
|
||||||
|
|
||||||
@property
|
"""Tracks FW Router Association"""
|
||||||
def _core_plugin(self):
|
|
||||||
return directory.get_plugin()
|
|
||||||
|
|
||||||
def _get_firewall(self, context, id):
|
__tablename__ = 'firewall_router_associations'
|
||||||
try:
|
|
||||||
return self._get_by_id(context, Firewall, id)
|
|
||||||
except exc.NoResultFound:
|
|
||||||
raise f_exc.FirewallNotFound(firewall_id=id)
|
|
||||||
|
|
||||||
def _get_firewall_policy(self, context, id):
|
fw_id = sa.Column(sa.String(36),
|
||||||
try:
|
sa.ForeignKey('firewalls.id', ondelete="CASCADE"),
|
||||||
return self._get_by_id(context, FirewallPolicy, id)
|
primary_key=True)
|
||||||
except exc.NoResultFound:
|
router_id = sa.Column(sa.String(36),
|
||||||
raise f_exc.FirewallPolicyNotFound(firewall_policy_id=id)
|
sa.ForeignKey('routers.id', ondelete="CASCADE"),
|
||||||
|
primary_key=True)
|
||||||
def _get_firewall_rule(self, context, id):
|
|
||||||
try:
|
|
||||||
return self._get_by_id(context, FirewallRule, id)
|
|
||||||
except exc.NoResultFound:
|
|
||||||
raise f_exc.FirewallRuleNotFound(firewall_rule_id=id)
|
|
||||||
|
|
||||||
def _make_firewall_dict(self, fw, fields=None):
|
|
||||||
res = {'id': fw['id'],
|
|
||||||
'tenant_id': fw['tenant_id'],
|
|
||||||
'name': fw['name'],
|
|
||||||
'description': fw['description'],
|
|
||||||
'shared': fw['shared'],
|
|
||||||
'admin_state_up': fw['admin_state_up'],
|
|
||||||
'status': fw['status'],
|
|
||||||
'firewall_policy_id': fw['firewall_policy_id']}
|
|
||||||
return self._fields(res, fields)
|
|
||||||
|
|
||||||
def _make_firewall_policy_dict(self, firewall_policy, fields=None):
|
|
||||||
fw_rules = [rule['id'] for rule in firewall_policy['firewall_rules']]
|
|
||||||
firewalls = [fw['id'] for fw in firewall_policy['firewalls']]
|
|
||||||
res = {'id': firewall_policy['id'],
|
|
||||||
'tenant_id': firewall_policy['tenant_id'],
|
|
||||||
'name': firewall_policy['name'],
|
|
||||||
'description': firewall_policy['description'],
|
|
||||||
'shared': firewall_policy['shared'],
|
|
||||||
'audited': firewall_policy['audited'],
|
|
||||||
'firewall_rules': fw_rules,
|
|
||||||
'firewall_list': firewalls}
|
|
||||||
return self._fields(res, fields)
|
|
||||||
|
|
||||||
def _make_firewall_rule_dict(self, firewall_rule, fields=None):
|
|
||||||
position = None
|
|
||||||
# We return the position only if the firewall_rule is bound to a
|
|
||||||
# firewall_policy.
|
|
||||||
if firewall_rule['firewall_policy_id']:
|
|
||||||
position = firewall_rule['position']
|
|
||||||
src_port_range = self._get_port_range_from_min_max_ports(
|
|
||||||
firewall_rule['source_port_range_min'],
|
|
||||||
firewall_rule['source_port_range_max'])
|
|
||||||
dst_port_range = self._get_port_range_from_min_max_ports(
|
|
||||||
firewall_rule['destination_port_range_min'],
|
|
||||||
firewall_rule['destination_port_range_max'])
|
|
||||||
res = {'id': firewall_rule['id'],
|
|
||||||
'tenant_id': firewall_rule['tenant_id'],
|
|
||||||
'name': firewall_rule['name'],
|
|
||||||
'description': firewall_rule['description'],
|
|
||||||
'firewall_policy_id': firewall_rule['firewall_policy_id'],
|
|
||||||
'shared': firewall_rule['shared'],
|
|
||||||
'protocol': firewall_rule['protocol'],
|
|
||||||
'ip_version': firewall_rule['ip_version'],
|
|
||||||
'source_ip_address': firewall_rule['source_ip_address'],
|
|
||||||
'destination_ip_address':
|
|
||||||
firewall_rule['destination_ip_address'],
|
|
||||||
'source_port': src_port_range,
|
|
||||||
'destination_port': dst_port_range,
|
|
||||||
'action': firewall_rule['action'],
|
|
||||||
'position': position,
|
|
||||||
'enabled': firewall_rule['enabled']}
|
|
||||||
return self._fields(res, fields)
|
|
||||||
|
|
||||||
def _make_firewall_dict_with_rules(self, context, firewall_id):
|
|
||||||
firewall = self.get_firewall(context, firewall_id)
|
|
||||||
fw_policy_id = firewall['firewall_policy_id']
|
|
||||||
if fw_policy_id:
|
|
||||||
fw_rules_list = self.get_firewall_rules(
|
|
||||||
context, filters={'firewall_policy_id': [fw_policy_id]})
|
|
||||||
fw_rules_list = sorted(
|
|
||||||
fw_rules_list, key=operator.itemgetter('position'))
|
|
||||||
firewall['firewall_rule_list'] = fw_rules_list
|
|
||||||
else:
|
|
||||||
firewall['firewall_rule_list'] = []
|
|
||||||
# FIXME(Sumit): If the size of the firewall object we are creating
|
|
||||||
# here exceeds the largest message size supported by rabbit/qpid
|
|
||||||
# then we will have a problem.
|
|
||||||
return firewall
|
|
||||||
|
|
||||||
def _check_firewall_rule_conflict(self, fwr_db, fwp_db):
|
|
||||||
if not fwr_db['shared']:
|
|
||||||
if fwr_db['tenant_id'] != fwp_db['tenant_id']:
|
|
||||||
raise f_exc.FirewallRuleConflict(
|
|
||||||
firewall_rule_id=fwr_db['id'],
|
|
||||||
project_id=fwr_db['tenant_id'])
|
|
||||||
|
|
||||||
def _set_rules_for_policy(self, context, firewall_policy_db, fwp):
|
|
||||||
rule_id_list = fwp['firewall_rules']
|
|
||||||
fwp_db = firewall_policy_db
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
if not rule_id_list:
|
|
||||||
fwp_db.firewall_rules = []
|
|
||||||
fwp_db.audited = False
|
|
||||||
return
|
|
||||||
# We will first check if the new list of rules is valid
|
|
||||||
filters = {'id': [r_id for r_id in rule_id_list]}
|
|
||||||
rules_in_db = self._get_collection_query(context, FirewallRule,
|
|
||||||
filters=filters)
|
|
||||||
rules_dict = dict((fwr_db['id'], fwr_db) for fwr_db in rules_in_db)
|
|
||||||
for fwrule_id in rule_id_list:
|
|
||||||
if fwrule_id not in rules_dict:
|
|
||||||
# If we find an invalid rule in the list we
|
|
||||||
# do not perform the update since this breaks
|
|
||||||
# the integrity of this list.
|
|
||||||
raise f_exc.FirewallRuleNotFound(
|
|
||||||
firewall_rule_id=fwrule_id)
|
|
||||||
elif rules_dict[fwrule_id]['firewall_policy_id']:
|
|
||||||
if (rules_dict[fwrule_id]['firewall_policy_id'] !=
|
|
||||||
fwp_db['id']):
|
|
||||||
raise f_exc.FirewallRuleInUse(
|
|
||||||
firewall_rule_id=fwrule_id)
|
|
||||||
if 'shared' in fwp:
|
|
||||||
if fwp['shared'] and not rules_dict[fwrule_id]['shared']:
|
|
||||||
raise f_exc.FirewallRuleSharingConflict(
|
|
||||||
firewall_rule_id=fwrule_id,
|
|
||||||
firewall_policy_id=fwp_db['id'])
|
|
||||||
elif fwp_db['shared'] and not rules_dict[fwrule_id]['shared']:
|
|
||||||
raise f_exc.FirewallRuleSharingConflict(
|
|
||||||
firewall_rule_id=fwrule_id,
|
|
||||||
firewall_policy_id=fwp_db['id'])
|
|
||||||
for fwr_db in rules_in_db:
|
|
||||||
self._check_firewall_rule_conflict(fwr_db, fwp_db)
|
|
||||||
# New list of rules is valid so we will first reset the existing
|
|
||||||
# list and then add each rule in order.
|
|
||||||
# Note that the list could be empty in which case we interpret
|
|
||||||
# it as clearing existing rules.
|
|
||||||
fwp_db.firewall_rules = []
|
|
||||||
for fwrule_id in rule_id_list:
|
|
||||||
fwp_db.firewall_rules.append(rules_dict[fwrule_id])
|
|
||||||
fwp_db.firewall_rules.reorder()
|
|
||||||
fwp_db.audited = False
|
|
||||||
|
|
||||||
def _check_unshared_rules_for_policy(self, fwp_db, fwp):
|
|
||||||
if fwp['shared']:
|
|
||||||
rules_in_db = fwp_db['firewall_rules']
|
|
||||||
for fwr_db in rules_in_db:
|
|
||||||
if not fwr_db['shared']:
|
|
||||||
raise f_exc.FirewallPolicySharingConflict(
|
|
||||||
firewall_rule_id=fwr_db['id'],
|
|
||||||
firewall_policy_id=fwp_db['id'])
|
|
||||||
|
|
||||||
def _process_rule_for_policy(self, context, firewall_policy_id,
|
|
||||||
firewall_rule_db, position):
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fwp_query = context.session.query(
|
|
||||||
FirewallPolicy).with_lockmode('update')
|
|
||||||
fwp_db = fwp_query.filter_by(id=firewall_policy_id).one()
|
|
||||||
if position:
|
|
||||||
# Note that although position numbering starts at 1,
|
|
||||||
# internal ordering of the list starts at 0, so we compensate.
|
|
||||||
fwp_db.firewall_rules.insert(position - 1, firewall_rule_db)
|
|
||||||
else:
|
|
||||||
fwp_db.firewall_rules.remove(firewall_rule_db)
|
|
||||||
fwp_db.firewall_rules.reorder()
|
|
||||||
fwp_db.audited = False
|
|
||||||
return self._make_firewall_policy_dict(fwp_db)
|
|
||||||
|
|
||||||
def _get_min_max_ports_from_range(self, port_range):
|
|
||||||
if not port_range:
|
|
||||||
return [None, None]
|
|
||||||
min_port, sep, max_port = port_range.partition(":")
|
|
||||||
if not max_port:
|
|
||||||
max_port = min_port
|
|
||||||
self._validate_fwr_port_range(min_port, max_port)
|
|
||||||
return [int(min_port), int(max_port)]
|
|
||||||
|
|
||||||
def _get_port_range_from_min_max_ports(self, min_port, max_port):
|
|
||||||
if not min_port:
|
|
||||||
return None
|
|
||||||
if min_port == max_port:
|
|
||||||
return str(min_port)
|
|
||||||
self._validate_fwr_port_range(min_port, max_port)
|
|
||||||
return '%s:%s' % (min_port, max_port)
|
|
||||||
|
|
||||||
def _validate_fw_parameters(self, context, fw, fw_tenant_id):
|
|
||||||
if 'firewall_policy_id' not in fw:
|
|
||||||
return
|
|
||||||
fwp_id = fw['firewall_policy_id']
|
|
||||||
fwp = self._get_firewall_policy(context, fwp_id)
|
|
||||||
if fw_tenant_id != fwp['tenant_id'] and not fwp['shared']:
|
|
||||||
raise f_exc.FirewallPolicyConflict(firewall_policy_id=fwp_id)
|
|
||||||
|
|
||||||
def _validate_fwr_src_dst_ip_version(self, fwr):
|
|
||||||
src_version = dst_version = None
|
|
||||||
if fwr.get('source_ip_address', None):
|
|
||||||
src_version = netaddr.IPNetwork(fwr['source_ip_address']).version
|
|
||||||
if fwr.get('destination_ip_address', None):
|
|
||||||
dst_version = netaddr.IPNetwork(
|
|
||||||
fwr['destination_ip_address']).version
|
|
||||||
rule_ip_version = fwr.get('ip_version', None)
|
|
||||||
if ((src_version and src_version != rule_ip_version) or
|
|
||||||
(dst_version and dst_version != rule_ip_version)):
|
|
||||||
raise f_exc.FirewallIpAddressConflict()
|
|
||||||
|
|
||||||
def _validate_fwr_port_range(self, min_port, max_port):
|
|
||||||
if int(min_port) > int(max_port):
|
|
||||||
port_range = '%s:%s' % (min_port, max_port)
|
|
||||||
raise f_exc.FirewallRuleInvalidPortValue(port=port_range)
|
|
||||||
|
|
||||||
def _validate_fwr_protocol_parameters(self, fwr):
|
|
||||||
protocol = fwr.get('protocol', None)
|
|
||||||
if protocol not in (nl_constants.PROTO_NAME_TCP,
|
|
||||||
nl_constants.PROTO_NAME_UDP):
|
|
||||||
if (fwr.get('source_port', None) or
|
|
||||||
fwr.get('destination_port', None)):
|
|
||||||
raise f_exc.FirewallRuleInvalidICMPParameter(
|
|
||||||
param="Source, destination port")
|
|
||||||
|
|
||||||
def create_firewall(self, context, firewall, status=None):
|
|
||||||
LOG.debug("create_firewall() called")
|
|
||||||
fw = firewall['firewall']
|
|
||||||
tenant_id = fw['tenant_id']
|
|
||||||
# distributed routers may required a more complex state machine;
|
|
||||||
# the introduction of a new 'CREATED' state allows this, whilst
|
|
||||||
# keeping a backward compatible behavior of the logical resource.
|
|
||||||
if not status:
|
|
||||||
status = (nl_constants.CREATED if cfg.CONF.router_distributed
|
|
||||||
else nl_constants.PENDING_CREATE)
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
self._validate_fw_parameters(context, fw, tenant_id)
|
|
||||||
firewall_db = Firewall(
|
|
||||||
id=uuidutils.generate_uuid(),
|
|
||||||
tenant_id=tenant_id,
|
|
||||||
name=fw['name'],
|
|
||||||
description=fw['description'],
|
|
||||||
firewall_policy_id=fw['firewall_policy_id'],
|
|
||||||
admin_state_up=fw['admin_state_up'],
|
|
||||||
status=status)
|
|
||||||
context.session.add(firewall_db)
|
|
||||||
return self._make_firewall_dict(firewall_db)
|
|
||||||
|
|
||||||
def update_firewall(self, context, id, firewall):
|
|
||||||
LOG.debug("update_firewall() called")
|
|
||||||
fw = firewall['firewall']
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fw_db = self.get_firewall(context, id)
|
|
||||||
self._validate_fw_parameters(context, fw, fw_db['tenant_id'])
|
|
||||||
count = context.session.query(Firewall).filter_by(id=id).update(fw)
|
|
||||||
if not count:
|
|
||||||
raise f_exc.FirewallNotFound(firewall_id=id)
|
|
||||||
return self.get_firewall(context, id)
|
|
||||||
|
|
||||||
def update_firewall_status(self, context, id, status, not_in=None):
|
|
||||||
"""Conditionally update firewall status.
|
|
||||||
|
|
||||||
Status transition is performed only if firewall is not in the specified
|
|
||||||
states as defined by 'not_in' list.
|
|
||||||
"""
|
|
||||||
# filter in_ wants iterable objects, None isn't.
|
|
||||||
not_in = not_in or []
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
return (context.session.query(Firewall).
|
|
||||||
filter(Firewall.id == id).
|
|
||||||
filter(~Firewall.status.in_(not_in)).
|
|
||||||
update({'status': status}, synchronize_session=False))
|
|
||||||
|
|
||||||
def delete_firewall(self, context, id):
|
|
||||||
LOG.debug("delete_firewall() called")
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
# Note: Plugin should ensure that it's okay to delete if the
|
|
||||||
# firewall is active
|
|
||||||
count = context.session.query(Firewall).filter_by(id=id).delete()
|
|
||||||
if not count:
|
|
||||||
raise f_exc.FirewallNotFound(firewall_id=id)
|
|
||||||
|
|
||||||
def get_firewall(self, context, id, fields=None):
|
|
||||||
LOG.debug("get_firewall() called")
|
|
||||||
fw = self._get_firewall(context, id)
|
|
||||||
return self._make_firewall_dict(fw, fields)
|
|
||||||
|
|
||||||
def get_firewalls(self, context, filters=None, fields=None):
|
|
||||||
LOG.debug("get_firewalls() called")
|
|
||||||
return self._get_collection(context, Firewall,
|
|
||||||
self._make_firewall_dict,
|
|
||||||
filters=filters, fields=fields)
|
|
||||||
|
|
||||||
def get_firewalls_count(self, context, filters=None):
|
|
||||||
LOG.debug("get_firewalls_count() called")
|
|
||||||
return self._get_collection_count(context, Firewall,
|
|
||||||
filters=filters)
|
|
||||||
|
|
||||||
def create_firewall_policy(self, context, firewall_policy):
|
|
||||||
LOG.debug("create_firewall_policy() called")
|
|
||||||
fwp = firewall_policy['firewall_policy']
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fwp_db = FirewallPolicy(id=uuidutils.generate_uuid(),
|
|
||||||
tenant_id=fwp['tenant_id'],
|
|
||||||
name=fwp['name'],
|
|
||||||
description=fwp['description'],
|
|
||||||
shared=fwp['shared'])
|
|
||||||
context.session.add(fwp_db)
|
|
||||||
self._set_rules_for_policy(context, fwp_db, fwp)
|
|
||||||
fwp_db.audited = fwp['audited']
|
|
||||||
return self._make_firewall_policy_dict(fwp_db)
|
|
||||||
|
|
||||||
def update_firewall_policy(self, context, id, firewall_policy):
|
|
||||||
LOG.debug("update_firewall_policy() called")
|
|
||||||
fwp = firewall_policy['firewall_policy']
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fwp_db = self._get_firewall_policy(context, id)
|
|
||||||
# check tenant ids are same for fw and fwp or not
|
|
||||||
if not fwp.get('shared', True) and fwp_db.firewalls:
|
|
||||||
for fw in fwp_db['firewalls']:
|
|
||||||
if fwp_db['tenant_id'] != fw['tenant_id']:
|
|
||||||
raise f_exc.FirewallPolicyInUse(
|
|
||||||
firewall_policy_id=id)
|
|
||||||
# check any existing rules are not shared
|
|
||||||
if 'shared' in fwp and 'firewall_rules' not in fwp:
|
|
||||||
self._check_unshared_rules_for_policy(fwp_db, fwp)
|
|
||||||
elif 'firewall_rules' in fwp:
|
|
||||||
self._set_rules_for_policy(context, fwp_db, fwp)
|
|
||||||
del fwp['firewall_rules']
|
|
||||||
if 'audited' not in fwp:
|
|
||||||
fwp['audited'] = False
|
|
||||||
fwp_db.update(fwp)
|
|
||||||
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 = self._get_firewall_policy(context, id)
|
|
||||||
# Ensure that the firewall_policy is not
|
|
||||||
# being used
|
|
||||||
qry = context.session.query(Firewall)
|
|
||||||
if qry.filter_by(firewall_policy_id=id).first():
|
|
||||||
raise f_exc.FirewallPolicyInUse(firewall_policy_id=id)
|
|
||||||
else:
|
|
||||||
context.session.delete(fwp)
|
|
||||||
|
|
||||||
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 get_firewalls_policies_count(self, context, filters=None):
|
|
||||||
LOG.debug("get_firewall_policies_count() called")
|
|
||||||
return self._get_collection_count(context, FirewallPolicy,
|
|
||||||
filters=filters)
|
|
||||||
|
|
||||||
def create_firewall_rule(self, context, firewall_rule):
|
|
||||||
LOG.debug("create_firewall_rule() called")
|
|
||||||
fwr = firewall_rule['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
|
|
||||||
fwr['destination_port']):
|
|
||||||
raise f_exc.FirewallRuleWithPortWithoutProtocolInvalid()
|
|
||||||
src_port_min, src_port_max = self._get_min_max_ports_from_range(
|
|
||||||
fwr['source_port'])
|
|
||||||
dst_port_min, dst_port_max = self._get_min_max_ports_from_range(
|
|
||||||
fwr['destination_port'])
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fwr_db = FirewallRule(
|
|
||||||
id=uuidutils.generate_uuid(),
|
|
||||||
tenant_id=fwr['tenant_id'],
|
|
||||||
name=fwr['name'],
|
|
||||||
description=fwr['description'],
|
|
||||||
shared=fwr['shared'],
|
|
||||||
protocol=fwr['protocol'],
|
|
||||||
ip_version=fwr['ip_version'],
|
|
||||||
source_ip_address=fwr['source_ip_address'],
|
|
||||||
destination_ip_address=fwr['destination_ip_address'],
|
|
||||||
source_port_range_min=src_port_min,
|
|
||||||
source_port_range_max=src_port_max,
|
|
||||||
destination_port_range_min=dst_port_min,
|
|
||||||
destination_port_range_max=dst_port_max,
|
|
||||||
action=fwr['action'],
|
|
||||||
enabled=fwr['enabled'])
|
|
||||||
context.session.add(fwr_db)
|
|
||||||
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']
|
|
||||||
self._validate_fwr_protocol_parameters(fwr)
|
|
||||||
self._validate_fwr_src_dst_ip_version(fwr)
|
|
||||||
fwr_db = self._get_firewall_rule(context, id)
|
|
||||||
if fwr_db.firewall_policy_id:
|
|
||||||
fwp_db = self._get_firewall_policy(context,
|
|
||||||
fwr_db.firewall_policy_id)
|
|
||||||
if 'shared' in fwr and not fwr['shared']:
|
|
||||||
if fwr_db['tenant_id'] != fwp_db['tenant_id']:
|
|
||||||
raise f_exc.FirewallRuleInUse(firewall_rule_id=id)
|
|
||||||
if 'source_port' in fwr:
|
|
||||||
src_port_min, src_port_max = self._get_min_max_ports_from_range(
|
|
||||||
fwr['source_port'])
|
|
||||||
fwr['source_port_range_min'] = src_port_min
|
|
||||||
fwr['source_port_range_max'] = src_port_max
|
|
||||||
del fwr['source_port']
|
|
||||||
if 'destination_port' in fwr:
|
|
||||||
dst_port_min, dst_port_max = self._get_min_max_ports_from_range(
|
|
||||||
fwr['destination_port'])
|
|
||||||
fwr['destination_port_range_min'] = dst_port_min
|
|
||||||
fwr['destination_port_range_max'] = dst_port_max
|
|
||||||
del fwr['destination_port']
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
protocol = fwr.get('protocol', fwr_db['protocol'])
|
|
||||||
if not protocol:
|
|
||||||
sport = fwr.get('source_port_range_min',
|
|
||||||
fwr_db['source_port_range_min'])
|
|
||||||
dport = fwr.get('destination_port_range_min',
|
|
||||||
fwr_db['destination_port_range_min'])
|
|
||||||
if sport or dport:
|
|
||||||
raise f_exc.FirewallRuleWithPortWithoutProtocolInvalid()
|
|
||||||
fwr_db.update(fwr)
|
|
||||||
if fwr_db.firewall_policy_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)
|
|
||||||
if fwr.firewall_policy_id:
|
|
||||||
raise f_exc.FirewallRuleInUse(firewall_rule_id=id)
|
|
||||||
context.session.delete(fwr)
|
|
||||||
|
|
||||||
def get_firewall_rule(self, context, id, fields=None):
|
|
||||||
LOG.debug("get_firewall_rule() called")
|
|
||||||
fwr = self._get_firewall_rule(context, id)
|
|
||||||
return self._make_firewall_rule_dict(fwr, fields)
|
|
||||||
|
|
||||||
def get_firewall_rules(self, context, filters=None, fields=None):
|
|
||||||
LOG.debug("get_firewall_rules() called")
|
|
||||||
return self._get_collection(context, FirewallRule,
|
|
||||||
self._make_firewall_rule_dict,
|
|
||||||
filters=filters, fields=fields)
|
|
||||||
|
|
||||||
def get_firewalls_rules_count(self, context, filters=None):
|
|
||||||
LOG.debug("get_firewall_rules_count() called")
|
|
||||||
return self._get_collection_count(context, FirewallRule,
|
|
||||||
filters=filters)
|
|
||||||
|
|
||||||
def _validate_insert_remove_rule_request(self, id, rule_info):
|
|
||||||
if not rule_info or 'firewall_rule_id' not in rule_info:
|
|
||||||
raise f_exc.FirewallRuleInfoMissing()
|
|
||||||
|
|
||||||
def insert_rule(self, context, id, rule_info):
|
|
||||||
LOG.debug("insert_rule() called")
|
|
||||||
self._validate_insert_remove_rule_request(id, rule_info)
|
|
||||||
firewall_rule_id = rule_info['firewall_rule_id']
|
|
||||||
insert_before = True
|
|
||||||
ref_firewall_rule_id = None
|
|
||||||
if not firewall_rule_id:
|
|
||||||
raise f_exc.FirewallRuleNotFound(firewall_rule_id=None)
|
|
||||||
if 'insert_before' in rule_info:
|
|
||||||
ref_firewall_rule_id = rule_info['insert_before']
|
|
||||||
if not ref_firewall_rule_id and 'insert_after' in rule_info:
|
|
||||||
# If insert_before is set, we will ignore insert_after.
|
|
||||||
ref_firewall_rule_id = rule_info['insert_after']
|
|
||||||
insert_before = False
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fwr_db = self._get_firewall_rule(context, firewall_rule_id)
|
|
||||||
fwp_db = self._get_firewall_policy(context, id)
|
|
||||||
if fwr_db.firewall_policy_id:
|
|
||||||
raise f_exc.FirewallRuleInUse(firewall_rule_id=fwr_db['id'])
|
|
||||||
self._check_firewall_rule_conflict(fwr_db, fwp_db)
|
|
||||||
if ref_firewall_rule_id:
|
|
||||||
# If reference_firewall_rule_id is set, the new rule
|
|
||||||
# is inserted depending on the value of insert_before.
|
|
||||||
# If insert_before is set, the new rule is inserted before
|
|
||||||
# reference_firewall_rule_id, and if it is not set the new
|
|
||||||
# rule is inserted after reference_firewall_rule_id.
|
|
||||||
ref_fwr_db = self._get_firewall_rule(
|
|
||||||
context, ref_firewall_rule_id)
|
|
||||||
if ref_fwr_db.firewall_policy_id != id:
|
|
||||||
raise f_exc.FirewallRuleNotAssociatedWithPolicy(
|
|
||||||
firewall_rule_id=ref_fwr_db['id'],
|
|
||||||
firewall_policy_id=id)
|
|
||||||
if insert_before:
|
|
||||||
position = ref_fwr_db.position
|
|
||||||
else:
|
|
||||||
position = ref_fwr_db.position + 1
|
|
||||||
else:
|
|
||||||
# If reference_firewall_rule_id is not set, it is assumed
|
|
||||||
# that the new rule needs to be inserted at the top.
|
|
||||||
# insert_before field is ignored.
|
|
||||||
# So default insertion is always at the top.
|
|
||||||
# Also note that position numbering starts at 1.
|
|
||||||
position = 1
|
|
||||||
return self._process_rule_for_policy(context, id, fwr_db,
|
|
||||||
position)
|
|
||||||
|
|
||||||
def remove_rule(self, context, id, rule_info):
|
|
||||||
LOG.debug("remove_rule() called")
|
|
||||||
self._validate_insert_remove_rule_request(id, rule_info)
|
|
||||||
firewall_rule_id = rule_info['firewall_rule_id']
|
|
||||||
if not firewall_rule_id:
|
|
||||||
raise f_exc.FirewallRuleNotFound(firewall_rule_id=None)
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fwr_db = self._get_firewall_rule(context, firewall_rule_id)
|
|
||||||
if fwr_db.firewall_policy_id != id:
|
|
||||||
raise f_exc.FirewallRuleNotAssociatedWithPolicy(
|
|
||||||
firewall_rule_id=fwr_db['id'],
|
|
||||||
firewall_policy_id=id)
|
|
||||||
return self._process_rule_for_policy(context, id, fwr_db, None)
|
|
||||||
|
|
||||||
def get_firewall_tenant_ids_on_host(self, context, host):
|
|
||||||
query = context.session.query(Firewall.tenant_id)
|
|
||||||
query = query.join(fw_r_ins_db.FirewallRouterAssociation)
|
|
||||||
query = query.join(l3agent_model.RouterL3AgentBinding,
|
|
||||||
l3agent_model.RouterL3AgentBinding.router_id ==
|
|
||||||
fw_r_ins_db.FirewallRouterAssociation.router_id)
|
|
||||||
query = query.join(agent_model.Agent)
|
|
||||||
query = query.filter(agent_model.Agent.host == host)
|
|
||||||
query = query.distinct()
|
|
||||||
return [item[0] for item in query]
|
|
||||||
|
|
||||||
|
|
||||||
def migration_callback(resource, event, trigger, **kwargs):
|
|
||||||
context = kwargs['context']
|
|
||||||
router = kwargs['router']
|
|
||||||
fw_plugin = directory.get_plugin(fwaas_constants.FIREWALL)
|
|
||||||
if fw_plugin:
|
|
||||||
tenant_firewalls = fw_plugin.get_firewalls(
|
|
||||||
context, filters={'tenant_id': [router['tenant_id']]})
|
|
||||||
if tenant_firewalls:
|
|
||||||
raise l3.RouterInUse(router_id=router['id'])
|
|
||||||
|
|
||||||
|
|
||||||
def subscribe():
|
|
||||||
registry.subscribe(
|
|
||||||
migration_callback, resources.ROUTER, events.BEFORE_UPDATE)
|
|
||||||
|
|
||||||
# NOTE(armax): multiple FW service plugins (potentially out of tree) may
|
|
||||||
# inherit from firewall_db and may need the callbacks to be processed. Having
|
|
||||||
# an implicit subscription (through the module import) preserves the existing
|
|
||||||
# behavior, and at the same time it avoids fixing it manually in each and
|
|
||||||
# every fw plugin out there. That said, The subscription is also made
|
|
||||||
# explicitly in the reference fw plugin. The subscription operation is
|
|
||||||
# idempotent so there is no harm in registering the same callback multiple
|
|
||||||
# times.
|
|
||||||
subscribe()
|
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
# Copyright 2015 Cisco Systems Inc.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from neutron_lib.db import model_base
|
|
||||||
from neutron_lib.exceptions import firewall_v1 as fwrtrins
|
|
||||||
from oslo_log import helpers as log_helpers
|
|
||||||
from oslo_log import log as logging
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class FirewallRouterAssociation(model_base.BASEV2):
|
|
||||||
|
|
||||||
"""Tracks FW Router Association"""
|
|
||||||
|
|
||||||
__tablename__ = 'firewall_router_associations'
|
|
||||||
|
|
||||||
fw_id = sa.Column(sa.String(36),
|
|
||||||
sa.ForeignKey('firewalls.id', ondelete="CASCADE"),
|
|
||||||
primary_key=True)
|
|
||||||
router_id = sa.Column(sa.String(36),
|
|
||||||
sa.ForeignKey('routers.id', ondelete="CASCADE"),
|
|
||||||
primary_key=True)
|
|
||||||
|
|
||||||
|
|
||||||
class FirewallRouterInsertionDbMixin(object):
|
|
||||||
|
|
||||||
"""Access methods for the firewall_router_associations table."""
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def set_routers_for_firewall(self, context, fw):
|
|
||||||
"""Sets the routers associated with the fw."""
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
for r_id in fw['router_ids']:
|
|
||||||
fw_rtr_db = FirewallRouterAssociation(fw_id=fw['fw_id'],
|
|
||||||
router_id=r_id)
|
|
||||||
context.session.add(fw_rtr_db)
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def get_firewall_routers(self, context, fwid):
|
|
||||||
"""Gets all routers associated with a firewall."""
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fw_rtr_qry = context.session.query(
|
|
||||||
FirewallRouterAssociation.router_id)
|
|
||||||
fw_rtr_rows = fw_rtr_qry.filter_by(fw_id=fwid)
|
|
||||||
fw_rtrs = [entry.router_id for entry in fw_rtr_rows]
|
|
||||||
LOG.debug("get_firewall_routers(): fw_rtrs: %s", fw_rtrs)
|
|
||||||
return fw_rtrs
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def validate_firewall_routers_not_in_use(
|
|
||||||
self, context, router_ids, fwid=None):
|
|
||||||
"""Validate if router-ids not associated with any firewall.
|
|
||||||
|
|
||||||
If any of the router-ids in the list is already associated with
|
|
||||||
a firewall, raise an exception else just return.
|
|
||||||
"""
|
|
||||||
fw_rtr_qry = context.session.query(FirewallRouterAssociation.router_id)
|
|
||||||
fw_rtrs = fw_rtr_qry.filter(
|
|
||||||
FirewallRouterAssociation.router_id.in_(router_ids),
|
|
||||||
FirewallRouterAssociation.fw_id != fwid).all()
|
|
||||||
if fw_rtrs:
|
|
||||||
router_ids = [entry.router_id for entry in fw_rtrs]
|
|
||||||
raise fwrtrins.FirewallRouterInUse(router_ids=router_ids)
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def update_firewall_routers(self, context, fw):
|
|
||||||
"""Update the firewall with new routers.
|
|
||||||
|
|
||||||
This involves removing existing router associations and replacing
|
|
||||||
it with the new router associations provided in the update method.
|
|
||||||
"""
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fw_rtr_qry = context.session.query(FirewallRouterAssociation)
|
|
||||||
fw_rtr_qry.filter_by(fw_id=fw['fw_id']).delete()
|
|
||||||
if fw['router_ids']:
|
|
||||||
self.set_routers_for_firewall(context, fw)
|
|
||||||
|
|
||||||
# TODO(sridar): Investigate potential corner case if rpc failure
|
|
||||||
# happens on PENDING_UPDATE and agent did not restart. Evaluate
|
|
||||||
# complexity vs benefit of holding on to old entries until ack
|
|
||||||
# from agent.
|
|
||||||
|
|
||||||
return fw
|
|
@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
from neutron_lib.db import model_base
|
from neutron_lib.db import model_base
|
||||||
|
|
||||||
from neutron_fwaas.db.firewall import firewall_db # noqa
|
|
||||||
from neutron_fwaas.db.firewall import firewall_router_insertion_db # noqa
|
|
||||||
from neutron_fwaas.db.firewall.v2 import firewall_db_v2 # noqa
|
from neutron_fwaas.db.firewall.v2 import firewall_db_v2 # noqa
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from neutron_fwaas.policies import firewall
|
|
||||||
from neutron_fwaas.policies import firewall_group
|
from neutron_fwaas.policies import firewall_group
|
||||||
from neutron_fwaas.policies import firewall_policy
|
from neutron_fwaas.policies import firewall_policy
|
||||||
from neutron_fwaas.policies import firewall_rule
|
from neutron_fwaas.policies import firewall_rule
|
||||||
@ -20,7 +19,6 @@ from neutron_fwaas.policies import firewall_rule
|
|||||||
|
|
||||||
def list_rules():
|
def list_rules():
|
||||||
return itertools.chain(
|
return itertools.chain(
|
||||||
firewall.list_rules(),
|
|
||||||
firewall_group.list_rules(),
|
firewall_group.list_rules(),
|
||||||
firewall_policy.list_rules(),
|
firewall_policy.list_rules(),
|
||||||
firewall_rule.list_rules(),
|
firewall_rule.list_rules(),
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
# 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 oslo_policy import policy
|
|
||||||
|
|
||||||
from neutron_fwaas.policies import base
|
|
||||||
|
|
||||||
|
|
||||||
rules = [
|
|
||||||
policy.RuleDefault(
|
|
||||||
'shared_firewalls',
|
|
||||||
'field:firewalls:shared=True',
|
|
||||||
'(FWaaS v1) Definition of shared firewalls'
|
|
||||||
),
|
|
||||||
|
|
||||||
policy.DocumentedRuleDefault(
|
|
||||||
'create_firewall',
|
|
||||||
base.RULE_ANY,
|
|
||||||
'(FWaaS v1) Create a firewall',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'method': 'POST',
|
|
||||||
'path': '/fw/firewalls',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
policy.DocumentedRuleDefault(
|
|
||||||
'update_firewall',
|
|
||||||
base.RULE_ADMIN_OR_OWNER,
|
|
||||||
'(FWaaS v1) Update a firewall',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'method': 'PUT',
|
|
||||||
'path': '/fw/firewalls/{id}',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
policy.DocumentedRuleDefault(
|
|
||||||
'delete_firewall',
|
|
||||||
base.RULE_ADMIN_OR_OWNER,
|
|
||||||
'(FWaaS v1) Delete a firewall',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'method': 'DELETE',
|
|
||||||
'path': '/fw/firewalls/{id}',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
|
|
||||||
policy.DocumentedRuleDefault(
|
|
||||||
'create_firewall:shared',
|
|
||||||
base.RULE_ADMIN_ONLY,
|
|
||||||
'(FWaaS v1) Create a shared firewall',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'method': 'POST',
|
|
||||||
'path': '/fw/firewalls',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
policy.DocumentedRuleDefault(
|
|
||||||
'update_firewall:shared',
|
|
||||||
base.RULE_ADMIN_ONLY,
|
|
||||||
'(FWaaS v1) Update ``shared`` attribute of a firewall',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'method': 'PUT',
|
|
||||||
'path': '/fw/firewalls/{id}',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
# TODO(amotoki): Drop this rule as it has no effect.
|
|
||||||
policy.DocumentedRuleDefault(
|
|
||||||
'delete_firewall:shared',
|
|
||||||
base.RULE_ADMIN_ONLY,
|
|
||||||
'(FWaaS v1) Delete a shared firewall',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'method': 'DELETE',
|
|
||||||
'path': '/fw/firewalls/{id}',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
|
|
||||||
policy.DocumentedRuleDefault(
|
|
||||||
'get_firewall',
|
|
||||||
'rule:admin_or_owner or rule:shared_firewalls',
|
|
||||||
'(FWaaS v1) Get firewalls',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'method': 'GET',
|
|
||||||
'path': '/fw/firewalls',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'method': 'GET',
|
|
||||||
'path': '/fw/firewalls/{id}',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def list_rules():
|
|
||||||
return rules
|
|
@ -1,444 +0,0 @@
|
|||||||
# Copyright 2013 Big Switch Networks, Inc.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from neutron import service
|
|
||||||
from neutron_lib.api.definitions import firewall as fw_ext
|
|
||||||
from neutron_lib.api import extensions
|
|
||||||
from neutron_lib import constants as nl_constants
|
|
||||||
from neutron_lib import context as neutron_context
|
|
||||||
from neutron_lib.exceptions import firewall_v1 as f_exc
|
|
||||||
from neutron_lib.plugins import constants as plugin_constants
|
|
||||||
from neutron_lib.plugins import directory
|
|
||||||
from neutron_lib import rpc as n_rpc
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import log as logging
|
|
||||||
import oslo_messaging
|
|
||||||
|
|
||||||
from neutron_fwaas.common import fwaas_constants as f_const
|
|
||||||
from neutron_fwaas.db.firewall import firewall_db
|
|
||||||
from neutron_fwaas.db.firewall import firewall_router_insertion_db
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class FirewallCallbacks(object):
|
|
||||||
target = oslo_messaging.Target(version='1.0')
|
|
||||||
|
|
||||||
def __init__(self, plugin):
|
|
||||||
super(FirewallCallbacks, self).__init__()
|
|
||||||
self.plugin = plugin
|
|
||||||
|
|
||||||
def set_firewall_status(self, context, firewall_id, status, **kwargs):
|
|
||||||
"""Agent uses this to set a firewall's status."""
|
|
||||||
LOG.debug("Setting firewall %s to status: %s", firewall_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 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_status(
|
|
||||||
context, firewall_id, to_update,
|
|
||||||
not_in=(nl_constants.PENDING_DELETE,))
|
|
||||||
if updated:
|
|
||||||
LOG.debug("firewall %s status set: %s", firewall_id, to_update)
|
|
||||||
return updated and to_update != nl_constants.ERROR
|
|
||||||
|
|
||||||
def firewall_deleted(self, context, firewall_id, **kwargs):
|
|
||||||
"""Agent uses this to indicate firewall is deleted."""
|
|
||||||
LOG.debug("firewall_deleted() called")
|
|
||||||
try:
|
|
||||||
with context.session.begin(subtransactions=True):
|
|
||||||
fw_db = self.plugin._get_firewall(context, firewall_id)
|
|
||||||
# allow to delete firewalls in ERROR state
|
|
||||||
if fw_db.status in (nl_constants.PENDING_DELETE,
|
|
||||||
nl_constants.ERROR):
|
|
||||||
self.plugin.delete_db_firewall_object(context, firewall_id)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
LOG.warning('Firewall %(fw)s unexpectedly deleted by '
|
|
||||||
'agent, status was %(status)s',
|
|
||||||
{'fw': firewall_id, 'status': fw_db.status})
|
|
||||||
fw_db.update({"status": nl_constants.ERROR})
|
|
||||||
return False
|
|
||||||
except f_exc.FirewallNotFound:
|
|
||||||
LOG.info('Firewall %s already deleted', firewall_id)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_firewalls_for_tenant(self, context, **kwargs):
|
|
||||||
"""Agent uses this to get all firewalls and rules for a tenant."""
|
|
||||||
LOG.debug("get_firewalls_for_tenant() called")
|
|
||||||
fw_list = []
|
|
||||||
for fw in self.plugin.get_firewalls(context):
|
|
||||||
fw_with_rules = self.plugin._make_firewall_dict_with_rules(
|
|
||||||
context, fw['id'])
|
|
||||||
if fw['status'] == nl_constants.PENDING_DELETE:
|
|
||||||
fw_with_rules['add-router-ids'] = []
|
|
||||||
fw_with_rules['del-router-ids'] = fw['router_ids']
|
|
||||||
else:
|
|
||||||
fw_with_rules['add-router-ids'] = fw['router_ids']
|
|
||||||
fw_with_rules['del-router-ids'] = []
|
|
||||||
fw_list.append(fw_with_rules)
|
|
||||||
return fw_list
|
|
||||||
|
|
||||||
def get_tenants_with_firewalls(self, context, **kwargs):
|
|
||||||
"""Agent uses this to get all tenants that have firewalls."""
|
|
||||||
LOG.debug("get_tenants_with_firewalls() called")
|
|
||||||
host = kwargs['host']
|
|
||||||
ctx = neutron_context.get_admin_context()
|
|
||||||
tenant_ids = self.plugin.get_firewall_tenant_ids_on_host(ctx, host)
|
|
||||||
return tenant_ids
|
|
||||||
|
|
||||||
|
|
||||||
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 _prepare_rpc_client(self, host=None):
|
|
||||||
if host:
|
|
||||||
return self.client.prepare(server=host)
|
|
||||||
else:
|
|
||||||
# historical behaviour (RPC broadcast)
|
|
||||||
return self.client.prepare(fanout=True)
|
|
||||||
|
|
||||||
def create_firewall(self, context, firewall, host=None):
|
|
||||||
cctxt = self._prepare_rpc_client(host)
|
|
||||||
# TODO(blallau) host param is not used on agent side (to be removed)
|
|
||||||
cctxt.cast(context, 'create_firewall', firewall=firewall,
|
|
||||||
host=self.host)
|
|
||||||
|
|
||||||
def update_firewall(self, context, firewall, host=None):
|
|
||||||
cctxt = self._prepare_rpc_client(host)
|
|
||||||
# TODO(blallau) host param is not used on agent side (to be removed)
|
|
||||||
cctxt.cast(context, 'update_firewall', firewall=firewall,
|
|
||||||
host=self.host)
|
|
||||||
|
|
||||||
def delete_firewall(self, context, firewall, host=None):
|
|
||||||
cctxt = self._prepare_rpc_client(host)
|
|
||||||
# TODO(blallau) host param is not used on agent side (to be removed)
|
|
||||||
cctxt.cast(context, 'delete_firewall', firewall=firewall,
|
|
||||||
host=self.host)
|
|
||||||
|
|
||||||
|
|
||||||
class FirewallPlugin(
|
|
||||||
firewall_db.Firewall_db_mixin,
|
|
||||||
firewall_router_insertion_db.FirewallRouterInsertionDbMixin):
|
|
||||||
|
|
||||||
"""Implementation of the Neutron Firewall Service Plugin.
|
|
||||||
|
|
||||||
This class manages the workflow of FWaaS request/response.
|
|
||||||
Most DB related works are implemented in class
|
|
||||||
firewall_db.Firewall_db_mixin.
|
|
||||||
"""
|
|
||||||
supported_extension_aliases = ["fwaas", "fwaasrouterinsertion"]
|
|
||||||
path_prefix = fw_ext.API_PREFIX
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""Do the initialization for the firewall service plugin here."""
|
|
||||||
|
|
||||||
self.agent_rpc = FirewallAgentApi(
|
|
||||||
f_const.FW_AGENT,
|
|
||||||
cfg.CONF.host
|
|
||||||
)
|
|
||||||
firewall_db.subscribe()
|
|
||||||
|
|
||||||
rpc_worker = service.RpcWorker([self], worker_process_count=0)
|
|
||||||
self.add_worker(rpc_worker)
|
|
||||||
|
|
||||||
def start_rpc_listeners(self):
|
|
||||||
self.endpoints = [FirewallCallbacks(self)]
|
|
||||||
|
|
||||||
self.conn = n_rpc.Connection()
|
|
||||||
self.conn.create_consumer(
|
|
||||||
f_const.FIREWALL_PLUGIN, self.endpoints, fanout=False)
|
|
||||||
return self.conn.consume_in_threads()
|
|
||||||
|
|
||||||
def _get_hosts_to_notify(self, context, router_ids):
|
|
||||||
"""Returns all hosts to send notification about firewall update"""
|
|
||||||
l3_plugin = directory.get_plugin(plugin_constants.L3)
|
|
||||||
no_broadcast = (
|
|
||||||
extensions.is_extension_supported(
|
|
||||||
l3_plugin, nl_constants.L3_AGENT_SCHEDULER_EXT_ALIAS) and
|
|
||||||
getattr(l3_plugin, 'get_l3_agents_hosting_routers', False))
|
|
||||||
if no_broadcast:
|
|
||||||
agents = l3_plugin.get_l3_agents_hosting_routers(
|
|
||||||
context, router_ids, admin_state_up=True, active=True)
|
|
||||||
return [a.host for a in agents]
|
|
||||||
|
|
||||||
# NOTE(blallau): default: FirewallAgentAPI performs RPC broadcast
|
|
||||||
return [None]
|
|
||||||
|
|
||||||
def _rpc_update_firewall(self, context, firewall_id):
|
|
||||||
status_update = {"firewall": {"status": nl_constants.PENDING_UPDATE}}
|
|
||||||
super(FirewallPlugin, self).update_firewall(context, firewall_id,
|
|
||||||
status_update)
|
|
||||||
fw_with_rules = self._make_firewall_dict_with_rules(context,
|
|
||||||
firewall_id)
|
|
||||||
# this is triggered on an update to fw rule or policy, no
|
|
||||||
# change in associated routers.
|
|
||||||
fw_update_rtrs = self.get_firewall_routers(context, firewall_id)
|
|
||||||
fw_with_rules['add-router-ids'] = fw_update_rtrs
|
|
||||||
fw_with_rules['del-router-ids'] = []
|
|
||||||
|
|
||||||
hosts = self._get_hosts_to_notify(context, fw_update_rtrs)
|
|
||||||
for host in hosts:
|
|
||||||
self.agent_rpc.update_firewall(context, fw_with_rules,
|
|
||||||
host=host)
|
|
||||||
|
|
||||||
def _rpc_update_firewall_policy(self, context, firewall_policy_id):
|
|
||||||
firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
|
|
||||||
if firewall_policy:
|
|
||||||
for firewall_id in firewall_policy['firewall_list']:
|
|
||||||
self._rpc_update_firewall(context, firewall_id)
|
|
||||||
|
|
||||||
def _ensure_update_firewall(self, context, firewall_id):
|
|
||||||
fwall = self.get_firewall(context, firewall_id)
|
|
||||||
if fwall['status'] in [nl_constants.PENDING_CREATE,
|
|
||||||
nl_constants.PENDING_UPDATE,
|
|
||||||
nl_constants.PENDING_DELETE]:
|
|
||||||
raise f_exc.FirewallInPendingState(firewall_id=firewall_id,
|
|
||||||
pending_state=fwall['status'])
|
|
||||||
|
|
||||||
def _ensure_update_firewall_policy(self, context, firewall_policy_id):
|
|
||||||
firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
|
|
||||||
if firewall_policy and 'firewall_list' in firewall_policy:
|
|
||||||
for firewall_id in firewall_policy['firewall_list']:
|
|
||||||
self._ensure_update_firewall(context, firewall_id)
|
|
||||||
|
|
||||||
def _ensure_update_firewall_rule(self, context, firewall_rule_id):
|
|
||||||
fw_rule = self.get_firewall_rule(context, firewall_rule_id)
|
|
||||||
if 'firewall_policy_id' in fw_rule and fw_rule['firewall_policy_id']:
|
|
||||||
self._ensure_update_firewall_policy(context,
|
|
||||||
fw_rule['firewall_policy_id'])
|
|
||||||
|
|
||||||
def _get_routers_for_create_firewall(self, tenant_id, context, firewall):
|
|
||||||
# pop router_id as this goes in the router association db
|
|
||||||
# and not firewall db
|
|
||||||
router_ids = firewall['firewall'].pop('router_ids', None)
|
|
||||||
if router_ids == nl_constants.ATTR_NOT_SPECIFIED:
|
|
||||||
# old semantics router-ids keyword not specified pick up
|
|
||||||
# all routers on tenant.
|
|
||||||
l3_plugin = directory.get_plugin(plugin_constants.L3)
|
|
||||||
ctx = neutron_context.get_admin_context()
|
|
||||||
routers = l3_plugin.get_routers(ctx)
|
|
||||||
router_ids = [
|
|
||||||
router['id']
|
|
||||||
for router in routers
|
|
||||||
if router['tenant_id'] == tenant_id]
|
|
||||||
# validation can still fail this if there is another fw
|
|
||||||
# which is associated with one of these routers.
|
|
||||||
self.validate_firewall_routers_not_in_use(context, router_ids)
|
|
||||||
return router_ids
|
|
||||||
else:
|
|
||||||
if not router_ids:
|
|
||||||
# This indicates that user specifies no routers.
|
|
||||||
return []
|
|
||||||
else:
|
|
||||||
# some router(s) provided.
|
|
||||||
self.validate_firewall_routers_not_in_use(context, router_ids)
|
|
||||||
return router_ids
|
|
||||||
|
|
||||||
def create_firewall(self, context, firewall):
|
|
||||||
LOG.debug("create_firewall() called")
|
|
||||||
|
|
||||||
fw_new_rtrs = self._get_routers_for_create_firewall(
|
|
||||||
firewall['firewall']['tenant_id'], context, firewall)
|
|
||||||
|
|
||||||
if not fw_new_rtrs:
|
|
||||||
# no messaging to agent needed, and fw needs to go
|
|
||||||
# to INACTIVE(no associated rtrs) state.
|
|
||||||
status = nl_constants.INACTIVE
|
|
||||||
fw = super(FirewallPlugin, self).create_firewall(
|
|
||||||
context, firewall, status)
|
|
||||||
fw['router_ids'] = []
|
|
||||||
return fw
|
|
||||||
else:
|
|
||||||
fw = super(FirewallPlugin, self).create_firewall(
|
|
||||||
context, firewall)
|
|
||||||
fw['router_ids'] = fw_new_rtrs
|
|
||||||
|
|
||||||
fw_with_rules = (
|
|
||||||
self._make_firewall_dict_with_rules(context, fw['id']))
|
|
||||||
|
|
||||||
fw_with_rtrs = {'fw_id': fw['id'],
|
|
||||||
'router_ids': fw_new_rtrs}
|
|
||||||
self.set_routers_for_firewall(context, fw_with_rtrs)
|
|
||||||
fw_with_rules['add-router-ids'] = fw_new_rtrs
|
|
||||||
fw_with_rules['del-router-ids'] = []
|
|
||||||
|
|
||||||
hosts = self._get_hosts_to_notify(context, fw_new_rtrs)
|
|
||||||
for host in hosts:
|
|
||||||
self.agent_rpc.create_firewall(context, fw_with_rules,
|
|
||||||
host=host)
|
|
||||||
return fw
|
|
||||||
|
|
||||||
def update_firewall(self, context, id, firewall):
|
|
||||||
LOG.debug("update_firewall() called on firewall %s", id)
|
|
||||||
|
|
||||||
self._ensure_update_firewall(context, id)
|
|
||||||
# pop router_id as this goes in the router association db
|
|
||||||
# and not firewall db
|
|
||||||
router_ids = firewall['firewall'].pop('router_ids', None)
|
|
||||||
fw_current_rtrs = fw_new_rtrs = self.get_firewall_routers(
|
|
||||||
context, id)
|
|
||||||
if router_ids is not None:
|
|
||||||
if router_ids == []:
|
|
||||||
# This indicates that user is indicating no routers.
|
|
||||||
fw_new_rtrs = []
|
|
||||||
else:
|
|
||||||
self.validate_firewall_routers_not_in_use(
|
|
||||||
context, router_ids, id)
|
|
||||||
fw_new_rtrs = router_ids
|
|
||||||
self.update_firewall_routers(context, {'fw_id': id,
|
|
||||||
'router_ids': fw_new_rtrs})
|
|
||||||
|
|
||||||
if not fw_new_rtrs and not fw_current_rtrs:
|
|
||||||
# no messaging to agent needed, and we need to continue
|
|
||||||
# in INACTIVE state
|
|
||||||
firewall['firewall']['status'] = nl_constants.INACTIVE
|
|
||||||
fw = super(FirewallPlugin, self).update_firewall(
|
|
||||||
context, id, firewall)
|
|
||||||
fw['router_ids'] = []
|
|
||||||
return fw
|
|
||||||
else:
|
|
||||||
firewall['firewall']['status'] = nl_constants.PENDING_UPDATE
|
|
||||||
fw = super(FirewallPlugin, self).update_firewall(
|
|
||||||
context, id, firewall)
|
|
||||||
fw['router_ids'] = fw_new_rtrs
|
|
||||||
|
|
||||||
fw_with_rules = (
|
|
||||||
self._make_firewall_dict_with_rules(context, fw['id']))
|
|
||||||
|
|
||||||
# determine rtrs to add fw to and del from
|
|
||||||
fw_with_rules['add-router-ids'] = fw_new_rtrs
|
|
||||||
fw_with_rules['del-router-ids'] = list(
|
|
||||||
set(fw_current_rtrs).difference(set(fw_new_rtrs)))
|
|
||||||
|
|
||||||
# last-router drives agent to ack with status to set state to INACTIVE
|
|
||||||
fw_with_rules['last-router'] = not fw_new_rtrs
|
|
||||||
|
|
||||||
LOG.debug("update_firewall %s: Add Routers: %s, Del Routers: %s",
|
|
||||||
fw['id'],
|
|
||||||
fw_with_rules['add-router-ids'],
|
|
||||||
fw_with_rules['del-router-ids'])
|
|
||||||
|
|
||||||
hosts = self._get_hosts_to_notify(context, list(
|
|
||||||
set(fw_new_rtrs).union(set(fw_current_rtrs))))
|
|
||||||
for host in hosts:
|
|
||||||
self.agent_rpc.update_firewall(context, fw_with_rules,
|
|
||||||
host=host)
|
|
||||||
return fw
|
|
||||||
|
|
||||||
def delete_db_firewall_object(self, context, id):
|
|
||||||
super(FirewallPlugin, self).delete_firewall(context, id)
|
|
||||||
|
|
||||||
def delete_firewall(self, context, id):
|
|
||||||
LOG.debug("delete_firewall() called on firewall %s", id)
|
|
||||||
fw_with_rules = (
|
|
||||||
self._make_firewall_dict_with_rules(context, id))
|
|
||||||
fw_delete_rtrs = self.get_firewall_routers(context, id)
|
|
||||||
fw_with_rules['del-router-ids'] = fw_delete_rtrs
|
|
||||||
fw_with_rules['add-router-ids'] = []
|
|
||||||
if not fw_with_rules['del-router-ids']:
|
|
||||||
# no routers to delete on the agent side
|
|
||||||
self.delete_db_firewall_object(context, id)
|
|
||||||
else:
|
|
||||||
status = {"firewall": {"status": nl_constants.PENDING_DELETE}}
|
|
||||||
super(FirewallPlugin, self).update_firewall(context, id, status)
|
|
||||||
# Reflect state change in fw_with_rules
|
|
||||||
fw_with_rules['status'] = status['firewall']['status']
|
|
||||||
hosts = self._get_hosts_to_notify(context, fw_delete_rtrs)
|
|
||||||
if hosts:
|
|
||||||
for host in hosts:
|
|
||||||
self.agent_rpc.delete_firewall(context, fw_with_rules,
|
|
||||||
host=host)
|
|
||||||
else:
|
|
||||||
# NOTE(blallau): we directly delete the firewall
|
|
||||||
# if router is not associated to an agent
|
|
||||||
self.delete_db_firewall_object(context, id)
|
|
||||||
|
|
||||||
def update_firewall_policy(self, context, id, firewall_policy):
|
|
||||||
LOG.debug("update_firewall_policy() called")
|
|
||||||
self._ensure_update_firewall_policy(context, id)
|
|
||||||
fwp = super(FirewallPlugin,
|
|
||||||
self).update_firewall_policy(context, id, firewall_policy)
|
|
||||||
self._rpc_update_firewall_policy(context, id)
|
|
||||||
return fwp
|
|
||||||
|
|
||||||
def update_firewall_rule(self, context, id, firewall_rule):
|
|
||||||
LOG.debug("update_firewall_rule() called")
|
|
||||||
self._ensure_update_firewall_rule(context, id)
|
|
||||||
fwr = super(FirewallPlugin,
|
|
||||||
self).update_firewall_rule(context, id, firewall_rule)
|
|
||||||
firewall_policy_id = fwr['firewall_policy_id']
|
|
||||||
if firewall_policy_id:
|
|
||||||
self._rpc_update_firewall_policy(context, firewall_policy_id)
|
|
||||||
return fwr
|
|
||||||
|
|
||||||
def _notify_firewall_updates(self, context, resource, update_info):
|
|
||||||
notifier = n_rpc.get_notifier('network')
|
|
||||||
notifier.info(context, resource, update_info)
|
|
||||||
|
|
||||||
def insert_rule(self, context, id, rule_info):
|
|
||||||
LOG.debug("insert_rule() called")
|
|
||||||
self._ensure_update_firewall_policy(context, id)
|
|
||||||
fwp = super(FirewallPlugin,
|
|
||||||
self).insert_rule(context, id, rule_info)
|
|
||||||
self._rpc_update_firewall_policy(context, id)
|
|
||||||
resource = 'firewall_policy.update.insert_rule'
|
|
||||||
self._notify_firewall_updates(context, resource, rule_info)
|
|
||||||
return fwp
|
|
||||||
|
|
||||||
def remove_rule(self, context, id, rule_info):
|
|
||||||
LOG.debug("remove_rule() called")
|
|
||||||
self._ensure_update_firewall_policy(context, id)
|
|
||||||
fwp = super(FirewallPlugin,
|
|
||||||
self).remove_rule(context, id, rule_info)
|
|
||||||
self._rpc_update_firewall_policy(context, id)
|
|
||||||
resource = 'firewall_policy.update.remove_rule'
|
|
||||||
self._notify_firewall_updates(context, resource, rule_info)
|
|
||||||
return fwp
|
|
||||||
|
|
||||||
def get_firewalls(self, context, filters=None, fields=None):
|
|
||||||
LOG.debug("fwaas get_firewalls() called")
|
|
||||||
has_id_field = not fields or 'id' in fields
|
|
||||||
if not has_id_field:
|
|
||||||
fields = fields + ['id']
|
|
||||||
fw_list = super(FirewallPlugin, self).get_firewalls(
|
|
||||||
context, filters, fields)
|
|
||||||
if not fields or 'router_ids' in fields:
|
|
||||||
for fw in fw_list:
|
|
||||||
fw['router_ids'] = self.get_firewall_routers(context, fw['id'])
|
|
||||||
if not has_id_field:
|
|
||||||
for fw in fw_list:
|
|
||||||
del fw['id']
|
|
||||||
return fw_list
|
|
||||||
|
|
||||||
def get_firewall(self, context, id, fields=None):
|
|
||||||
LOG.debug("fwaas get_firewall() called")
|
|
||||||
res = super(FirewallPlugin, self).get_firewall(
|
|
||||||
context, id, fields)
|
|
||||||
fw_current_rtrs = self.get_firewall_routers(context, id)
|
|
||||||
res['router_ids'] = fw_current_rtrs
|
|
||||||
return res
|
|
@ -1,431 +0,0 @@
|
|||||||
# Copyright 2013 Dell Inc.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from neutron.agent.linux import iptables_manager
|
|
||||||
from neutron.common import utils
|
|
||||||
from neutron_lib import constants
|
|
||||||
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.service_drivers.agents.drivers import\
|
|
||||||
conntrack_base
|
|
||||||
from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\
|
|
||||||
fwaas_base
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
FWAAS_DRIVER_NAME = 'Fwaas iptables driver'
|
|
||||||
FWAAS_DEFAULT_CHAIN = 'fwaas-default-policy'
|
|
||||||
|
|
||||||
FWAAS_TO_IPTABLE_ACTION_MAP = {'allow': 'ACCEPT',
|
|
||||||
'deny': 'DROP',
|
|
||||||
'reject': 'REJECT'}
|
|
||||||
|
|
||||||
CHAIN_NAME_PREFIX = {constants.INGRESS_DIRECTION: 'i',
|
|
||||||
constants.EGRESS_DIRECTION: 'o'}
|
|
||||||
|
|
||||||
""" Firewall rules are applied on internal-interfaces of Neutron router.
|
|
||||||
The packets ingressing tenant's network will be on the output
|
|
||||||
direction on internal-interfaces.
|
|
||||||
"""
|
|
||||||
IPTABLES_DIR = {constants.INGRESS_DIRECTION: '-o',
|
|
||||||
constants.EGRESS_DIRECTION: '-i'}
|
|
||||||
IPV4 = 'ipv4'
|
|
||||||
IPV6 = 'ipv6'
|
|
||||||
IP_VER_TAG = {IPV4: 'v4',
|
|
||||||
IPV6: 'v6'}
|
|
||||||
|
|
||||||
INTERNAL_DEV_PREFIX = 'qr-'
|
|
||||||
SNAT_INT_DEV_PREFIX = 'sg-'
|
|
||||||
ROUTER_2_FIP_DEV_PREFIX = 'rfp-'
|
|
||||||
|
|
||||||
|
|
||||||
class IptablesFwaasDriver(fwaas_base.FwaasDriverBase):
|
|
||||||
"""IPTables driver for Firewall As A Service."""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
LOG.debug("Initializing fwaas iptables driver")
|
|
||||||
self.pre_firewall = None
|
|
||||||
self.conntrack = conntrack_base.load_and_init_conntrack_driver()
|
|
||||||
|
|
||||||
def create_firewall(self, agent_mode, apply_list, firewall):
|
|
||||||
LOG.debug('Creating firewall %(fw_id)s for tenant %(tid)s',
|
|
||||||
{'fw_id': firewall['id'], 'tid': firewall['tenant_id']})
|
|
||||||
try:
|
|
||||||
if firewall['admin_state_up']:
|
|
||||||
self._setup_firewall(agent_mode, apply_list, firewall)
|
|
||||||
self._remove_conntrack_new_firewall(agent_mode,
|
|
||||||
apply_list, firewall)
|
|
||||||
self.pre_firewall = dict(firewall)
|
|
||||||
else:
|
|
||||||
self.apply_default_policy(agent_mode, apply_list, firewall)
|
|
||||||
except (LookupError, RuntimeError):
|
|
||||||
# catch known library exceptions and raise Fwaas generic exception
|
|
||||||
LOG.exception("Failed to create firewall: %s", firewall['id'])
|
|
||||||
raise f_exc.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
|
|
||||||
|
|
||||||
def _get_ipt_mgrs_with_if_prefix(self, agent_mode, router_info):
|
|
||||||
"""Gets the iptables manager along with the if prefix to apply rules.
|
|
||||||
|
|
||||||
With DVR we can have differing namespaces depending on which agent
|
|
||||||
(on Network or Compute node). Also, there is an associated i/f for
|
|
||||||
each namespace. The iptables on the relevant namespace and matching
|
|
||||||
i/f are provided. On the Network node we could have both the snat
|
|
||||||
namespace and a fip so this is provided back as a list - so in that
|
|
||||||
scenario rules can be applied on both.
|
|
||||||
"""
|
|
||||||
if not router_info.router.get('distributed'):
|
|
||||||
return [{'ipt': router_info.iptables_manager,
|
|
||||||
'if_prefix': INTERNAL_DEV_PREFIX}]
|
|
||||||
ipt_mgrs = []
|
|
||||||
# TODO(sridar): refactor to get strings to a common location.
|
|
||||||
if agent_mode == 'dvr_snat':
|
|
||||||
if router_info.snat_iptables_manager:
|
|
||||||
ipt_mgrs.append({'ipt': router_info.snat_iptables_manager,
|
|
||||||
'if_prefix': SNAT_INT_DEV_PREFIX})
|
|
||||||
if router_info.rtr_fip_connect:
|
|
||||||
# handle the fip case on n/w or compute node.
|
|
||||||
ipt_mgrs.append({'ipt': router_info.iptables_manager,
|
|
||||||
'if_prefix': ROUTER_2_FIP_DEV_PREFIX})
|
|
||||||
return ipt_mgrs
|
|
||||||
|
|
||||||
def delete_firewall(self, agent_mode, apply_list, firewall):
|
|
||||||
LOG.debug('Deleting firewall %(fw_id)s for tenant %(tid)s',
|
|
||||||
{'fw_id': firewall['id'], 'tid': firewall['tenant_id']})
|
|
||||||
fwid = firewall['id']
|
|
||||||
try:
|
|
||||||
for router_info in apply_list:
|
|
||||||
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
|
|
||||||
agent_mode, router_info)
|
|
||||||
for ipt_if_prefix in ipt_if_prefix_list:
|
|
||||||
ipt_mgr = ipt_if_prefix['ipt']
|
|
||||||
self._remove_chains(fwid, ipt_mgr)
|
|
||||||
self._remove_default_chains(ipt_mgr)
|
|
||||||
# apply the changes immediately (no defer in firewall path)
|
|
||||||
ipt_mgr.defer_apply_off()
|
|
||||||
self.pre_firewall = None
|
|
||||||
except (LookupError, RuntimeError):
|
|
||||||
# catch known library exceptions and raise Fwaas generic exception
|
|
||||||
LOG.exception("Failed to delete firewall: %s", fwid)
|
|
||||||
raise f_exc.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
|
|
||||||
|
|
||||||
def update_firewall(self, agent_mode, apply_list, firewall):
|
|
||||||
LOG.debug('Updating firewall %(fw_id)s for tenant %(tid)s',
|
|
||||||
{'fw_id': firewall['id'], 'tid': firewall['tenant_id']})
|
|
||||||
try:
|
|
||||||
if firewall['admin_state_up']:
|
|
||||||
self._setup_firewall(agent_mode, apply_list, firewall)
|
|
||||||
if self.pre_firewall:
|
|
||||||
self._remove_conntrack_updated_firewall(agent_mode,
|
|
||||||
apply_list, self.pre_firewall, firewall)
|
|
||||||
else:
|
|
||||||
self._remove_conntrack_new_firewall(agent_mode,
|
|
||||||
apply_list, firewall)
|
|
||||||
else:
|
|
||||||
self.apply_default_policy(agent_mode, apply_list, firewall)
|
|
||||||
self.pre_firewall = dict(firewall)
|
|
||||||
except (LookupError, RuntimeError):
|
|
||||||
# catch known library exceptions and raise Fwaas generic exception
|
|
||||||
LOG.exception("Failed to update firewall: %s", firewall['id'])
|
|
||||||
raise f_exc.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
|
|
||||||
|
|
||||||
def apply_default_policy(self, agent_mode, apply_list, firewall):
|
|
||||||
LOG.debug('Applying firewall %(fw_id)s for tenant %(tid)s',
|
|
||||||
{'fw_id': firewall['id'], 'tid': firewall['tenant_id']})
|
|
||||||
fwid = firewall['id']
|
|
||||||
try:
|
|
||||||
for router_info in apply_list:
|
|
||||||
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
|
|
||||||
agent_mode, router_info)
|
|
||||||
for ipt_if_prefix in ipt_if_prefix_list:
|
|
||||||
# the following only updates local memory; no hole in FW
|
|
||||||
ipt_mgr = ipt_if_prefix['ipt']
|
|
||||||
self._remove_chains(fwid, ipt_mgr)
|
|
||||||
self._remove_default_chains(ipt_mgr)
|
|
||||||
|
|
||||||
# create default 'DROP ALL' policy chain
|
|
||||||
self._add_default_policy_chain_v4v6(ipt_mgr)
|
|
||||||
self._enable_policy_chain(fwid, ipt_if_prefix)
|
|
||||||
|
|
||||||
# apply the changes immediately (no defer in firewall path)
|
|
||||||
ipt_mgr.defer_apply_off()
|
|
||||||
except (LookupError, RuntimeError):
|
|
||||||
# catch known library exceptions and raise Fwaas generic exception
|
|
||||||
LOG.exception(
|
|
||||||
"Failed to apply default policy on firewall: %s", fwid)
|
|
||||||
raise f_exc.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
|
|
||||||
|
|
||||||
def _setup_firewall(self, agent_mode, apply_list, firewall):
|
|
||||||
fwid = firewall['id']
|
|
||||||
for router_info in apply_list:
|
|
||||||
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
|
|
||||||
agent_mode, router_info)
|
|
||||||
for ipt_if_prefix in ipt_if_prefix_list:
|
|
||||||
ipt_mgr = ipt_if_prefix['ipt']
|
|
||||||
# the following only updates local memory; no hole in FW
|
|
||||||
self._remove_chains(fwid, ipt_mgr)
|
|
||||||
self._remove_default_chains(ipt_mgr)
|
|
||||||
|
|
||||||
# create default 'DROP ALL' policy chain
|
|
||||||
self._add_default_policy_chain_v4v6(ipt_mgr)
|
|
||||||
#create chain based on configured policy
|
|
||||||
self._setup_chains(firewall, ipt_if_prefix)
|
|
||||||
|
|
||||||
# apply the changes immediately (no defer in firewall path)
|
|
||||||
ipt_mgr.defer_apply_off()
|
|
||||||
|
|
||||||
def _get_chain_name(self, fwid, ver, direction):
|
|
||||||
return '%s%s%s' % (CHAIN_NAME_PREFIX[direction],
|
|
||||||
IP_VER_TAG[ver],
|
|
||||||
fwid)
|
|
||||||
|
|
||||||
def _setup_chains(self, firewall, ipt_if_prefix):
|
|
||||||
"""Create Fwaas chain using the rules in the policy
|
|
||||||
"""
|
|
||||||
fw_rules_list = firewall['firewall_rule_list']
|
|
||||||
fwid = firewall['id']
|
|
||||||
ipt_mgr = ipt_if_prefix['ipt']
|
|
||||||
|
|
||||||
#default rules for invalid packets and established sessions
|
|
||||||
invalid_rule = self._drop_invalid_packets_rule()
|
|
||||||
est_rule = self._allow_established_rule()
|
|
||||||
|
|
||||||
for ver in [IPV4, IPV6]:
|
|
||||||
if ver == IPV4:
|
|
||||||
table = ipt_mgr.ipv4['filter']
|
|
||||||
else:
|
|
||||||
table = ipt_mgr.ipv6['filter']
|
|
||||||
ichain_name = self._get_chain_name(
|
|
||||||
fwid, ver, constants.INGRESS_DIRECTION)
|
|
||||||
ochain_name = self._get_chain_name(
|
|
||||||
fwid, ver, constants.EGRESS_DIRECTION)
|
|
||||||
for name in [ichain_name, ochain_name]:
|
|
||||||
table.add_chain(name)
|
|
||||||
table.add_rule(name, invalid_rule)
|
|
||||||
table.add_rule(name, est_rule)
|
|
||||||
|
|
||||||
for rule in fw_rules_list:
|
|
||||||
if not rule['enabled']:
|
|
||||||
continue
|
|
||||||
iptbl_rule = self._convert_fwaas_to_iptables_rule(rule)
|
|
||||||
if rule['ip_version'] == 4:
|
|
||||||
ver = IPV4
|
|
||||||
table = ipt_mgr.ipv4['filter']
|
|
||||||
else:
|
|
||||||
ver = IPV6
|
|
||||||
table = ipt_mgr.ipv6['filter']
|
|
||||||
ichain_name = self._get_chain_name(
|
|
||||||
fwid, ver, constants.INGRESS_DIRECTION)
|
|
||||||
ochain_name = self._get_chain_name(
|
|
||||||
fwid, ver, constants.EGRESS_DIRECTION)
|
|
||||||
table.add_rule(ichain_name, iptbl_rule)
|
|
||||||
table.add_rule(ochain_name, iptbl_rule)
|
|
||||||
self._enable_policy_chain(fwid, ipt_if_prefix)
|
|
||||||
|
|
||||||
def _find_changed_rules(self, pre_firewall, firewall):
|
|
||||||
"""Find the rules changed between the current firewall
|
|
||||||
and the updating rule
|
|
||||||
"""
|
|
||||||
changed_rules = []
|
|
||||||
fw_rules_list = firewall[f_const.FIREWALL_RULE_LIST]
|
|
||||||
pre_fw_rules_list = pre_firewall[f_const.FIREWALL_RULE_LIST]
|
|
||||||
for pre_fw_rule in pre_fw_rules_list:
|
|
||||||
for fw_rule in fw_rules_list:
|
|
||||||
if (pre_fw_rule.get('id') == fw_rule.get('id') and
|
|
||||||
pre_fw_rule != fw_rule):
|
|
||||||
changed_rules.append(pre_fw_rule)
|
|
||||||
changed_rules.append(fw_rule)
|
|
||||||
return changed_rules
|
|
||||||
|
|
||||||
def _find_removed_rules(self, pre_firewall, firewall):
|
|
||||||
fw_rules_list = firewall[f_const.FIREWALL_RULE_LIST]
|
|
||||||
pre_fw_rules_list = pre_firewall[f_const.FIREWALL_RULE_LIST]
|
|
||||||
fw_rule_ids = [fw_rule.get('id') for fw_rule in fw_rules_list]
|
|
||||||
removed_rules = [pre_fw_rule for pre_fw_rule in
|
|
||||||
pre_fw_rules_list if pre_fw_rule.get('id') not in fw_rule_ids]
|
|
||||||
return removed_rules
|
|
||||||
|
|
||||||
def _find_new_rules(self, pre_firewall, firewall):
|
|
||||||
return self._find_removed_rules(firewall, pre_firewall)
|
|
||||||
|
|
||||||
def _remove_conntrack_new_firewall(self, agent_mode, apply_list, firewall):
|
|
||||||
"""Remove conntrack when create new firewall"""
|
|
||||||
routers_list = list(set(apply_list))
|
|
||||||
for router_info in routers_list:
|
|
||||||
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
|
|
||||||
agent_mode, router_info)
|
|
||||||
for ipt_if_prefix in ipt_if_prefix_list:
|
|
||||||
ipt_mgr = ipt_if_prefix['ipt']
|
|
||||||
self.conntrack.flush_entries(ipt_mgr.namespace)
|
|
||||||
|
|
||||||
def _remove_conntrack_updated_firewall(self, agent_mode,
|
|
||||||
apply_list, pre_firewall, firewall):
|
|
||||||
"""Remove conntrack when updated firewall"""
|
|
||||||
router_list = list(set(apply_list))
|
|
||||||
for router_info in router_list:
|
|
||||||
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
|
|
||||||
agent_mode, router_info)
|
|
||||||
for ipt_if_prefix in ipt_if_prefix_list:
|
|
||||||
ipt_mgr = ipt_if_prefix['ipt']
|
|
||||||
ch_rules = self._find_changed_rules(pre_firewall,
|
|
||||||
firewall)
|
|
||||||
i_rules = self._find_new_rules(pre_firewall, firewall)
|
|
||||||
r_rules = self._find_removed_rules(pre_firewall, firewall)
|
|
||||||
removed_conntrack_rules_list = ch_rules + i_rules + r_rules
|
|
||||||
self.conntrack.delete_entries(removed_conntrack_rules_list,
|
|
||||||
ipt_mgr.namespace)
|
|
||||||
|
|
||||||
def _remove_default_chains(self, nsid):
|
|
||||||
"""Remove fwaas default policy chain."""
|
|
||||||
self._remove_chain_by_name(IPV4, FWAAS_DEFAULT_CHAIN, nsid)
|
|
||||||
self._remove_chain_by_name(IPV6, FWAAS_DEFAULT_CHAIN, nsid)
|
|
||||||
|
|
||||||
def _remove_chains(self, fwid, ipt_mgr):
|
|
||||||
"""Remove fwaas policy chain."""
|
|
||||||
for ver in [IPV4, IPV6]:
|
|
||||||
for direction in [constants.INGRESS_DIRECTION,
|
|
||||||
constants.EGRESS_DIRECTION]:
|
|
||||||
chain_name = self._get_chain_name(fwid, ver, direction)
|
|
||||||
self._remove_chain_by_name(ver, chain_name, ipt_mgr)
|
|
||||||
|
|
||||||
def _add_default_policy_chain_v4v6(self, ipt_mgr):
|
|
||||||
ipt_mgr.ipv4['filter'].add_chain(FWAAS_DEFAULT_CHAIN)
|
|
||||||
ipt_mgr.ipv4['filter'].add_rule(FWAAS_DEFAULT_CHAIN, '-j DROP')
|
|
||||||
ipt_mgr.ipv6['filter'].add_chain(FWAAS_DEFAULT_CHAIN)
|
|
||||||
ipt_mgr.ipv6['filter'].add_rule(FWAAS_DEFAULT_CHAIN, '-j DROP')
|
|
||||||
|
|
||||||
def _remove_chain_by_name(self, ver, chain_name, ipt_mgr):
|
|
||||||
if ver == IPV4:
|
|
||||||
ipt_mgr.ipv4['filter'].remove_chain(chain_name)
|
|
||||||
else:
|
|
||||||
ipt_mgr.ipv6['filter'].remove_chain(chain_name)
|
|
||||||
|
|
||||||
def _add_rules_to_chain(self, ipt_mgr, ver, chain_name, rules):
|
|
||||||
if ver == IPV4:
|
|
||||||
table = ipt_mgr.ipv4['filter']
|
|
||||||
else:
|
|
||||||
table = ipt_mgr.ipv6['filter']
|
|
||||||
for rule in rules:
|
|
||||||
table.add_rule(chain_name, rule)
|
|
||||||
|
|
||||||
def _enable_policy_chain(self, fwid, ipt_if_prefix):
|
|
||||||
bname = iptables_manager.binary_name
|
|
||||||
ipt_mgr = ipt_if_prefix['ipt']
|
|
||||||
if_prefix = ipt_if_prefix['if_prefix']
|
|
||||||
|
|
||||||
for (ver, tbl) in [(IPV4, ipt_mgr.ipv4['filter']),
|
|
||||||
(IPV6, ipt_mgr.ipv6['filter'])]:
|
|
||||||
for direction in [constants.INGRESS_DIRECTION,
|
|
||||||
constants.EGRESS_DIRECTION]:
|
|
||||||
chain_name = self._get_chain_name(fwid, ver, direction)
|
|
||||||
chain_name = iptables_manager.get_chain_name(chain_name)
|
|
||||||
if chain_name in tbl.chains:
|
|
||||||
jump_rule = ['%s %s+ -j %s-%s' % (IPTABLES_DIR[direction],
|
|
||||||
if_prefix, bname, chain_name)]
|
|
||||||
self._add_rules_to_chain(ipt_mgr,
|
|
||||||
ver, 'FORWARD', jump_rule)
|
|
||||||
|
|
||||||
#jump to DROP_ALL policy
|
|
||||||
chain_name = iptables_manager.get_chain_name(FWAAS_DEFAULT_CHAIN)
|
|
||||||
jump_rule = ['-o %s+ -j %s-%s' % (if_prefix, bname, chain_name)]
|
|
||||||
self._add_rules_to_chain(ipt_mgr, IPV4, 'FORWARD', jump_rule)
|
|
||||||
self._add_rules_to_chain(ipt_mgr, IPV6, 'FORWARD', jump_rule)
|
|
||||||
|
|
||||||
#jump to DROP_ALL policy
|
|
||||||
chain_name = iptables_manager.get_chain_name(FWAAS_DEFAULT_CHAIN)
|
|
||||||
jump_rule = ['-i %s+ -j %s-%s' % (if_prefix, bname, chain_name)]
|
|
||||||
self._add_rules_to_chain(ipt_mgr, IPV4, 'FORWARD', jump_rule)
|
|
||||||
self._add_rules_to_chain(ipt_mgr, IPV6, 'FORWARD', jump_rule)
|
|
||||||
|
|
||||||
def _convert_fwaas_to_iptables_rule(self, rule):
|
|
||||||
action = FWAAS_TO_IPTABLE_ACTION_MAP[rule.get('action')]
|
|
||||||
|
|
||||||
# Output ordering is important here as it must exactly match what
|
|
||||||
# is returned by iptables-save. If not we risk unnecessarily removing
|
|
||||||
# and readding rules.
|
|
||||||
args = []
|
|
||||||
|
|
||||||
args += self._protocol_arg(rule.get('protocol'))
|
|
||||||
|
|
||||||
args += self._ip_prefix_arg('s', rule.get('source_ip_address'))
|
|
||||||
args += self._ip_prefix_arg('d', rule.get('destination_ip_address'))
|
|
||||||
|
|
||||||
# iptables adds '-m protocol' when any source
|
|
||||||
# or destination port number is specified
|
|
||||||
if (rule.get('source_port') is not None or
|
|
||||||
rule.get('destination_port') is not None):
|
|
||||||
args += self._match_arg(rule.get('protocol'))
|
|
||||||
|
|
||||||
args += self._port_arg('sport',
|
|
||||||
rule.get('protocol'),
|
|
||||||
rule.get('source_port'))
|
|
||||||
|
|
||||||
args += self._port_arg('dport',
|
|
||||||
rule.get('protocol'),
|
|
||||||
rule.get('destination_port'))
|
|
||||||
|
|
||||||
args += self._action_arg(action)
|
|
||||||
|
|
||||||
iptables_rule = ' '.join(args)
|
|
||||||
return iptables_rule
|
|
||||||
|
|
||||||
def _drop_invalid_packets_rule(self):
|
|
||||||
return '-m state --state INVALID -j DROP'
|
|
||||||
|
|
||||||
def _allow_established_rule(self):
|
|
||||||
return '-m state --state RELATED,ESTABLISHED -j ACCEPT'
|
|
||||||
|
|
||||||
def _action_arg(self, action):
|
|
||||||
if not action:
|
|
||||||
return []
|
|
||||||
|
|
||||||
args = ['-j', action]
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
def _protocol_arg(self, protocol):
|
|
||||||
if not protocol:
|
|
||||||
return []
|
|
||||||
|
|
||||||
args = ['-p', protocol]
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
def _match_arg(self, protocol):
|
|
||||||
if not protocol:
|
|
||||||
return []
|
|
||||||
|
|
||||||
protocol_modules = {'udp': 'udp', 'tcp': 'tcp',
|
|
||||||
'icmp': 'icmp', 'ipv6-icmp': 'icmp6'}
|
|
||||||
# iptables adds '-m protocol' when the port number is specified
|
|
||||||
args = ['-m', protocol_modules[protocol]]
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
def _port_arg(self, direction, protocol, port):
|
|
||||||
if protocol not in ['udp', 'tcp'] or port is None:
|
|
||||||
return []
|
|
||||||
|
|
||||||
args = ['--%s' % direction, '%s' % port]
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
def _ip_prefix_arg(self, direction, ip_prefix):
|
|
||||||
if not(ip_prefix):
|
|
||||||
return []
|
|
||||||
|
|
||||||
args = ['-%s' % direction, '%s' % utils.ip_to_cidr(ip_prefix)]
|
|
||||||
return args
|
|
@ -1,428 +0,0 @@
|
|||||||
# 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_lib.agent import l3_extension
|
|
||||||
from neutron_lib import constants as nl_constants
|
|
||||||
from neutron_lib import context
|
|
||||||
from neutron_lib.exceptions import firewall_v1 as fw_ext
|
|
||||||
from neutron_lib import rpc as n_rpc
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import helpers as log_helpers
|
|
||||||
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.service_drivers.agents \
|
|
||||||
import firewall_agent_api as api
|
|
||||||
from neutron_fwaas.services.firewall.service_drivers.agents \
|
|
||||||
import firewall_service
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
#TODO(njohnston): There needs to be some extrapolation of the common code
|
|
||||||
# between this module and firewall_l3_agent_v2.py.
|
|
||||||
|
|
||||||
|
|
||||||
class FWaaSL3PluginApi(api.FWaaSPluginApiMixin):
|
|
||||||
"""Agent side of the FWaaS agent to FWaaS Plugin RPC API."""
|
|
||||||
def __init__(self, topic, host):
|
|
||||||
super(FWaaSL3PluginApi, self).__init__(topic, host)
|
|
||||||
|
|
||||||
def get_firewalls_for_tenant(self, context, **kwargs):
|
|
||||||
"""Get the Firewalls with rules from the Plugin to send to driver."""
|
|
||||||
LOG.debug("Retrieve Firewall with rules from Plugin")
|
|
||||||
cctxt = self.client.prepare()
|
|
||||||
return cctxt.call(context, 'get_firewalls_for_tenant', host=self.host)
|
|
||||||
|
|
||||||
def get_tenants_with_firewalls(self, context, **kwargs):
|
|
||||||
"""Get all Tenants that have Firewalls configured from plugin."""
|
|
||||||
LOG.debug("Retrieve Tenants with Firewalls configured from Plugin")
|
|
||||||
cctxt = self.client.prepare()
|
|
||||||
return cctxt.call(context,
|
|
||||||
'get_tenants_with_firewalls', host=self.host)
|
|
||||||
|
|
||||||
|
|
||||||
class FWaaSL3AgentExtension(l3_extension.L3AgentExtension):
|
|
||||||
"""FWaaS Agent support to be used by Neutron L3 agent."""
|
|
||||||
|
|
||||||
SUPPORTED_RESOURCE_TYPES = [f_resources.FIREWALL_GROUP,
|
|
||||||
f_resources.FIREWALL_POLICY,
|
|
||||||
f_resources.FIREWALL_RULE]
|
|
||||||
|
|
||||||
def initialize(self, connection, driver_type):
|
|
||||||
self._register_rpc_consumers(connection)
|
|
||||||
|
|
||||||
def consume_api(self, agent_api):
|
|
||||||
LOG.debug("FWaaS consume_api call occurred with %s", agent_api)
|
|
||||||
self.agent_api = agent_api
|
|
||||||
|
|
||||||
def _register_rpc_consumers(self, connection):
|
|
||||||
#TODO(njohnston): Add RPC consumer connection loading here.
|
|
||||||
pass
|
|
||||||
|
|
||||||
def start_rpc_listeners(self, conf):
|
|
||||||
self.endpoints = [self]
|
|
||||||
|
|
||||||
self.conn = n_rpc.Connection()
|
|
||||||
self.conn.create_consumer(
|
|
||||||
fwaas_constants.FW_AGENT, self.endpoints, fanout=False)
|
|
||||||
return self.conn.consume_in_threads()
|
|
||||||
|
|
||||||
def __init__(self, host, conf):
|
|
||||||
LOG.debug("Initializing firewall agent")
|
|
||||||
self.agent_api = None
|
|
||||||
self.neutron_service_plugins = None
|
|
||||||
self.conf = conf
|
|
||||||
self.fwaas_enabled = cfg.CONF.fwaas.enabled
|
|
||||||
self.start_rpc_listeners(conf)
|
|
||||||
|
|
||||||
# None means l3-agent has no information on the server
|
|
||||||
# configuration due to the lack of RPC support.
|
|
||||||
if self.neutron_service_plugins is not None:
|
|
||||||
fwaas_plugin_configured = (fwaas_constants.FIREWALL
|
|
||||||
in self.neutron_service_plugins)
|
|
||||||
if fwaas_plugin_configured and not self.fwaas_enabled:
|
|
||||||
msg = ("FWaaS plugin is configured in the server side, but "
|
|
||||||
"FWaaS is disabled in L3-agent.")
|
|
||||||
LOG.error(msg)
|
|
||||||
raise SystemExit(1)
|
|
||||||
self.fwaas_enabled = self.fwaas_enabled and fwaas_plugin_configured
|
|
||||||
|
|
||||||
if self.fwaas_enabled:
|
|
||||||
# NOTE: Temp location for creating service and loading driver
|
|
||||||
self.fw_service = firewall_service.FirewallService()
|
|
||||||
self.fwaas_driver = self.fw_service.load_device_drivers()
|
|
||||||
self.services_sync_needed = False
|
|
||||||
# setup RPC to msg fwaas plugin
|
|
||||||
self.fwplugin_rpc = FWaaSL3PluginApi(fwaas_constants.FIREWALL_PLUGIN,
|
|
||||||
host)
|
|
||||||
|
|
||||||
def _has_router_insertion_fields(self, fw):
|
|
||||||
return 'add-router-ids' in fw
|
|
||||||
|
|
||||||
def _get_router_ids_for_fw(self, context, fw, to_delete=False):
|
|
||||||
"""Return the router_ids either from fw dict or tenant routers."""
|
|
||||||
if self._has_router_insertion_fields(fw):
|
|
||||||
# it is a new version of plugin
|
|
||||||
return (fw['del-router-ids'] if to_delete
|
|
||||||
else fw['add-router-ids'])
|
|
||||||
else:
|
|
||||||
return [router['id'] for router in
|
|
||||||
self.agent_api.get_routers_in_project(fw['tenant_id'])]
|
|
||||||
|
|
||||||
def _get_routers_in_project(self, project_id):
|
|
||||||
if self.agent_api is None:
|
|
||||||
LOG.exception("FWaaS RPC call failed; L3 agent_api failure")
|
|
||||||
return self.agent_api.get_routers_in_project(project_id)
|
|
||||||
|
|
||||||
def _get_router_info_list_for_tenant(self, router_ids, tenant_id):
|
|
||||||
"""Returns the list of router info objects on which to apply the fw."""
|
|
||||||
return [ri for ri in self._get_routers_in_project(tenant_id)
|
|
||||||
if ri.router_id in router_ids and
|
|
||||||
self.agent_api.is_router_in_namespace(ri.router_id)]
|
|
||||||
|
|
||||||
def _invoke_driver_for_sync_from_plugin(self, ctx, router_info_list, fw):
|
|
||||||
"""Invoke the delete driver method for status of PENDING_DELETE and
|
|
||||||
update method for all other status to (re)apply on driver which is
|
|
||||||
Idempotent.
|
|
||||||
"""
|
|
||||||
if fw['status'] == nl_constants.PENDING_DELETE:
|
|
||||||
try:
|
|
||||||
self.fwaas_driver.delete_firewall(
|
|
||||||
self.conf.agent_mode,
|
|
||||||
router_info_list,
|
|
||||||
fw)
|
|
||||||
self.fwplugin_rpc.firewall_deleted(
|
|
||||||
ctx,
|
|
||||||
fw['id'])
|
|
||||||
except fw_ext.FirewallInternalDriverError:
|
|
||||||
LOG.error("Firewall Driver Error on fw state %(fwmsg)s "
|
|
||||||
"for fw: %(fwid)s",
|
|
||||||
{'fwmsg': fw['status'], 'fwid': fw['id']})
|
|
||||||
self.fwplugin_rpc.set_firewall_status(
|
|
||||||
ctx,
|
|
||||||
fw['id'],
|
|
||||||
nl_constants.ERROR)
|
|
||||||
else:
|
|
||||||
# PENDING_UPDATE, PENDING_CREATE, ...
|
|
||||||
try:
|
|
||||||
self.fwaas_driver.update_firewall(
|
|
||||||
self.conf.agent_mode,
|
|
||||||
router_info_list,
|
|
||||||
fw)
|
|
||||||
if fw['admin_state_up']:
|
|
||||||
status = nl_constants.ACTIVE
|
|
||||||
else:
|
|
||||||
status = nl_constants.DOWN
|
|
||||||
except fw_ext.FirewallInternalDriverError:
|
|
||||||
LOG.error("Firewall Driver Error on fw state %(fwmsg)s "
|
|
||||||
"for fw: %(fwid)s",
|
|
||||||
{'fwmsg': fw['status'], 'fwid': fw['id']})
|
|
||||||
status = nl_constants.ERROR
|
|
||||||
|
|
||||||
self.fwplugin_rpc.set_firewall_status(
|
|
||||||
ctx,
|
|
||||||
fw['id'],
|
|
||||||
status)
|
|
||||||
|
|
||||||
def _process_router_add(self, router):
|
|
||||||
"""On router add, get fw with rules from plugin and update driver."""
|
|
||||||
LOG.debug("Process router add, router_id: '%s'", router['id'])
|
|
||||||
router_ids = router['id']
|
|
||||||
router_info_list = self._get_router_info_list_for_tenant(
|
|
||||||
[router_ids],
|
|
||||||
router['tenant_id'])
|
|
||||||
if router_info_list:
|
|
||||||
# Get the firewall with rules
|
|
||||||
# for the tenant the router is on.
|
|
||||||
ctx = context.Context('', router['tenant_id'])
|
|
||||||
fw_list = self.fwplugin_rpc.get_firewalls_for_tenant(ctx)
|
|
||||||
for fw in fw_list:
|
|
||||||
if self._has_router_insertion_fields(fw):
|
|
||||||
# if router extension present apply only if router in fw
|
|
||||||
if (not (router_ids in fw['add-router-ids']) and
|
|
||||||
not (router_ids in fw['del-router-ids'])):
|
|
||||||
continue
|
|
||||||
self._invoke_driver_for_sync_from_plugin(
|
|
||||||
ctx,
|
|
||||||
router_info_list,
|
|
||||||
fw)
|
|
||||||
# router can be present only on one fw
|
|
||||||
return
|
|
||||||
|
|
||||||
def add_router(self, context, new_router):
|
|
||||||
"""On router add, get fw with rules from plugin and update driver.
|
|
||||||
|
|
||||||
Handles agent restart, when a router is added, query the plugin to
|
|
||||||
check if this router is in the router list for any firewall. If so
|
|
||||||
install firewall rules on this router.
|
|
||||||
"""
|
|
||||||
# avoid msg to plugin when fwaas is not configured
|
|
||||||
if not self.fwaas_enabled:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
self._process_router_add(new_router)
|
|
||||||
except Exception:
|
|
||||||
LOG.exception(
|
|
||||||
"FWaaS RPC info call failed for '%s'.", new_router['id'])
|
|
||||||
self.services_sync_needed = True
|
|
||||||
|
|
||||||
def update_router(self, context, updated_router):
|
|
||||||
"""The update_router method is just a synonym for add_router"""
|
|
||||||
self.add_router(context, updated_router)
|
|
||||||
|
|
||||||
def delete_router(self, context, new_router):
|
|
||||||
"""Handles router deletion. There is basically nothing to do for this
|
|
||||||
in the context of FWaaS with an IPTables driver; the namespace will
|
|
||||||
already have been deleted, taking the IPTables rules with it.
|
|
||||||
"""
|
|
||||||
#TODO(njohnston): When another firewall driver is implemented, look at
|
|
||||||
# expanding this out so that the driver can handle deletion calls.
|
|
||||||
pass
|
|
||||||
|
|
||||||
def process_services_sync(self, ctx):
|
|
||||||
if not self.services_sync_needed:
|
|
||||||
return
|
|
||||||
|
|
||||||
"""On RPC issues sync with plugin and apply the sync data."""
|
|
||||||
# avoid msg to plugin when fwaas is not configured
|
|
||||||
if not self.fwaas_enabled:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
# get the list of tenants with firewalls configured
|
|
||||||
# from the plugin
|
|
||||||
tenant_ids = self.fwplugin_rpc.get_tenants_with_firewalls(ctx)
|
|
||||||
LOG.debug("Tenants with Firewalls: '%s'", tenant_ids)
|
|
||||||
for tenant_id in tenant_ids:
|
|
||||||
ctx = context.Context('', tenant_id)
|
|
||||||
fw_list = self.fwplugin_rpc.get_firewalls_for_tenant(ctx)
|
|
||||||
for fw in fw_list:
|
|
||||||
if fw['status'] == nl_constants.PENDING_DELETE:
|
|
||||||
self.delete_firewall(ctx, fw, self.host)
|
|
||||||
# no need to apply sync data for ACTIVE fw
|
|
||||||
elif fw['status'] != nl_constants.ACTIVE:
|
|
||||||
self.update_firewall(ctx, fw, self.host)
|
|
||||||
self.services_sync_needed = False
|
|
||||||
except Exception:
|
|
||||||
LOG.exception("Failed fwaas process services sync")
|
|
||||||
self.services_sync_needed = True
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def create_firewall(self, context, firewall, host):
|
|
||||||
"""Handle Rpc from plugin to create a firewall."""
|
|
||||||
|
|
||||||
router_ids = self._get_router_ids_for_fw(context, firewall)
|
|
||||||
if not router_ids:
|
|
||||||
return
|
|
||||||
router_info_list = self._get_router_info_list_for_tenant(
|
|
||||||
router_ids,
|
|
||||||
firewall['tenant_id'])
|
|
||||||
LOG.debug("Create: Add firewall on Router List: '%s'",
|
|
||||||
[ri.router['id'] for ri in router_info_list])
|
|
||||||
# call into the driver
|
|
||||||
try:
|
|
||||||
self.fwaas_driver.create_firewall(
|
|
||||||
self.conf.agent_mode,
|
|
||||||
router_info_list,
|
|
||||||
firewall)
|
|
||||||
if firewall['admin_state_up']:
|
|
||||||
status = nl_constants.ACTIVE
|
|
||||||
else:
|
|
||||||
status = nl_constants.DOWN
|
|
||||||
except fw_ext.FirewallInternalDriverError:
|
|
||||||
LOG.error("Firewall Driver Error for create_firewall "
|
|
||||||
"for firewall: %s", firewall['id'])
|
|
||||||
status = nl_constants.ERROR
|
|
||||||
|
|
||||||
try:
|
|
||||||
# send status back to plugin
|
|
||||||
self.fwplugin_rpc.set_firewall_status(
|
|
||||||
context,
|
|
||||||
firewall['id'],
|
|
||||||
status)
|
|
||||||
except Exception:
|
|
||||||
LOG.exception("FWaaS RPC failure in create_firewall "
|
|
||||||
"for firewall: %s", firewall['id'])
|
|
||||||
self.services_sync_needed = True
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def update_firewall(self, context, firewall, host):
|
|
||||||
"""Handle Rpc from plugin to update a firewall."""
|
|
||||||
|
|
||||||
status = ""
|
|
||||||
if self._has_router_insertion_fields(firewall):
|
|
||||||
# with the router_ids extension, we may need to delete and add
|
|
||||||
# based on the list of routers. On the older version, we just
|
|
||||||
# update (add) all routers on the tenant - delete not needed.
|
|
||||||
router_ids = self._get_router_ids_for_fw(
|
|
||||||
context, firewall, to_delete=True)
|
|
||||||
if router_ids:
|
|
||||||
router_info_list = self._get_router_info_list_for_tenant(
|
|
||||||
router_ids,
|
|
||||||
firewall['tenant_id'])
|
|
||||||
# remove the firewall from this set of routers
|
|
||||||
# but no ack sent yet, check if we need to add
|
|
||||||
LOG.debug("Update: Delete firewall on Router List: '%s'",
|
|
||||||
[ri.router['id'] for ri in router_info_list])
|
|
||||||
try:
|
|
||||||
self.fwaas_driver.delete_firewall(
|
|
||||||
self.conf.agent_mode,
|
|
||||||
router_info_list,
|
|
||||||
firewall)
|
|
||||||
if firewall['last-router']:
|
|
||||||
status = nl_constants.INACTIVE
|
|
||||||
elif firewall['admin_state_up']:
|
|
||||||
status = nl_constants.ACTIVE
|
|
||||||
else:
|
|
||||||
status = nl_constants.DOWN
|
|
||||||
except fw_ext.FirewallInternalDriverError:
|
|
||||||
LOG.error(
|
|
||||||
"Firewall Driver Error for "
|
|
||||||
"update_firewall for firewall: %s", firewall['id'])
|
|
||||||
status = nl_constants.ERROR
|
|
||||||
|
|
||||||
# handle the add router and/or rule, policy, firewall
|
|
||||||
# attribute updates
|
|
||||||
if status not in (nl_constants.ERROR, nl_constants.INACTIVE):
|
|
||||||
router_ids = self._get_router_ids_for_fw(context, firewall)
|
|
||||||
if router_ids or firewall['router_ids']:
|
|
||||||
router_info_list = self._get_router_info_list_for_tenant(
|
|
||||||
router_ids + firewall['router_ids'],
|
|
||||||
firewall['tenant_id'])
|
|
||||||
LOG.debug("Update: Add firewall on Router List: '%s'",
|
|
||||||
[ri.router['id'] for ri in router_info_list])
|
|
||||||
# call into the driver
|
|
||||||
try:
|
|
||||||
self.fwaas_driver.update_firewall(
|
|
||||||
self.conf.agent_mode,
|
|
||||||
router_info_list,
|
|
||||||
firewall)
|
|
||||||
if firewall['admin_state_up']:
|
|
||||||
status = nl_constants.ACTIVE
|
|
||||||
else:
|
|
||||||
status = nl_constants.DOWN
|
|
||||||
except fw_ext.FirewallInternalDriverError:
|
|
||||||
LOG.error(
|
|
||||||
"Firewall Driver Error for "
|
|
||||||
"update_firewall for firewall: %s", firewall['id'])
|
|
||||||
status = nl_constants.ERROR
|
|
||||||
else:
|
|
||||||
status = nl_constants.INACTIVE
|
|
||||||
try:
|
|
||||||
# send status back to plugin
|
|
||||||
self.fwplugin_rpc.set_firewall_status(
|
|
||||||
context,
|
|
||||||
firewall['id'],
|
|
||||||
status)
|
|
||||||
except Exception:
|
|
||||||
LOG.exception("FWaaS RPC failure in update_firewall "
|
|
||||||
"for firewall: %s", firewall['id'])
|
|
||||||
self.services_sync_needed = True
|
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
|
||||||
def delete_firewall(self, context, firewall, host):
|
|
||||||
"""Handle Rpc from plugin to delete a firewall."""
|
|
||||||
|
|
||||||
router_ids = self._get_router_ids_for_fw(
|
|
||||||
context, firewall, to_delete=True)
|
|
||||||
if router_ids:
|
|
||||||
router_info_list = self._get_router_info_list_for_tenant(
|
|
||||||
router_ids,
|
|
||||||
firewall['tenant_id'])
|
|
||||||
LOG.debug(
|
|
||||||
"Delete firewall %(fw)s on routers: '%(routers)s'",
|
|
||||||
{'fw': firewall['id'],
|
|
||||||
'routers': [ri.router['id'] for ri in router_info_list]})
|
|
||||||
# call into the driver
|
|
||||||
try:
|
|
||||||
self.fwaas_driver.delete_firewall(
|
|
||||||
self.conf.agent_mode,
|
|
||||||
router_info_list,
|
|
||||||
firewall)
|
|
||||||
if firewall['admin_state_up']:
|
|
||||||
status = nl_constants.ACTIVE
|
|
||||||
else:
|
|
||||||
status = nl_constants.DOWN
|
|
||||||
except fw_ext.FirewallInternalDriverError:
|
|
||||||
LOG.error("Firewall Driver Error for delete_firewall "
|
|
||||||
"for firewall: %s", firewall['id'])
|
|
||||||
status = nl_constants.ERROR
|
|
||||||
|
|
||||||
try:
|
|
||||||
# send status back to plugin
|
|
||||||
if status in [nl_constants.ACTIVE, nl_constants.DOWN]:
|
|
||||||
self.fwplugin_rpc.firewall_deleted(context, firewall['id'])
|
|
||||||
else:
|
|
||||||
self.fwplugin_rpc.set_firewall_status(
|
|
||||||
context,
|
|
||||||
firewall['id'],
|
|
||||||
status)
|
|
||||||
except Exception:
|
|
||||||
LOG.exception("FWaaS RPC failure in delete_firewall "
|
|
||||||
"for firewall: %s", firewall['id'])
|
|
||||||
self.services_sync_needed = True
|
|
||||||
|
|
||||||
def ha_state_change(self, context, data):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class L3WithFWaaS(FWaaSL3AgentExtension):
|
|
||||||
|
|
||||||
def __init__(self, conf=None):
|
|
||||||
if conf:
|
|
||||||
self.conf = conf
|
|
||||||
else:
|
|
||||||
self.conf = cfg.CONF
|
|
||||||
super(L3WithFWaaS, self).__init__(host=self.conf.host, conf=self.conf)
|
|
@ -22,9 +22,10 @@ from neutron_fwaas.db.models import head
|
|||||||
|
|
||||||
# EXTERNAL_TABLES should contain all names of tables that are not related to
|
# EXTERNAL_TABLES should contain all names of tables that are not related to
|
||||||
# current repo.
|
# current repo.
|
||||||
EXTERNAL_TABLES = set(external.TABLES) - set(external.FWAAS_TABLES)
|
EXTERNAL_TABLES = set(external.TABLES)
|
||||||
# Model moved to vendor repo
|
# Model moved to vendor repo
|
||||||
EXTERNAL_TABLES.update({'cisco_firewall_associations'})
|
EXTERNAL_TABLES.update({'cisco_firewall_associations'})
|
||||||
|
EXTERNAL_TABLES.update({'firewall_router_associations'})
|
||||||
|
|
||||||
VERSION_TABLE = 'alembic_version_fwaas'
|
VERSION_TABLE = 'alembic_version_fwaas'
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
# Copyright (c) 2015 Midokura SARL
|
|
||||||
# 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 tempest.api.network import base
|
|
||||||
|
|
||||||
from neutron_fwaas.tests.tempest_plugin.tests import fwaas_client
|
|
||||||
|
|
||||||
|
|
||||||
class BaseFWaaSTest(fwaas_client.FWaaSClientMixin, base.BaseNetworkTest):
|
|
||||||
pass
|
|
@ -1,447 +0,0 @@
|
|||||||
# Copyright 2014 NEC Corporation. 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 six
|
|
||||||
|
|
||||||
from tempest.common import utils
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib.common.utils import test_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
from tempest.lib import exceptions as lib_exc
|
|
||||||
|
|
||||||
from neutron_fwaas.tests.tempest_plugin.tests.api import base
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class FWaaSExtensionTestJSON(base.BaseFWaaSTest):
|
|
||||||
|
|
||||||
"""
|
|
||||||
Tests the following operations in the Neutron API using the REST client for
|
|
||||||
Neutron:
|
|
||||||
|
|
||||||
List firewall rules
|
|
||||||
Create firewall rule
|
|
||||||
Update firewall rule
|
|
||||||
Delete firewall rule
|
|
||||||
Show firewall rule
|
|
||||||
List firewall policies
|
|
||||||
Create firewall policy
|
|
||||||
Update firewall policy
|
|
||||||
Insert firewall rule to policy
|
|
||||||
Remove firewall rule from policy
|
|
||||||
Insert firewall rule after/before rule in policy
|
|
||||||
Update firewall policy audited attribute
|
|
||||||
Delete firewall policy
|
|
||||||
Show firewall policy
|
|
||||||
List firewall
|
|
||||||
Create firewall
|
|
||||||
Update firewall
|
|
||||||
Delete firewall
|
|
||||||
Show firewall
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(FWaaSExtensionTestJSON, cls).resource_setup()
|
|
||||||
if not utils.is_extension_enabled('fwaas', 'network'):
|
|
||||||
msg = "FWaaS Extension not enabled."
|
|
||||||
raise cls.skipException(msg)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(FWaaSExtensionTestJSON, self).setUp()
|
|
||||||
self.fw_rule = self.create_firewall_rule(action="allow",
|
|
||||||
protocol="tcp")
|
|
||||||
self.fw_policy = self.create_firewall_policy()
|
|
||||||
|
|
||||||
def _try_delete_router(self, router):
|
|
||||||
# delete router, if it exists
|
|
||||||
try:
|
|
||||||
self.delete_router(router)
|
|
||||||
# if router is not found, this means it was deleted in the test
|
|
||||||
except lib_exc.NotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _try_delete_policy(self, policy_id):
|
|
||||||
# delete policy, if it exists
|
|
||||||
try:
|
|
||||||
self.firewall_policies_client.delete_firewall_policy(policy_id)
|
|
||||||
# if policy is not found, this means it was deleted in the test
|
|
||||||
except lib_exc.NotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _try_delete_rule(self, rule_id):
|
|
||||||
# delete rule, if it exists
|
|
||||||
try:
|
|
||||||
self.firewall_rules_client.delete_firewall_rule(rule_id)
|
|
||||||
# if rule is not found, this means it was deleted in the test
|
|
||||||
except lib_exc.NotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _try_delete_firewall(self, fw_id):
|
|
||||||
# delete firewall, if it exists
|
|
||||||
try:
|
|
||||||
self.firewalls_client.delete_firewall(fw_id)
|
|
||||||
# if firewall is not found, this means it was deleted in the test
|
|
||||||
except lib_exc.NotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.firewalls_client.wait_for_resource_deletion(fw_id)
|
|
||||||
|
|
||||||
def _wait_until_ready(self, fw_id):
|
|
||||||
target_states = ('ACTIVE', 'CREATED')
|
|
||||||
|
|
||||||
def _wait():
|
|
||||||
firewall = self.firewalls_client.show_firewall(fw_id)
|
|
||||||
firewall = firewall['firewall']
|
|
||||||
return firewall['status'] in target_states
|
|
||||||
|
|
||||||
if not test_utils.call_until_true(_wait, CONF.network.build_timeout,
|
|
||||||
CONF.network.build_interval):
|
|
||||||
m = ("Timed out waiting for firewall %s to reach %s state(s)" %
|
|
||||||
(fw_id, target_states))
|
|
||||||
raise lib_exc.TimeoutException(m)
|
|
||||||
|
|
||||||
def _wait_until_deleted(self, fw_id):
|
|
||||||
def _wait():
|
|
||||||
try:
|
|
||||||
firewall = self.firewalls_client.show_firewall(fw_id)
|
|
||||||
except lib_exc.NotFound:
|
|
||||||
return True
|
|
||||||
|
|
||||||
fw_status = firewall['firewall']['status']
|
|
||||||
if fw_status == 'ERROR':
|
|
||||||
raise lib_exc.DeleteErrorException(resource_id=fw_id)
|
|
||||||
|
|
||||||
if not test_utils.call_until_true(_wait, CONF.network.build_timeout,
|
|
||||||
CONF.network.build_interval):
|
|
||||||
m = ("Timed out waiting for firewall %s deleted" % fw_id)
|
|
||||||
raise lib_exc.TimeoutException(m)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('1b84cf01-9c09-4ce7-bc72-b15e39076468')
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
def test_list_firewall_rules(self):
|
|
||||||
# List firewall rules
|
|
||||||
fw_rules = self.firewall_rules_client.list_firewall_rules()
|
|
||||||
fw_rules = fw_rules['firewall_rules']
|
|
||||||
self.assertIn((self.fw_rule['id'],
|
|
||||||
self.fw_rule['name'],
|
|
||||||
self.fw_rule['action'],
|
|
||||||
self.fw_rule['protocol'],
|
|
||||||
self.fw_rule['ip_version'],
|
|
||||||
self.fw_rule['enabled']),
|
|
||||||
[(m['id'],
|
|
||||||
m['name'],
|
|
||||||
m['action'],
|
|
||||||
m['protocol'],
|
|
||||||
m['ip_version'],
|
|
||||||
m['enabled']) for m in fw_rules])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('563564f7-7077-4f5e-8cdc-51f37ae5a2b9')
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
def test_create_update_delete_firewall_rule(self):
|
|
||||||
# Create firewall rule
|
|
||||||
body = self.firewall_rules_client.create_firewall_rule(
|
|
||||||
name=data_utils.rand_name("fw-rule"),
|
|
||||||
action="allow",
|
|
||||||
protocol="tcp")
|
|
||||||
fw_rule_id = body['firewall_rule']['id']
|
|
||||||
self.addCleanup(self._try_delete_rule, fw_rule_id)
|
|
||||||
|
|
||||||
# Update firewall rule
|
|
||||||
body = self.firewall_rules_client.update_firewall_rule(fw_rule_id,
|
|
||||||
action="deny")
|
|
||||||
self.assertEqual("deny", body["firewall_rule"]['action'])
|
|
||||||
|
|
||||||
# Delete firewall rule
|
|
||||||
self.firewall_rules_client.delete_firewall_rule(fw_rule_id)
|
|
||||||
# Confirm deletion
|
|
||||||
fw_rules = self.firewall_rules_client.list_firewall_rules()
|
|
||||||
self.assertNotIn(fw_rule_id,
|
|
||||||
[m['id'] for m in fw_rules['firewall_rules']])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('3ff8c08e-26ff-4034-ae48-810ed213a998')
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
def test_show_firewall_rule(self):
|
|
||||||
# show a created firewall rule
|
|
||||||
fw_rule = self.firewall_rules_client.show_firewall_rule(
|
|
||||||
self.fw_rule['id'])
|
|
||||||
for key, value in six.iteritems(fw_rule['firewall_rule']):
|
|
||||||
self.assertEqual(self.fw_rule[key], value)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('1086dd93-a4c0-4bbb-a1bd-6d4bc62c199f')
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
def test_list_firewall_policies(self):
|
|
||||||
fw_policies = self.firewall_policies_client.list_firewall_policies()
|
|
||||||
fw_policies = fw_policies['firewall_policies']
|
|
||||||
self.assertIn((self.fw_policy['id'],
|
|
||||||
self.fw_policy['name'],
|
|
||||||
self.fw_policy['firewall_rules']),
|
|
||||||
[(m['id'],
|
|
||||||
m['name'],
|
|
||||||
m['firewall_rules']) for m in fw_policies])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('bbf37b6c-498c-421e-9c95-45897d3ed775')
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
def test_create_update_delete_firewall_policy(self):
|
|
||||||
# Create firewall policy
|
|
||||||
body = self.firewall_policies_client.create_firewall_policy(
|
|
||||||
name=data_utils.rand_name("fw-policy"))
|
|
||||||
fw_policy_id = body['firewall_policy']['id']
|
|
||||||
self.addCleanup(self._try_delete_policy, fw_policy_id)
|
|
||||||
|
|
||||||
# Update firewall policy
|
|
||||||
body = self.firewall_policies_client.update_firewall_policy(
|
|
||||||
fw_policy_id,
|
|
||||||
name="updated_policy")
|
|
||||||
updated_fw_policy = body["firewall_policy"]
|
|
||||||
self.assertEqual("updated_policy", updated_fw_policy['name'])
|
|
||||||
|
|
||||||
# Delete firewall policy
|
|
||||||
self.firewall_policies_client.delete_firewall_policy(fw_policy_id)
|
|
||||||
# Confirm deletion
|
|
||||||
fw_policies = self.firewall_policies_client.list_firewall_policies()
|
|
||||||
fw_policies = fw_policies['firewall_policies']
|
|
||||||
self.assertNotIn(fw_policy_id, [m['id'] for m in fw_policies])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('1df59b3a-517e-41d4-96f6-fc31cf4ecff2')
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
def test_show_firewall_policy(self):
|
|
||||||
# show a created firewall policy
|
|
||||||
fw_policy = self.firewall_policies_client.show_firewall_policy(
|
|
||||||
self.fw_policy['id'])
|
|
||||||
fw_policy = fw_policy['firewall_policy']
|
|
||||||
for key, value in six.iteritems(fw_policy):
|
|
||||||
self.assertEqual(self.fw_policy[key], value)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('02082a03-3cdd-4789-986a-1327dd80bfb7')
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
def test_create_show_delete_firewall(self):
|
|
||||||
# Create tenant network resources required for an ACTIVE firewall
|
|
||||||
network = self.create_network()
|
|
||||||
subnet = self.create_subnet(network)
|
|
||||||
router = self.create_router(
|
|
||||||
data_utils.rand_name('router-'),
|
|
||||||
admin_state_up=True)
|
|
||||||
self.addCleanup(self._try_delete_router, router)
|
|
||||||
self.routers_client.add_router_interface(router['id'],
|
|
||||||
subnet_id=subnet['id'])
|
|
||||||
|
|
||||||
# Create firewall
|
|
||||||
body = self.firewalls_client.create_firewall(
|
|
||||||
name=data_utils.rand_name("firewall"),
|
|
||||||
firewall_policy_id=self.fw_policy['id'])
|
|
||||||
created_firewall = body['firewall']
|
|
||||||
firewall_id = created_firewall['id']
|
|
||||||
self.addCleanup(self._try_delete_firewall, firewall_id)
|
|
||||||
|
|
||||||
# Wait for the firewall resource to become ready
|
|
||||||
self._wait_until_ready(firewall_id)
|
|
||||||
|
|
||||||
# show a created firewall
|
|
||||||
firewall = self.firewalls_client.show_firewall(firewall_id)
|
|
||||||
firewall = firewall['firewall']
|
|
||||||
|
|
||||||
for key, value in six.iteritems(firewall):
|
|
||||||
if key == 'status':
|
|
||||||
continue
|
|
||||||
self.assertEqual(created_firewall[key], value)
|
|
||||||
|
|
||||||
# list firewall
|
|
||||||
firewalls = self.firewalls_client.list_firewalls()
|
|
||||||
firewalls = firewalls['firewalls']
|
|
||||||
self.assertIn((created_firewall['id'],
|
|
||||||
created_firewall['name'],
|
|
||||||
created_firewall['firewall_policy_id']),
|
|
||||||
[(m['id'],
|
|
||||||
m['name'],
|
|
||||||
m['firewall_policy_id']) for m in firewalls])
|
|
||||||
|
|
||||||
# Delete firewall
|
|
||||||
self.firewalls_client.delete_firewall(firewall_id)
|
|
||||||
|
|
||||||
# Wait for the firewall resource to be deleted
|
|
||||||
self._wait_until_deleted(firewall_id)
|
|
||||||
|
|
||||||
# Confirm deletion
|
|
||||||
firewalls = self.firewalls_client.list_firewalls()['firewalls']
|
|
||||||
self.assertNotIn(firewall_id, [m['id'] for m in firewalls])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('1355cf5c-77d4-4bb9-87d7-e50c194d08b5')
|
|
||||||
def test_firewall_insertion_mode_add_remove_router(self):
|
|
||||||
# Create legacy routers
|
|
||||||
router1 = self.create_router(
|
|
||||||
data_utils.rand_name('router-'),
|
|
||||||
admin_state_up=True)
|
|
||||||
self.addCleanup(self._try_delete_router, router1)
|
|
||||||
router2 = self.create_router(
|
|
||||||
data_utils.rand_name('router-'),
|
|
||||||
admin_state_up=True)
|
|
||||||
self.addCleanup(self._try_delete_router, router2)
|
|
||||||
|
|
||||||
# Create firewall on a router1
|
|
||||||
body = self.firewalls_client.create_firewall(
|
|
||||||
name=data_utils.rand_name("firewall"),
|
|
||||||
firewall_policy_id=self.fw_policy['id'],
|
|
||||||
router_ids=[router1['id']])
|
|
||||||
created_firewall = body['firewall']
|
|
||||||
firewall_id = created_firewall['id']
|
|
||||||
self.addCleanup(self._try_delete_firewall, firewall_id)
|
|
||||||
|
|
||||||
self.assertEqual([router1['id']], created_firewall['router_ids'])
|
|
||||||
|
|
||||||
# Legacy routers are scheduled on L3 agents on network plug events
|
|
||||||
# Hence firewall resource will not became ready at this stage
|
|
||||||
network = self.create_network()
|
|
||||||
subnet = self.create_subnet(network)
|
|
||||||
self.routers_client.add_router_interface(router1['id'],
|
|
||||||
subnet_id=subnet['id'])
|
|
||||||
# Wait for the firewall resource to become ready
|
|
||||||
self._wait_until_ready(firewall_id)
|
|
||||||
|
|
||||||
# Add router2 to the firewall
|
|
||||||
body = self.firewalls_client.update_firewall(
|
|
||||||
firewall_id, router_ids=[router1['id'], router2['id']])
|
|
||||||
updated_firewall = body['firewall']
|
|
||||||
self.assertIn(router2['id'], updated_firewall['router_ids'])
|
|
||||||
self.assertEqual(2, len(updated_firewall['router_ids']))
|
|
||||||
|
|
||||||
# Wait for the firewall resource to become ready
|
|
||||||
self._wait_until_ready(firewall_id)
|
|
||||||
|
|
||||||
# Remove router1 from the firewall
|
|
||||||
body = self.firewalls_client.update_firewall(
|
|
||||||
firewall_id, router_ids=[router2['id']])
|
|
||||||
updated_firewall = body['firewall']
|
|
||||||
self.assertNotIn(router1['id'], updated_firewall['router_ids'])
|
|
||||||
self.assertEqual(1, len(updated_firewall['router_ids']))
|
|
||||||
|
|
||||||
@decorators.idempotent_id('c60ceff5-d51f-451d-b6e6-cb983d16ab6b')
|
|
||||||
def test_firewall_insertion_mode_one_firewall_per_router(self):
|
|
||||||
# Create router required for an ACTIVE firewall
|
|
||||||
router = self.create_router(
|
|
||||||
data_utils.rand_name('router1-'),
|
|
||||||
admin_state_up=True)
|
|
||||||
self.addCleanup(self._try_delete_router, router)
|
|
||||||
|
|
||||||
# Create firewall
|
|
||||||
body = self.firewalls_client.create_firewall(
|
|
||||||
name=data_utils.rand_name("firewall"),
|
|
||||||
firewall_policy_id=self.fw_policy['id'],
|
|
||||||
router_ids=[router['id']])
|
|
||||||
created_firewall = body['firewall']
|
|
||||||
self.addCleanup(self._try_delete_firewall, created_firewall['id'])
|
|
||||||
|
|
||||||
# Try to create firewall with the same router
|
|
||||||
self.assertRaisesRegex(
|
|
||||||
lib_exc.Conflict,
|
|
||||||
"already associated with other firewall",
|
|
||||||
self.firewalls_client.create_firewall,
|
|
||||||
name=data_utils.rand_name("firewall"),
|
|
||||||
firewall_policy_id=self.fw_policy['id'],
|
|
||||||
router_ids=[router['id']])
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('53305b4b-9897-4e01-87c0-2ae386083180')
|
|
||||||
def test_firewall_rule_insertion_position_removal_rule_from_policy(self):
|
|
||||||
# Create firewall rule
|
|
||||||
body = self.firewall_rules_client.create_firewall_rule(
|
|
||||||
name=data_utils.rand_name("fw-rule"),
|
|
||||||
action="allow",
|
|
||||||
protocol="tcp")
|
|
||||||
fw_rule_id1 = body['firewall_rule']['id']
|
|
||||||
self.addCleanup(self._try_delete_rule, fw_rule_id1)
|
|
||||||
# Create firewall policy
|
|
||||||
body = self.firewall_policies_client.create_firewall_policy(
|
|
||||||
name=data_utils.rand_name("fw-policy"))
|
|
||||||
fw_policy_id = body['firewall_policy']['id']
|
|
||||||
self.addCleanup(self._try_delete_policy, fw_policy_id)
|
|
||||||
|
|
||||||
# Insert rule to firewall policy
|
|
||||||
self.firewall_policies_client.insert_firewall_rule_in_policy(
|
|
||||||
fw_policy_id, fw_rule_id1, '', '')
|
|
||||||
|
|
||||||
# Verify insertion of rule in policy
|
|
||||||
self.assertIn(fw_rule_id1, self._get_list_fw_rule_ids(fw_policy_id))
|
|
||||||
# Create another firewall rule
|
|
||||||
body = self.firewall_rules_client.create_firewall_rule(
|
|
||||||
name=data_utils.rand_name("fw-rule"),
|
|
||||||
action="allow",
|
|
||||||
protocol="icmp")
|
|
||||||
fw_rule_id2 = body['firewall_rule']['id']
|
|
||||||
self.addCleanup(self._try_delete_rule, fw_rule_id2)
|
|
||||||
|
|
||||||
# Insert rule to firewall policy after the first rule
|
|
||||||
self.firewall_policies_client.insert_firewall_rule_in_policy(
|
|
||||||
fw_policy_id, fw_rule_id2, fw_rule_id1, '')
|
|
||||||
|
|
||||||
# Verify the position of rule after insertion
|
|
||||||
fw_rule = self.firewall_rules_client.show_firewall_rule(
|
|
||||||
fw_rule_id2)
|
|
||||||
|
|
||||||
self.assertEqual(int(fw_rule['firewall_rule']['position']), 2)
|
|
||||||
# Remove rule from the firewall policy
|
|
||||||
self.firewall_policies_client.remove_firewall_rule_from_policy(
|
|
||||||
fw_policy_id, fw_rule_id2)
|
|
||||||
# Insert rule to firewall policy before the first rule
|
|
||||||
self.firewall_policies_client.insert_firewall_rule_in_policy(
|
|
||||||
fw_policy_id, fw_rule_id2, '', fw_rule_id1)
|
|
||||||
# Verify the position of rule after insertion
|
|
||||||
fw_rule = self.firewall_rules_client.show_firewall_rule(
|
|
||||||
fw_rule_id2)
|
|
||||||
self.assertEqual(int(fw_rule['firewall_rule']['position']), 1)
|
|
||||||
# Remove rule from the firewall policy
|
|
||||||
self.firewall_policies_client.remove_firewall_rule_from_policy(
|
|
||||||
fw_policy_id, fw_rule_id2)
|
|
||||||
# Verify removal of rule from firewall policy
|
|
||||||
self.assertNotIn(fw_rule_id2, self._get_list_fw_rule_ids(fw_policy_id))
|
|
||||||
|
|
||||||
# Remove rule from the firewall policy
|
|
||||||
self.firewall_policies_client.remove_firewall_rule_from_policy(
|
|
||||||
fw_policy_id, fw_rule_id1)
|
|
||||||
|
|
||||||
# Verify removal of rule from firewall policy
|
|
||||||
self.assertNotIn(fw_rule_id1, self._get_list_fw_rule_ids(fw_policy_id))
|
|
||||||
|
|
||||||
def _get_list_fw_rule_ids(self, fw_policy_id):
|
|
||||||
fw_policy = self.firewall_policies_client.show_firewall_policy(
|
|
||||||
fw_policy_id)
|
|
||||||
return [ruleid for ruleid in fw_policy['firewall_policy']
|
|
||||||
['firewall_rules']]
|
|
||||||
|
|
||||||
@decorators.idempotent_id('8515ca8a-0d2f-4298-b5ff-6f924e4587ca')
|
|
||||||
def test_update_firewall_policy_audited_attribute(self):
|
|
||||||
# Create firewall rule
|
|
||||||
body = self.firewall_rules_client.create_firewall_rule(
|
|
||||||
name=data_utils.rand_name("fw-rule"),
|
|
||||||
action="allow",
|
|
||||||
protocol="icmp")
|
|
||||||
fw_rule_id = body['firewall_rule']['id']
|
|
||||||
self.addCleanup(self._try_delete_rule, fw_rule_id)
|
|
||||||
# Create firewall policy
|
|
||||||
body = self.firewall_policies_client.create_firewall_policy(
|
|
||||||
name=data_utils.rand_name('fw-policy'))
|
|
||||||
fw_policy_id = body['firewall_policy']['id']
|
|
||||||
self.addCleanup(self._try_delete_policy, fw_policy_id)
|
|
||||||
self.assertFalse(body['firewall_policy']['audited'])
|
|
||||||
# Update firewall policy audited attribute to true
|
|
||||||
self.firewall_policies_client.update_firewall_policy(fw_policy_id,
|
|
||||||
audited=True)
|
|
||||||
# Insert Firewall rule to firewall policy
|
|
||||||
self.firewall_policies_client.insert_firewall_rule_in_policy(
|
|
||||||
fw_policy_id, fw_rule_id, '', '')
|
|
||||||
body = self.firewall_policies_client.show_firewall_policy(
|
|
||||||
fw_policy_id)
|
|
||||||
self.assertFalse(body['firewall_policy']['audited'])
|
|
@ -1,122 +0,0 @@
|
|||||||
# Copyright (c) 2015 Midokura SARL
|
|
||||||
# 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 time
|
|
||||||
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib.common.utils import test_utils
|
|
||||||
from tempest.lib import exceptions as lib_exc
|
|
||||||
|
|
||||||
from neutron_fwaas.tests.tempest_plugin.services import client
|
|
||||||
from neutron_lib import constants as nl_constants
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class FWaaSClientMixin(object):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(FWaaSClientMixin, cls).resource_setup()
|
|
||||||
manager = cls.os_primary
|
|
||||||
default_params = config.service_client_config()
|
|
||||||
cls.firewalls_client = client.FirewallsClient(
|
|
||||||
manager.auth_provider,
|
|
||||||
CONF.network.catalog_type,
|
|
||||||
CONF.network.region or CONF.identity.region,
|
|
||||||
endpoint_type=CONF.network.endpoint_type,
|
|
||||||
build_interval=CONF.network.build_interval,
|
|
||||||
build_timeout=CONF.network.build_timeout,
|
|
||||||
**default_params)
|
|
||||||
cls.firewall_policies_client = client.FirewallPoliciesClient(
|
|
||||||
manager.auth_provider,
|
|
||||||
CONF.network.catalog_type,
|
|
||||||
CONF.network.region or CONF.identity.region,
|
|
||||||
endpoint_type=CONF.network.endpoint_type,
|
|
||||||
build_interval=CONF.network.build_interval,
|
|
||||||
build_timeout=CONF.network.build_timeout,
|
|
||||||
**default_params)
|
|
||||||
cls.firewall_rules_client = client.FirewallRulesClient(
|
|
||||||
manager.auth_provider,
|
|
||||||
CONF.network.catalog_type,
|
|
||||||
CONF.network.region or CONF.identity.region,
|
|
||||||
endpoint_type=CONF.network.endpoint_type,
|
|
||||||
build_interval=CONF.network.build_interval,
|
|
||||||
build_timeout=CONF.network.build_timeout,
|
|
||||||
**default_params)
|
|
||||||
|
|
||||||
def create_firewall_rule(self, **kwargs):
|
|
||||||
body = self.firewall_rules_client.create_firewall_rule(
|
|
||||||
name=data_utils.rand_name("fw-rule"),
|
|
||||||
**kwargs)
|
|
||||||
fw_rule = body['firewall_rule']
|
|
||||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
|
||||||
self.firewall_rules_client.delete_firewall_rule,
|
|
||||||
fw_rule['id'])
|
|
||||||
return fw_rule
|
|
||||||
|
|
||||||
def create_firewall_policy(self, **kwargs):
|
|
||||||
body = self.firewall_policies_client.create_firewall_policy(
|
|
||||||
name=data_utils.rand_name("fw-policy"),
|
|
||||||
**kwargs)
|
|
||||||
fw_policy = body['firewall_policy']
|
|
||||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
|
||||||
self.firewall_policies_client.delete_firewall_policy,
|
|
||||||
fw_policy['id'])
|
|
||||||
return fw_policy
|
|
||||||
|
|
||||||
def create_firewall(self, **kwargs):
|
|
||||||
body = self.firewalls_client.create_firewall(
|
|
||||||
name=data_utils.rand_name("fw"),
|
|
||||||
**kwargs)
|
|
||||||
fw = body['firewall']
|
|
||||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
|
||||||
self.delete_firewall_and_wait,
|
|
||||||
fw['id'])
|
|
||||||
return fw
|
|
||||||
|
|
||||||
def delete_firewall_and_wait(self, firewall_id):
|
|
||||||
self.firewalls_client.delete_firewall(firewall_id)
|
|
||||||
self._wait_firewall_while(firewall_id, [nl_constants.PENDING_DELETE],
|
|
||||||
not_found_ok=True)
|
|
||||||
|
|
||||||
def _wait_firewall_ready(self, firewall_id):
|
|
||||||
self._wait_firewall_while(firewall_id,
|
|
||||||
[nl_constants.PENDING_CREATE,
|
|
||||||
nl_constants.PENDING_UPDATE])
|
|
||||||
|
|
||||||
def _wait_firewall_while(self, firewall_id, statuses, not_found_ok=False):
|
|
||||||
start = int(time.time())
|
|
||||||
if not_found_ok:
|
|
||||||
expected_exceptions = (lib_exc.NotFound)
|
|
||||||
else:
|
|
||||||
expected_exceptions = ()
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
fw = self.firewalls_client.show_firewall(firewall_id)
|
|
||||||
except expected_exceptions:
|
|
||||||
break
|
|
||||||
status = fw['firewall']['status']
|
|
||||||
if status not in statuses:
|
|
||||||
break
|
|
||||||
if int(time.time()) - start >= self.firewalls_client.build_timeout:
|
|
||||||
msg = ("Firewall %(firewall)s failed to reach "
|
|
||||||
"non PENDING status (current %(status)s)") % {
|
|
||||||
"firewall": firewall_id,
|
|
||||||
"status": status,
|
|
||||||
}
|
|
||||||
raise lib_exc.TimeoutException(msg)
|
|
||||||
time.sleep(1)
|
|
@ -17,7 +17,6 @@ from tempest import config
|
|||||||
from tempest.lib.common import ssh
|
from tempest.lib.common import ssh
|
||||||
from tempest.lib import exceptions as lib_exc
|
from tempest.lib import exceptions as lib_exc
|
||||||
|
|
||||||
from neutron_fwaas.tests.tempest_plugin.tests import fwaas_client
|
|
||||||
from neutron_fwaas.tests.tempest_plugin.tests import fwaas_v2_client
|
from neutron_fwaas.tests.tempest_plugin.tests import fwaas_v2_client
|
||||||
from neutron_fwaas.tests.tempest_plugin.tests.scenario import manager
|
from neutron_fwaas.tests.tempest_plugin.tests.scenario import manager
|
||||||
|
|
||||||
@ -64,12 +63,6 @@ class FWaaSScenarioTestBase(object):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
class FWaaSScenarioTest(fwaas_client.FWaaSClientMixin,
|
|
||||||
FWaaSScenarioTestBase,
|
|
||||||
manager.NetworkScenarioTest):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class FWaaSScenarioTest_V2(fwaas_v2_client.FWaaSClientMixin,
|
class FWaaSScenarioTest_V2(fwaas_v2_client.FWaaSClientMixin,
|
||||||
FWaaSScenarioTestBase,
|
FWaaSScenarioTestBase,
|
||||||
manager.NetworkScenarioTest):
|
manager.NetworkScenarioTest):
|
||||||
|
@ -1,379 +0,0 @@
|
|||||||
# Copyright (c) 2015 Midokura SARL
|
|
||||||
# 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 testscenarios
|
|
||||||
|
|
||||||
from tempest.common import utils
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib import decorators
|
|
||||||
|
|
||||||
from neutron_fwaas.tests.tempest_plugin.tests.scenario import base
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
load_tests = testscenarios.load_tests_apply_scenarios
|
|
||||||
|
|
||||||
|
|
||||||
class TestFWaaS(base.FWaaSScenarioTest):
|
|
||||||
scenarios = [
|
|
||||||
('without router insersion', {
|
|
||||||
'router_insertion': False,
|
|
||||||
}),
|
|
||||||
('with router insersion', {
|
|
||||||
'router_insertion': True,
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestFWaaS, self).setUp()
|
|
||||||
required_exts = ['fwaas', 'security-group', 'router']
|
|
||||||
if self.router_insertion:
|
|
||||||
required_exts.append('fwaasrouterinsertion')
|
|
||||||
for ext in required_exts:
|
|
||||||
if not utils.is_extension_enabled(ext, 'network'):
|
|
||||||
msg = "%s Extension not enabled." % ext
|
|
||||||
raise self.skipException(msg)
|
|
||||||
self._router_ids = None
|
|
||||||
|
|
||||||
def _create_server(self, network, security_group=None):
|
|
||||||
keys = self.create_keypair()
|
|
||||||
kwargs = {}
|
|
||||||
if security_group is not None:
|
|
||||||
kwargs['security_groups'] = [{'name': security_group['name']}]
|
|
||||||
server = self.create_server(
|
|
||||||
key_name=keys['name'],
|
|
||||||
networks=[{'uuid': network['id']}],
|
|
||||||
wait_until='ACTIVE',
|
|
||||||
**kwargs)
|
|
||||||
return server, keys
|
|
||||||
|
|
||||||
def _create_firewall(self, **kwargs):
|
|
||||||
if self._router_ids is not None:
|
|
||||||
kwargs['router_ids'] = self._router_ids
|
|
||||||
return self.create_firewall(**kwargs)
|
|
||||||
|
|
||||||
def _empty_policy(self, **kwargs):
|
|
||||||
# NOTE(yamamoto): an empty policy would deny all
|
|
||||||
fw_policy = self.create_firewall_policy(firewall_rules=[])
|
|
||||||
fw = self._create_firewall(firewall_policy_id=fw_policy['id'])
|
|
||||||
self._wait_firewall_ready(fw['id'])
|
|
||||||
return {
|
|
||||||
'fw': fw,
|
|
||||||
'fw_policy': fw_policy,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _all_disabled_rules(self, **kwargs):
|
|
||||||
# NOTE(yamamoto): a policy whose rules are all disabled would deny all
|
|
||||||
fw_rule = self.create_firewall_rule(action="allow", enabled=False)
|
|
||||||
fw_policy = self.create_firewall_policy(firewall_rules=[fw_rule['id']])
|
|
||||||
fw = self._create_firewall(firewall_policy_id=fw_policy['id'])
|
|
||||||
self._wait_firewall_ready(fw['id'])
|
|
||||||
return {
|
|
||||||
'fw': fw,
|
|
||||||
'fw_policy': fw_policy,
|
|
||||||
'fw_rule': fw_rule,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _block_ip(self, server1_fixed_ip, server2_fixed_ip, **kwargs):
|
|
||||||
rules = [
|
|
||||||
# NOTE(yamamoto): The filtering is taken place after
|
|
||||||
# destination ip is rewritten to fixed-ip.
|
|
||||||
self.create_firewall_rule(destination_ip_address=server1_fixed_ip,
|
|
||||||
action="deny"),
|
|
||||||
self.create_firewall_rule(destination_ip_address=server2_fixed_ip,
|
|
||||||
action="deny"),
|
|
||||||
self.create_firewall_rule(action="allow"),
|
|
||||||
]
|
|
||||||
rule_ids = [r['id'] for r in rules]
|
|
||||||
fw_policy = self.create_firewall_policy(firewall_rules=rule_ids)
|
|
||||||
fw = self._create_firewall(firewall_policy_id=fw_policy['id'])
|
|
||||||
self._wait_firewall_ready(fw['id'])
|
|
||||||
return {
|
|
||||||
'fw': fw,
|
|
||||||
'fw_policy': fw_policy,
|
|
||||||
'server1_fixed_ip': server1_fixed_ip,
|
|
||||||
'server2_fixed_ip': server2_fixed_ip,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _block_icmp(self, **kwargs):
|
|
||||||
fw_rule = self.create_firewall_rule(
|
|
||||||
protocol="icmp",
|
|
||||||
action="deny")
|
|
||||||
fw_rule_allow = self.create_firewall_rule(
|
|
||||||
action="allow")
|
|
||||||
fw_policy = self.create_firewall_policy(
|
|
||||||
firewall_rules=[fw_rule['id'], fw_rule_allow['id']])
|
|
||||||
fw = self._create_firewall(firewall_policy_id=fw_policy['id'])
|
|
||||||
self._wait_firewall_ready(fw['id'])
|
|
||||||
return {
|
|
||||||
'fw': fw,
|
|
||||||
'fw_policy': fw_policy,
|
|
||||||
'fw_rule': fw_rule,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _block_all_with_default_allow(self, **kwargs):
|
|
||||||
fw_rule = self.create_firewall_rule(
|
|
||||||
action="deny")
|
|
||||||
fw_rule_allow = self.create_firewall_rule(
|
|
||||||
action="allow")
|
|
||||||
fw_policy = self.create_firewall_policy(
|
|
||||||
firewall_rules=[fw_rule['id'], fw_rule_allow['id']])
|
|
||||||
fw = self._create_firewall(firewall_policy_id=fw_policy['id'])
|
|
||||||
self._wait_firewall_ready(fw['id'])
|
|
||||||
return {
|
|
||||||
'fw': fw,
|
|
||||||
'fw_policy': fw_policy,
|
|
||||||
'fw_rule': fw_rule,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _admin_disable(self, **kwargs):
|
|
||||||
# NOTE(yamamoto): A firewall with admin_state_up=False would block all
|
|
||||||
fw_rule = self.create_firewall_rule(action="allow")
|
|
||||||
fw_policy = self.create_firewall_policy(firewall_rules=[fw_rule['id']])
|
|
||||||
fw = self._create_firewall(firewall_policy_id=fw_policy['id'],
|
|
||||||
admin_state_up=False)
|
|
||||||
self._wait_firewall_ready(fw['id'])
|
|
||||||
return {
|
|
||||||
'fw': fw,
|
|
||||||
'fw_policy': fw_policy,
|
|
||||||
'fw_rule': fw_rule,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _allow_ssh_and_icmp(self, ctx):
|
|
||||||
fw_ssh_rule = self.create_firewall_rule(
|
|
||||||
protocol="tcp",
|
|
||||||
destination_port=22,
|
|
||||||
action="allow")
|
|
||||||
fw_icmp_rule = self.create_firewall_rule(
|
|
||||||
protocol="icmp",
|
|
||||||
action="allow")
|
|
||||||
for rule in [fw_ssh_rule, fw_icmp_rule]:
|
|
||||||
self.firewall_policies_client.insert_firewall_rule_in_policy(
|
|
||||||
firewall_policy_id=ctx['fw_policy']['id'],
|
|
||||||
firewall_rule_id=rule['id'],
|
|
||||||
insert_before=ctx['fw_rule']['id'])
|
|
||||||
self.addCleanup(
|
|
||||||
self._remove_rule_and_wait,
|
|
||||||
firewall_id=ctx['fw']['id'],
|
|
||||||
firewall_policy_id=ctx['fw_policy']['id'],
|
|
||||||
firewall_rule_id=rule['id'])
|
|
||||||
self._wait_firewall_ready(ctx['fw']['id'])
|
|
||||||
|
|
||||||
def _remove_rule_and_wait(self, firewall_id, firewall_policy_id,
|
|
||||||
firewall_rule_id):
|
|
||||||
self.firewall_policies_client.remove_firewall_rule_from_policy(
|
|
||||||
firewall_policy_id=firewall_policy_id,
|
|
||||||
firewall_rule_id=firewall_rule_id)
|
|
||||||
self._wait_firewall_ready(firewall_id)
|
|
||||||
|
|
||||||
def _delete_fw(self, ctx):
|
|
||||||
self.delete_firewall_and_wait(ctx['fw']['id'])
|
|
||||||
|
|
||||||
def _set_admin_up(self, firewall_id, up):
|
|
||||||
self.firewalls_client.update_firewall(firewall_id=firewall_id,
|
|
||||||
admin_state_up=up)
|
|
||||||
self._wait_firewall_ready(firewall_id=firewall_id)
|
|
||||||
|
|
||||||
def _admin_enable(self, ctx):
|
|
||||||
self._set_admin_up(ctx['fw']['id'], up=True)
|
|
||||||
|
|
||||||
def _remove_rule(self, ctx):
|
|
||||||
self._remove_rule_and_wait(
|
|
||||||
firewall_id=ctx['fw']['id'],
|
|
||||||
firewall_policy_id=ctx['fw_policy']['id'],
|
|
||||||
firewall_rule_id=ctx['fw_rule']['id'])
|
|
||||||
|
|
||||||
def _disable_rule(self, ctx):
|
|
||||||
self.firewall_rules_client.update_firewall_rule(
|
|
||||||
firewall_rule_id=ctx['fw_rule']['id'],
|
|
||||||
enabled=False)
|
|
||||||
self._wait_firewall_ready(ctx['fw']['id'])
|
|
||||||
|
|
||||||
def _allow_ip(self, ctx):
|
|
||||||
self._delete_fw(ctx)
|
|
||||||
server1_fixed_ip = ctx['server1_fixed_ip']
|
|
||||||
server2_fixed_ip = ctx['server2_fixed_ip']
|
|
||||||
rules = [
|
|
||||||
# NOTE(yamamoto): The filtering is taken place after
|
|
||||||
# destination ip is rewritten to fixed-ip.
|
|
||||||
# The return traffic should be allowed regardless
|
|
||||||
# of firewall rules.
|
|
||||||
self.create_firewall_rule(
|
|
||||||
destination_ip_address=server1_fixed_ip,
|
|
||||||
action="allow"),
|
|
||||||
self.create_firewall_rule(
|
|
||||||
destination_ip_address=server2_fixed_ip,
|
|
||||||
action="allow"),
|
|
||||||
]
|
|
||||||
rule_ids = [r['id'] for r in rules]
|
|
||||||
fw_policy = self.create_firewall_policy(firewall_rules=rule_ids)
|
|
||||||
fw = self._create_firewall(firewall_policy_id=fw_policy['id'])
|
|
||||||
self._wait_firewall_ready(fw['id'])
|
|
||||||
|
|
||||||
def _confirm_allowed(self, **kwargs):
|
|
||||||
self.check_connectivity(check_reverse_icmp_ip=self._public_gateway_ip,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def _confirm_allowed_oneway(self, **kwargs):
|
|
||||||
# Can ping and ssh, but can't ping back to the public gateway.
|
|
||||||
# Same as _confirm_allowed if _public_gateway_ip is None.
|
|
||||||
self.check_connectivity(check_reverse_icmp_ip=self._public_gateway_ip,
|
|
||||||
should_reverse_connect=False, **kwargs)
|
|
||||||
|
|
||||||
def _confirm_blocked(self, **kwargs):
|
|
||||||
self.check_connectivity(should_connect=False, **kwargs)
|
|
||||||
|
|
||||||
def _confirm_icmp_blocked_but_tcp(self, **kwargs):
|
|
||||||
self.check_connectivity(should_connect=False, check_ssh=False,
|
|
||||||
**kwargs)
|
|
||||||
self.check_connectivity(check_icmp=False, **kwargs)
|
|
||||||
|
|
||||||
def _create_topology(self):
|
|
||||||
"""Create a topology for testing
|
|
||||||
|
|
||||||
+--------+ +-----------+
|
|
||||||
|"server"| | "subnet" |
|
|
||||||
| VM +-------------+ "network" |
|
|
||||||
+--------+ +----+------+
|
|
||||||
|
|
|
||||||
| router interface port
|
|
||||||
+----+-----+
|
|
||||||
| "router" |
|
|
||||||
+----+-----+
|
|
||||||
| router gateway port
|
|
||||||
|
|
|
||||||
|
|
|
||||||
+----+------------------+
|
|
||||||
| existing network |
|
|
||||||
| ("public_network_id") |
|
|
||||||
+-----------------------+
|
|
||||||
"""
|
|
||||||
public_network_id = CONF.network.public_network_id
|
|
||||||
network, subnet, router = self.create_networks()
|
|
||||||
security_group = self._create_security_group()
|
|
||||||
server, keys = self._create_server(network,
|
|
||||||
security_group=security_group)
|
|
||||||
private_key = keys['private_key']
|
|
||||||
server_floating_ip = self.create_floating_ip(server, public_network_id)
|
|
||||||
fixed_ip = list(server['addresses'].values())[0][0]['addr']
|
|
||||||
floating_ip = server_floating_ip['floating_ip_address']
|
|
||||||
return fixed_ip, floating_ip, private_key, router
|
|
||||||
|
|
||||||
def _get_public_gateway_ip(self):
|
|
||||||
self._public_gateway_ip = None
|
|
||||||
router = self._get_router()
|
|
||||||
ext_gw_info = router['external_gateway_info']
|
|
||||||
ext_fixed_ips = ext_gw_info['external_fixed_ips']
|
|
||||||
for ip in ext_fixed_ips:
|
|
||||||
subnet_id = ip['subnet_id']
|
|
||||||
res = self.os_admin.subnets_client.show_subnet(subnet_id)
|
|
||||||
subnet = res['subnet']
|
|
||||||
# REVISIT(yamamoto): IPv4 assumption
|
|
||||||
if subnet['ip_version'] == 4:
|
|
||||||
self._public_gateway_ip = subnet['gateway_ip']
|
|
||||||
return
|
|
||||||
|
|
||||||
def _test_firewall_basic(self, block, allow=None,
|
|
||||||
confirm_allowed=None, confirm_blocked=None):
|
|
||||||
if allow is None:
|
|
||||||
allow = self._delete_fw
|
|
||||||
if confirm_allowed is None:
|
|
||||||
confirm_allowed = self._confirm_allowed
|
|
||||||
if confirm_blocked is None:
|
|
||||||
confirm_blocked = self._confirm_blocked
|
|
||||||
ssh_login = CONF.validation.image_ssh_user
|
|
||||||
|
|
||||||
if self.router_insertion and CONF.network.public_router_id:
|
|
||||||
# NOTE(yamamoto): If public_router_id is configured
|
|
||||||
# router1 and router2 will be the same router.
|
|
||||||
msg = "This test assumes no public_router_id configured"
|
|
||||||
raise self.skipException(msg)
|
|
||||||
|
|
||||||
server1_fixed_ip, server1_floating_ip, private_key1, router1 = \
|
|
||||||
self._create_topology()
|
|
||||||
server2_fixed_ip, server2_floating_ip, private_key2, router2 = \
|
|
||||||
self._create_topology()
|
|
||||||
self._get_public_gateway_ip()
|
|
||||||
if self.router_insertion:
|
|
||||||
# Specify the router when creating a firewall and ensures that
|
|
||||||
# the other router (router2) is not affected by the firewall
|
|
||||||
self._router_ids = [router1['id']]
|
|
||||||
confirm_allowed2 = self.check_connectivity
|
|
||||||
confirm_blocked2 = self.check_connectivity
|
|
||||||
else:
|
|
||||||
# Without router insertion, all routers should be affected
|
|
||||||
# equally
|
|
||||||
confirm_allowed2 = confirm_allowed
|
|
||||||
confirm_blocked2 = confirm_blocked
|
|
||||||
self.check_connectivity(ip_address=server1_floating_ip,
|
|
||||||
username=ssh_login,
|
|
||||||
private_key=private_key1)
|
|
||||||
self.check_connectivity(ip_address=server2_floating_ip,
|
|
||||||
username=ssh_login,
|
|
||||||
private_key=private_key2)
|
|
||||||
ctx = block(server1_fixed_ip=server1_fixed_ip,
|
|
||||||
server1_floating_ip=server1_floating_ip,
|
|
||||||
server2_fixed_ip=server2_fixed_ip,
|
|
||||||
server2_floating_ip=server2_floating_ip)
|
|
||||||
confirm_blocked(ip_address=server1_floating_ip, username=ssh_login,
|
|
||||||
private_key=private_key1)
|
|
||||||
confirm_blocked2(ip_address=server2_floating_ip, username=ssh_login,
|
|
||||||
private_key=private_key2)
|
|
||||||
allow(ctx)
|
|
||||||
confirm_allowed(ip_address=server1_floating_ip, username=ssh_login,
|
|
||||||
private_key=private_key1)
|
|
||||||
confirm_allowed2(ip_address=server2_floating_ip, username=ssh_login,
|
|
||||||
private_key=private_key2)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('f970f6b3-6541-47ac-a9ea-f769be1e21a8')
|
|
||||||
def test_firewall_block_ip(self):
|
|
||||||
self._test_firewall_basic(block=self._block_ip, allow=self._allow_ip,
|
|
||||||
confirm_allowed=self._confirm_allowed_oneway)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('b985d010-994a-4055-bd5c-9e961464ccde')
|
|
||||||
def test_firewall_block_icmp(self):
|
|
||||||
self._test_firewall_basic(
|
|
||||||
block=self._block_icmp,
|
|
||||||
confirm_blocked=self._confirm_icmp_blocked_but_tcp)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('ca473af0-26f9-4fad-9550-1c34371c900e')
|
|
||||||
def test_firewall_insert_rule(self):
|
|
||||||
self._test_firewall_basic(
|
|
||||||
block=self._block_icmp,
|
|
||||||
allow=self._allow_ssh_and_icmp,
|
|
||||||
confirm_blocked=self._confirm_icmp_blocked_but_tcp)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('54a937a6-cecf-444c-b3f9-b67a1c1b7411')
|
|
||||||
def test_firewall_remove_rule(self):
|
|
||||||
self._test_firewall_basic(block=self._block_all_with_default_allow,
|
|
||||||
allow=self._remove_rule)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('12a18776-9b60-4479-9988-f45971c96a92')
|
|
||||||
def test_firewall_disable_rule(self):
|
|
||||||
self._test_firewall_basic(block=self._block_all_with_default_allow,
|
|
||||||
allow=self._disable_rule)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('a2a58c1f-49ad-4b5f-9463-e746b9efe08a')
|
|
||||||
def test_firewall_empty_policy(self):
|
|
||||||
self._test_firewall_basic(block=self._empty_policy)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('477a47e0-5156-4784-9417-f77970d85c36')
|
|
||||||
def test_firewall_all_disabled_rules(self):
|
|
||||||
self._test_firewall_basic(block=self._all_disabled_rules)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('a83f51c5-1a18-4d2a-a778-c368e4d95c29')
|
|
||||||
def test_firewall_admin_disable(self):
|
|
||||||
self._test_firewall_basic(block=self._admin_disable,
|
|
||||||
allow=self._admin_enable)
|
|
File diff suppressed because it is too large
Load Diff
@ -1,412 +0,0 @@
|
|||||||
# Copyright 2013 Dell Inc.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import copy
|
|
||||||
|
|
||||||
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.service_drivers.agents.drivers.linux.\
|
|
||||||
iptables_fwaas as fwaas
|
|
||||||
|
|
||||||
|
|
||||||
_uuid = test_api_v2._uuid
|
|
||||||
FAKE_SRC_PREFIX = '10.0.0.0/24'
|
|
||||||
FAKE_DST_PREFIX = '20.0.0.0/24'
|
|
||||||
FAKE_PROTOCOL = 'tcp'
|
|
||||||
FAKE_SRC_PORT = 5000
|
|
||||||
FAKE_DST_PORT = 22
|
|
||||||
FAKE_FW_ID = 'fake-fw-uuid'
|
|
||||||
FW_LEGACY = 'legacy'
|
|
||||||
|
|
||||||
|
|
||||||
class IptablesFwaasTestCase(base.BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(IptablesFwaasTestCase, self).setUp()
|
|
||||||
self.conntrack_driver = mock.Mock()
|
|
||||||
self.conntrack_driver.initialize = mock.Mock()
|
|
||||||
self.conntrack_driver.delete_entries = mock.Mock()
|
|
||||||
self.conntrack_driver.flush_entries = mock.Mock()
|
|
||||||
self.iptables_cls_p = mock.patch(
|
|
||||||
'neutron.agent.linux.iptables_manager.IptablesManager')
|
|
||||||
self.iptables_cls_p.start()
|
|
||||||
self.firewall = fwaas.IptablesFwaasDriver()
|
|
||||||
self.firewall.conntrack = self.conntrack_driver
|
|
||||||
|
|
||||||
def _fake_rules_v4(self, fwid, apply_list):
|
|
||||||
rule_list = []
|
|
||||||
rule1 = {'enabled': True,
|
|
||||||
'action': 'allow',
|
|
||||||
'ip_version': 4,
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'destination_port': '80',
|
|
||||||
'source_ip_address': '10.24.4.2',
|
|
||||||
'id': 'fake-fw-rule1'}
|
|
||||||
rule2 = {'enabled': True,
|
|
||||||
'action': 'deny',
|
|
||||||
'ip_version': 4,
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'destination_port': '22',
|
|
||||||
'id': 'fake-fw-rule2'}
|
|
||||||
rule3 = {'enabled': True,
|
|
||||||
'action': 'reject',
|
|
||||||
'ip_version': 4,
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'destination_port': '23',
|
|
||||||
'id': 'fake-fw-rule3'}
|
|
||||||
ingress_chain = ('iv4%s' % fwid)[:11]
|
|
||||||
egress_chain = ('ov4%s' % fwid)[:11]
|
|
||||||
for router_info_inst in apply_list:
|
|
||||||
v4filter_inst = router_info_inst.iptables_manager.ipv4['filter']
|
|
||||||
v4filter_inst.chains.append(ingress_chain)
|
|
||||||
v4filter_inst.chains.append(egress_chain)
|
|
||||||
rule_list.append(rule1)
|
|
||||||
rule_list.append(rule2)
|
|
||||||
rule_list.append(rule3)
|
|
||||||
return rule_list
|
|
||||||
|
|
||||||
def _fake_firewall_no_rule(self):
|
|
||||||
rule_list = []
|
|
||||||
fw_inst = {'id': FAKE_FW_ID,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'tenant_id': 'tenant-uuid',
|
|
||||||
'firewall_rule_list': rule_list}
|
|
||||||
return fw_inst
|
|
||||||
|
|
||||||
def _fake_firewall(self, rule_list):
|
|
||||||
_rule_list = copy.deepcopy(rule_list)
|
|
||||||
for rule in _rule_list:
|
|
||||||
rule['position'] = str(_rule_list.index(rule))
|
|
||||||
fw_inst = {'id': FAKE_FW_ID,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'tenant_id': 'tenant-uuid',
|
|
||||||
'firewall_rule_list': _rule_list}
|
|
||||||
return fw_inst
|
|
||||||
|
|
||||||
def _fake_firewall_with_admin_down(self, rule_list):
|
|
||||||
fw_inst = {'id': FAKE_FW_ID,
|
|
||||||
'admin_state_up': False,
|
|
||||||
'tenant_id': 'tenant-uuid',
|
|
||||||
'firewall_rule_list': rule_list}
|
|
||||||
return fw_inst
|
|
||||||
|
|
||||||
def _fake_apply_list(self, router_count=1, distributed=False,
|
|
||||||
distributed_mode=None):
|
|
||||||
apply_list = []
|
|
||||||
while router_count > 0:
|
|
||||||
iptables_inst = mock.Mock()
|
|
||||||
if distributed is not None:
|
|
||||||
router_inst = {'distributed': distributed}
|
|
||||||
else:
|
|
||||||
router_inst = {}
|
|
||||||
v4filter_inst = mock.Mock()
|
|
||||||
v6filter_inst = mock.Mock()
|
|
||||||
v4filter_inst.chains = []
|
|
||||||
v6filter_inst.chains = []
|
|
||||||
iptables_inst.ipv4 = {'filter': v4filter_inst}
|
|
||||||
iptables_inst.ipv6 = {'filter': v6filter_inst}
|
|
||||||
router_info_inst = mock.Mock()
|
|
||||||
router_info_inst.iptables_manager = iptables_inst
|
|
||||||
router_info_inst.snat_iptables_manager = iptables_inst
|
|
||||||
if distributed_mode == 'dvr':
|
|
||||||
router_info_inst.rtr_fip_connect = True
|
|
||||||
router_info_inst.router = router_inst
|
|
||||||
apply_list.append(router_info_inst)
|
|
||||||
router_count -= 1
|
|
||||||
return apply_list
|
|
||||||
|
|
||||||
def _setup_firewall_with_rules(self, func, router_count=1,
|
|
||||||
distributed=False, distributed_mode=None):
|
|
||||||
apply_list = self._fake_apply_list(router_count=router_count,
|
|
||||||
distributed=distributed, distributed_mode=distributed_mode)
|
|
||||||
rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list)
|
|
||||||
firewall = self._fake_firewall(rule_list)
|
|
||||||
if distributed:
|
|
||||||
if distributed_mode == 'dvr_snat':
|
|
||||||
if_prefix = 'sg-+'
|
|
||||||
if distributed_mode == 'dvr':
|
|
||||||
if_prefix = 'rfp-+'
|
|
||||||
else:
|
|
||||||
if_prefix = 'qr-+'
|
|
||||||
distributed_mode = 'legacy'
|
|
||||||
func(distributed_mode, apply_list, firewall)
|
|
||||||
invalid_rule = '-m state --state INVALID -j DROP'
|
|
||||||
est_rule = '-m state --state RELATED,ESTABLISHED -j ACCEPT'
|
|
||||||
rule1 = '-p tcp -s 10.24.4.2/32 -m tcp --dport 80 -j ACCEPT'
|
|
||||||
rule2 = '-p tcp -m tcp --dport 22 -j DROP'
|
|
||||||
rule3 = '-p tcp -m tcp --dport 23 -j REJECT'
|
|
||||||
ingress_chain = 'iv4%s' % firewall['id']
|
|
||||||
egress_chain = 'ov4%s' % firewall['id']
|
|
||||||
bname = fwaas.iptables_manager.binary_name
|
|
||||||
ipt_mgr_ichain = '%s-%s' % (bname, ingress_chain[:11])
|
|
||||||
ipt_mgr_echain = '%s-%s' % (bname, egress_chain[:11])
|
|
||||||
for router_info_inst in apply_list:
|
|
||||||
v4filter_inst = router_info_inst.iptables_manager.ipv4['filter']
|
|
||||||
calls = [mock.call.remove_chain('iv4fake-fw-uuid'),
|
|
||||||
mock.call.remove_chain('ov4fake-fw-uuid'),
|
|
||||||
mock.call.remove_chain('fwaas-default-policy'),
|
|
||||||
mock.call.add_chain('fwaas-default-policy'),
|
|
||||||
mock.call.add_rule('fwaas-default-policy', '-j DROP'),
|
|
||||||
mock.call.add_chain(ingress_chain),
|
|
||||||
mock.call.add_rule(ingress_chain, invalid_rule),
|
|
||||||
mock.call.add_rule(ingress_chain, est_rule),
|
|
||||||
mock.call.add_chain(egress_chain),
|
|
||||||
mock.call.add_rule(egress_chain, invalid_rule),
|
|
||||||
mock.call.add_rule(egress_chain, est_rule),
|
|
||||||
mock.call.add_rule(ingress_chain, rule1),
|
|
||||||
mock.call.add_rule(egress_chain, rule1),
|
|
||||||
mock.call.add_rule(ingress_chain, rule2),
|
|
||||||
mock.call.add_rule(egress_chain, rule2),
|
|
||||||
mock.call.add_rule(ingress_chain, rule3),
|
|
||||||
mock.call.add_rule(egress_chain, rule3),
|
|
||||||
mock.call.add_rule('FORWARD',
|
|
||||||
'-o %s -j %s' % (if_prefix,
|
|
||||||
ipt_mgr_ichain)),
|
|
||||||
mock.call.add_rule('FORWARD',
|
|
||||||
'-i %s -j %s' % (if_prefix,
|
|
||||||
ipt_mgr_echain)),
|
|
||||||
mock.call.add_rule('FORWARD',
|
|
||||||
'-o %s -j %s-fwaas-defau' % (if_prefix,
|
|
||||||
bname)),
|
|
||||||
mock.call.add_rule('FORWARD',
|
|
||||||
'-i %s -j %s-fwaas-defau' % (if_prefix,
|
|
||||||
bname))]
|
|
||||||
v4filter_inst.assert_has_calls(calls)
|
|
||||||
|
|
||||||
def test_create_firewall_no_rules(self):
|
|
||||||
apply_list = self._fake_apply_list()
|
|
||||||
firewall = self._fake_firewall_no_rule()
|
|
||||||
self.firewall.create_firewall('legacy', apply_list, firewall)
|
|
||||||
invalid_rule = '-m state --state INVALID -j DROP'
|
|
||||||
est_rule = '-m state --state RELATED,ESTABLISHED -j ACCEPT'
|
|
||||||
bname = fwaas.iptables_manager.binary_name
|
|
||||||
for ip_version in (4, 6):
|
|
||||||
ingress_chain = ('iv%s%s' % (ip_version, firewall['id']))
|
|
||||||
egress_chain = ('ov%s%s' % (ip_version, firewall['id']))
|
|
||||||
calls = [mock.call.remove_chain(
|
|
||||||
'iv%sfake-fw-uuid' % ip_version),
|
|
||||||
mock.call.remove_chain(
|
|
||||||
'ov%sfake-fw-uuid' % ip_version),
|
|
||||||
mock.call.remove_chain('fwaas-default-policy'),
|
|
||||||
mock.call.add_chain('fwaas-default-policy'),
|
|
||||||
mock.call.add_rule('fwaas-default-policy', '-j DROP'),
|
|
||||||
mock.call.add_chain(ingress_chain),
|
|
||||||
mock.call.add_rule(ingress_chain, invalid_rule),
|
|
||||||
mock.call.add_rule(ingress_chain, est_rule),
|
|
||||||
mock.call.add_chain(egress_chain),
|
|
||||||
mock.call.add_rule(egress_chain, invalid_rule),
|
|
||||||
mock.call.add_rule(egress_chain, est_rule),
|
|
||||||
mock.call.add_rule('FORWARD',
|
|
||||||
'-o qr-+ -j %s-fwaas-defau' % bname),
|
|
||||||
mock.call.add_rule('FORWARD',
|
|
||||||
'-i qr-+ -j %s-fwaas-defau' % bname)]
|
|
||||||
if ip_version == 4:
|
|
||||||
v4filter_inst = apply_list[0].iptables_manager.ipv4['filter']
|
|
||||||
v4filter_inst.assert_has_calls(calls)
|
|
||||||
else:
|
|
||||||
v6filter_inst = apply_list[0].iptables_manager.ipv6['filter']
|
|
||||||
v6filter_inst.assert_has_calls(calls)
|
|
||||||
|
|
||||||
def test_create_firewall_with_rules(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.create_firewall)
|
|
||||||
|
|
||||||
def test_create_firewall_with_rules_without_distributed_attr(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.create_firewall,
|
|
||||||
distributed=None)
|
|
||||||
|
|
||||||
def test_create_firewall_with_rules_two_routers(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.create_firewall,
|
|
||||||
router_count=2)
|
|
||||||
|
|
||||||
def test_update_firewall_with_rules(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.update_firewall)
|
|
||||||
|
|
||||||
def test_update_firewall_with_rules_without_distributed_attr(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.update_firewall,
|
|
||||||
distributed=None)
|
|
||||||
|
|
||||||
def _test_delete_firewall(self, distributed=False):
|
|
||||||
apply_list = self._fake_apply_list(distributed=distributed)
|
|
||||||
firewall = self._fake_firewall_no_rule()
|
|
||||||
self.firewall.delete_firewall('legacy', apply_list, firewall)
|
|
||||||
ingress_chain = 'iv4%s' % firewall['id']
|
|
||||||
egress_chain = 'ov4%s' % firewall['id']
|
|
||||||
calls = [mock.call.remove_chain(ingress_chain),
|
|
||||||
mock.call.remove_chain(egress_chain),
|
|
||||||
mock.call.remove_chain('fwaas-default-policy')]
|
|
||||||
apply_list[0].iptables_manager.ipv4['filter'].assert_has_calls(calls)
|
|
||||||
|
|
||||||
def test_delete_firewall(self):
|
|
||||||
self._test_delete_firewall()
|
|
||||||
|
|
||||||
def test_delete_firewall_without_distributed_attr(self):
|
|
||||||
self._test_delete_firewall(distributed=None)
|
|
||||||
|
|
||||||
def test_create_firewall_with_admin_down(self):
|
|
||||||
apply_list = self._fake_apply_list()
|
|
||||||
rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list)
|
|
||||||
firewall = self._fake_firewall_with_admin_down(rule_list)
|
|
||||||
self.firewall.create_firewall('legacy', apply_list, firewall)
|
|
||||||
calls = [mock.call.remove_chain('iv4fake-fw-uuid'),
|
|
||||||
mock.call.remove_chain('ov4fake-fw-uuid'),
|
|
||||||
mock.call.remove_chain('fwaas-default-policy'),
|
|
||||||
mock.call.add_chain('fwaas-default-policy'),
|
|
||||||
mock.call.add_rule('fwaas-default-policy', '-j DROP')]
|
|
||||||
apply_list[0].iptables_manager.ipv4['filter'].assert_has_calls(calls)
|
|
||||||
|
|
||||||
def test_create_firewall_with_rules_dvr_snat(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.create_firewall,
|
|
||||||
distributed=True, distributed_mode='dvr_snat')
|
|
||||||
|
|
||||||
def test_update_firewall_with_rules_dvr_snat(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.update_firewall,
|
|
||||||
distributed=True, distributed_mode='dvr_snat')
|
|
||||||
|
|
||||||
def test_create_firewall_with_rules_dvr(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.create_firewall,
|
|
||||||
distributed=True, distributed_mode='dvr')
|
|
||||||
|
|
||||||
def test_update_firewall_with_rules_dvr(self):
|
|
||||||
self._setup_firewall_with_rules(self.firewall.update_firewall,
|
|
||||||
distributed=True, distributed_mode='dvr')
|
|
||||||
|
|
||||||
def test_remove_conntrack_new_firewall(self):
|
|
||||||
apply_list = self._fake_apply_list()
|
|
||||||
firewall = self._fake_firewall_no_rule()
|
|
||||||
self.firewall.create_firewall(FW_LEGACY, apply_list, firewall)
|
|
||||||
for router_info_inst in apply_list:
|
|
||||||
namespace = router_info_inst.iptables_manager.namespace
|
|
||||||
calls = [mock.call(namespace)]
|
|
||||||
self.conntrack_driver.flush_entries.assert_has_calls(calls)
|
|
||||||
|
|
||||||
def test_remove_conntrack_inserted_rule(self):
|
|
||||||
apply_list = self._fake_apply_list()
|
|
||||||
rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list)
|
|
||||||
firewall = self._fake_firewall(rule_list)
|
|
||||||
self.firewall.create_firewall(FW_LEGACY, apply_list, firewall)
|
|
||||||
self.firewall.pre_firewall = dict(firewall)
|
|
||||||
insert_rule = {'enabled': True,
|
|
||||||
'action': 'deny',
|
|
||||||
'ip_version': 4,
|
|
||||||
'protocol': 'icmp',
|
|
||||||
'id': 'fake-fw-rule'}
|
|
||||||
rule_list.insert(2, insert_rule)
|
|
||||||
firewall = self._fake_firewall(rule_list)
|
|
||||||
self.firewall.update_firewall(FW_LEGACY, apply_list, firewall)
|
|
||||||
rules_changed = [
|
|
||||||
{'destination_port': '23',
|
|
||||||
'position': '2',
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'ip_version': 4,
|
|
||||||
'enabled': True,
|
|
||||||
'action': 'reject',
|
|
||||||
'id': 'fake-fw-rule3'},
|
|
||||||
{'destination_port': '23',
|
|
||||||
'position': '3',
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'ip_version': 4,
|
|
||||||
'enabled': True,
|
|
||||||
'action': 'reject',
|
|
||||||
'id': 'fake-fw-rule3'}
|
|
||||||
]
|
|
||||||
rules_inserted = [
|
|
||||||
{'id': 'fake-fw-rule',
|
|
||||||
'protocol': 'icmp',
|
|
||||||
'ip_version': 4,
|
|
||||||
'enabled': True,
|
|
||||||
'action': 'deny',
|
|
||||||
'position': '2'}
|
|
||||||
]
|
|
||||||
for router_info_inst in apply_list:
|
|
||||||
namespace = router_info_inst.iptables_manager.namespace
|
|
||||||
self.conntrack_driver.delete_entries.assert_called_once_with(
|
|
||||||
rules_changed + rules_inserted, namespace
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_remove_conntrack_removed_rule(self):
|
|
||||||
apply_list = self._fake_apply_list()
|
|
||||||
rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list)
|
|
||||||
firewall = self._fake_firewall(rule_list)
|
|
||||||
self.firewall.create_firewall(FW_LEGACY, apply_list, firewall)
|
|
||||||
self.firewall.pre_firewall = dict(firewall)
|
|
||||||
remove_rule = rule_list[1]
|
|
||||||
rule_list.remove(remove_rule)
|
|
||||||
firewall = self._fake_firewall(rule_list)
|
|
||||||
self.firewall.update_firewall(FW_LEGACY, apply_list, firewall)
|
|
||||||
rules_changed = [
|
|
||||||
{'destination_port': '23',
|
|
||||||
'position': '2',
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'ip_version': 4,
|
|
||||||
'enabled': True,
|
|
||||||
'action': 'reject',
|
|
||||||
'id': 'fake-fw-rule3'},
|
|
||||||
{'destination_port': '23',
|
|
||||||
'position': '1',
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'ip_version': 4,
|
|
||||||
'enabled': True,
|
|
||||||
'action': 'reject',
|
|
||||||
'id': 'fake-fw-rule3'}
|
|
||||||
]
|
|
||||||
rules_removed = [
|
|
||||||
{'enabled': True,
|
|
||||||
'position': '1',
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'id': 'fake-fw-rule2',
|
|
||||||
'ip_version': 4,
|
|
||||||
'action': 'deny',
|
|
||||||
'destination_port': '22'}
|
|
||||||
]
|
|
||||||
for router_info_inst in apply_list:
|
|
||||||
namespace = router_info_inst.iptables_manager.namespace
|
|
||||||
self.conntrack_driver.delete_entries.assert_called_once_with(
|
|
||||||
rules_changed + rules_removed, namespace
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_remove_conntrack_changed_rule(self):
|
|
||||||
apply_list = self._fake_apply_list()
|
|
||||||
rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list)
|
|
||||||
firewall = self._fake_firewall(rule_list)
|
|
||||||
self.firewall.create_firewall(FW_LEGACY, apply_list, firewall)
|
|
||||||
income_rule = {'enabled': True,
|
|
||||||
'action': 'deny',
|
|
||||||
'ip_version': 4,
|
|
||||||
'protocol': 'tcp',
|
|
||||||
'id': 'fake-fw-rule3'}
|
|
||||||
rule_list[2] = income_rule
|
|
||||||
firewall = self._fake_firewall(rule_list)
|
|
||||||
self.firewall.update_firewall(FW_LEGACY, apply_list, firewall)
|
|
||||||
rules_changed = [
|
|
||||||
{'id': 'fake-fw-rule3',
|
|
||||||
'enabled': True,
|
|
||||||
'action': 'reject',
|
|
||||||
'position': '2',
|
|
||||||
'destination_port': '23',
|
|
||||||
'ip_version': 4,
|
|
||||||
'protocol': 'tcp'},
|
|
||||||
{'position': '2',
|
|
||||||
'enabled': True,
|
|
||||||
'action': 'deny',
|
|
||||||
'id': 'fake-fw-rule3',
|
|
||||||
'ip_version': 4,
|
|
||||||
'protocol': 'tcp'}
|
|
||||||
]
|
|
||||||
for router_info_inst in apply_list:
|
|
||||||
namespace = router_info_inst.iptables_manager.namespace
|
|
||||||
self.conntrack_driver.delete_entries.assert_called_once_with(
|
|
||||||
rules_changed, namespace
|
|
||||||
)
|
|
@ -1,361 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
import mock
|
|
||||||
from neutron.agent.l3 import l3_agent_extension_api as l3_agent_api
|
|
||||||
from neutron.agent.l3 import router_info
|
|
||||||
from neutron.agent.linux import ip_lib
|
|
||||||
from neutron.conf.agent.l3 import config as l3_config
|
|
||||||
from neutron.conf import common as base_config
|
|
||||||
from neutron_lib import context
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_utils import uuidutils
|
|
||||||
import testtools
|
|
||||||
|
|
||||||
from neutron_fwaas.common import fwaas_constants
|
|
||||||
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.service_drivers.agents \
|
|
||||||
import test_firewall_agent_api
|
|
||||||
|
|
||||||
|
|
||||||
class FWaasHelper(object):
|
|
||||||
def __init__(self, host):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class FWaasAgent(firewall_l3_agent.FWaaSL3AgentExtension, FWaasHelper):
|
|
||||||
neutron_service_plugins = []
|
|
||||||
|
|
||||||
|
|
||||||
def _setup_test_agent_class(service_plugins):
|
|
||||||
class FWaasTestAgent(firewall_l3_agent.FWaaSL3AgentExtension,
|
|
||||||
FWaasHelper):
|
|
||||||
neutron_service_plugins = service_plugins
|
|
||||||
|
|
||||||
def __init__(self, conf):
|
|
||||||
self.event_observers = mock.Mock()
|
|
||||||
self.conf = conf
|
|
||||||
super(FWaasTestAgent, self).__init__("myhost", conf)
|
|
||||||
|
|
||||||
return FWaasTestAgent
|
|
||||||
|
|
||||||
|
|
||||||
class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestFwaasL3AgentRpcCallback, self).setUp()
|
|
||||||
|
|
||||||
self.conf = cfg.ConfigOpts()
|
|
||||||
self.conf.register_opts(base_config.core_opts)
|
|
||||||
self.conf.register_opts(l3_config.OPTS)
|
|
||||||
self.conf.register_opts(firewall_agent_api.FWaaSOpts, 'fwaas')
|
|
||||||
self.api = FWaasAgent(host=None, conf=self.conf)
|
|
||||||
self.api.fwaas_driver = test_firewall_agent_api.NoopFwaasDriver()
|
|
||||||
self.adminContext = context.get_admin_context()
|
|
||||||
self.router_id = uuidutils.generate_uuid()
|
|
||||||
self.agent_conf = mock.Mock()
|
|
||||||
# For 'tenant_id' and 'project_id' keys
|
|
||||||
project_id = uuidutils.generate_uuid()
|
|
||||||
self.ri_kwargs = {'router': {'id': self.router_id,
|
|
||||||
'tenant_id': project_id,
|
|
||||||
'project_id': project_id},
|
|
||||||
'agent_conf': self.agent_conf,
|
|
||||||
'interface_driver': mock.ANY,
|
|
||||||
'use_ipv6': mock.ANY,
|
|
||||||
}
|
|
||||||
|
|
||||||
def test_fw_config_match(self):
|
|
||||||
test_agent_class = _setup_test_agent_class([fwaas_constants.FIREWALL])
|
|
||||||
cfg.CONF.set_override('enabled', True, 'fwaas')
|
|
||||||
with mock.patch('oslo_utils.importutils.import_object'):
|
|
||||||
test_agent_class(cfg.CONF)
|
|
||||||
|
|
||||||
@testtools.skip('needs to be refactored for fwaas v2')
|
|
||||||
def test_fw_config_mismatch_plugin_enabled_agent_disabled(self):
|
|
||||||
test_agent_class = _setup_test_agent_class([fwaas_constants.FIREWALL])
|
|
||||||
cfg.CONF.set_override('enabled', False, 'fwaas')
|
|
||||||
self.assertRaises(SystemExit, test_agent_class, cfg.CONF)
|
|
||||||
|
|
||||||
def test_fw_plugin_list_unavailable(self):
|
|
||||||
test_agent_class = _setup_test_agent_class(None)
|
|
||||||
cfg.CONF.set_override('enabled', False, 'fwaas')
|
|
||||||
with mock.patch('oslo_utils.importutils.import_object'):
|
|
||||||
test_agent_class(cfg.CONF)
|
|
||||||
|
|
||||||
def test_create_firewall(self):
|
|
||||||
fake_firewall = {'id': 0, 'tenant_id': 1,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'add-router-ids': [1, 2]}
|
|
||||||
self.api.plugin_rpc = mock.Mock()
|
|
||||||
with mock.patch.object(self.api, '_get_router_info_list_for_tenant'
|
|
||||||
) as mock_get_router_info_list_for_tenant, \
|
|
||||||
mock.patch.object(self.api.fwaas_driver, 'create_firewall'
|
|
||||||
) as mock_driver_create_firewall, \
|
|
||||||
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status'
|
|
||||||
) as mock_set_firewall_status:
|
|
||||||
mock_driver_create_firewall.return_value = True
|
|
||||||
self.api.create_firewall(
|
|
||||||
context=mock.sentinel.context,
|
|
||||||
firewall=fake_firewall, host='host')
|
|
||||||
|
|
||||||
mock_get_router_info_list_for_tenant.assert_called_once_with(
|
|
||||||
fake_firewall['add-router-ids'], fake_firewall['tenant_id'])
|
|
||||||
|
|
||||||
mock_set_firewall_status.assert_called_once_with(
|
|
||||||
mock.sentinel.context,
|
|
||||||
fake_firewall['id'],
|
|
||||||
'ACTIVE')
|
|
||||||
|
|
||||||
def test_update_firewall_with_routers_added_and_deleted(self):
|
|
||||||
fake_firewall = {'id': 0, 'tenant_id': 1,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'add-router-ids': [1, 2],
|
|
||||||
'del-router-ids': [3, 4],
|
|
||||||
'router_ids': [],
|
|
||||||
'last-router': False}
|
|
||||||
|
|
||||||
self.api.plugin_rpc = mock.Mock()
|
|
||||||
with mock.patch.object(self.api, '_get_router_info_list_for_tenant'
|
|
||||||
) as mock_get_router_info_list_for_tenant, \
|
|
||||||
mock.patch.object(self.api.fwaas_driver, 'update_firewall'
|
|
||||||
) as mock_driver_delete_firewall, \
|
|
||||||
mock.patch.object(self.api.fwaas_driver, 'delete_firewall'
|
|
||||||
) as mock_driver_update_firewall, \
|
|
||||||
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status'
|
|
||||||
) as mock_set_firewall_status:
|
|
||||||
|
|
||||||
mock_driver_delete_firewall.return_value = True
|
|
||||||
mock_driver_update_firewall.return_value = True
|
|
||||||
|
|
||||||
calls = [mock.call(fake_firewall['del-router-ids'],
|
|
||||||
fake_firewall['tenant_id']),
|
|
||||||
mock.call(fake_firewall['add-router-ids'],
|
|
||||||
fake_firewall['tenant_id'])]
|
|
||||||
|
|
||||||
self.api.update_firewall(
|
|
||||||
context=mock.sentinel.context,
|
|
||||||
firewall=fake_firewall, host='host')
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
mock_get_router_info_list_for_tenant.call_args_list,
|
|
||||||
calls)
|
|
||||||
|
|
||||||
mock_set_firewall_status.assert_called_once_with(
|
|
||||||
mock.sentinel.context,
|
|
||||||
fake_firewall['id'],
|
|
||||||
'ACTIVE')
|
|
||||||
|
|
||||||
def test_update_firewall_with_routers_added_and_admin_state_down(self):
|
|
||||||
fake_firewall = {'id': 0, 'tenant_id': 1,
|
|
||||||
'admin_state_up': False,
|
|
||||||
'add-router-ids': [1, 2],
|
|
||||||
'del-router-ids': [],
|
|
||||||
'router_ids': [],
|
|
||||||
'last-router': False}
|
|
||||||
|
|
||||||
self.api.plugin_rpc = mock.Mock()
|
|
||||||
with mock.patch.object(self.api, '_get_router_info_list_for_tenant'
|
|
||||||
) as mock_get_router_info_list_for_tenant, \
|
|
||||||
mock.patch.object(self.api.fwaas_driver, 'update_firewall'
|
|
||||||
) as mock_driver_update_firewall, \
|
|
||||||
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status'
|
|
||||||
) as mock_set_firewall_status:
|
|
||||||
|
|
||||||
mock_driver_update_firewall.return_value = True
|
|
||||||
|
|
||||||
self.api.update_firewall(
|
|
||||||
context=mock.sentinel.context,
|
|
||||||
firewall=fake_firewall, host='host')
|
|
||||||
|
|
||||||
mock_get_router_info_list_for_tenant.assert_called_once_with(
|
|
||||||
fake_firewall['add-router-ids'], fake_firewall['tenant_id'])
|
|
||||||
|
|
||||||
mock_set_firewall_status.assert_called_once_with(
|
|
||||||
mock.sentinel.context,
|
|
||||||
fake_firewall['id'],
|
|
||||||
'DOWN')
|
|
||||||
|
|
||||||
def test_update_firewall_with_all_routers_deleted(self):
|
|
||||||
fake_firewall = {'id': 0, 'tenant_id': 1,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'add-router-ids': [],
|
|
||||||
'del-router-ids': [3, 4],
|
|
||||||
'last-router': True}
|
|
||||||
|
|
||||||
self.api.plugin_rpc = mock.Mock()
|
|
||||||
with mock.patch.object(self.api, '_get_router_info_list_for_tenant'
|
|
||||||
) as mock_get_router_info_list_for_tenant, \
|
|
||||||
mock.patch.object(self.api.fwaas_driver, 'delete_firewall'
|
|
||||||
) as mock_driver_delete_firewall, \
|
|
||||||
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status'
|
|
||||||
) as mock_set_firewall_status:
|
|
||||||
|
|
||||||
mock_driver_delete_firewall.return_value = True
|
|
||||||
|
|
||||||
self.api.update_firewall(
|
|
||||||
context=mock.sentinel.context,
|
|
||||||
firewall=fake_firewall, host='host')
|
|
||||||
|
|
||||||
mock_get_router_info_list_for_tenant.assert_called_once_with(
|
|
||||||
fake_firewall['del-router-ids'], fake_firewall['tenant_id'])
|
|
||||||
|
|
||||||
mock_set_firewall_status.assert_called_once_with(
|
|
||||||
mock.sentinel.context,
|
|
||||||
fake_firewall['id'],
|
|
||||||
'INACTIVE')
|
|
||||||
|
|
||||||
def test_update_firewall_with_rtrs_and_no_rtrs_added_nor_deleted(self):
|
|
||||||
fake_firewall = {'id': 0, 'tenant_id': 1,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'add-router-ids': [],
|
|
||||||
'del-router-ids': [],
|
|
||||||
'router_ids': [1, 2]}
|
|
||||||
self.api.plugin_rpc = mock.Mock()
|
|
||||||
with mock.patch.object(self.api.fwaas_driver, 'update_firewall'
|
|
||||||
) as mock_driver_update_firewall, \
|
|
||||||
mock.patch.object(self.api, '_get_router_info_list_for_tenant'
|
|
||||||
) as mock_get_router_info_list_for_tenant, \
|
|
||||||
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status'
|
|
||||||
) as mock_set_firewall_status:
|
|
||||||
|
|
||||||
mock_driver_update_firewall.return_value = True
|
|
||||||
|
|
||||||
self.api.update_firewall(
|
|
||||||
context=mock.sentinel.context,
|
|
||||||
firewall=fake_firewall, host='host')
|
|
||||||
|
|
||||||
mock_get_router_info_list_for_tenant.assert_called_once_with(
|
|
||||||
fake_firewall['router_ids'], fake_firewall['tenant_id'])
|
|
||||||
|
|
||||||
mock_set_firewall_status.assert_called_once_with(
|
|
||||||
mock.sentinel.context,
|
|
||||||
fake_firewall['id'],
|
|
||||||
'ACTIVE')
|
|
||||||
|
|
||||||
def test_update_firewall_with_no_rtrs_and_no_rtrs_added_nor_deleted(self):
|
|
||||||
fake_firewall = {'id': 0, 'tenant_id': 1,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'add-router-ids': [],
|
|
||||||
'del-router-ids': [],
|
|
||||||
'router_ids': []}
|
|
||||||
self.api.plugin_rpc = mock.Mock()
|
|
||||||
with mock.patch.object(self.api.fwaas_driver, 'update_firewall'
|
|
||||||
) as mock_driver_update_firewall, \
|
|
||||||
mock.patch.object(self.api.fwplugin_rpc, 'set_firewall_status'
|
|
||||||
) as mock_set_firewall_status:
|
|
||||||
|
|
||||||
mock_driver_update_firewall.return_value = True
|
|
||||||
|
|
||||||
self.api.update_firewall(
|
|
||||||
context=mock.sentinel.context,
|
|
||||||
firewall=fake_firewall, host='host')
|
|
||||||
|
|
||||||
mock_set_firewall_status.assert_called_once_with(
|
|
||||||
mock.sentinel.context,
|
|
||||||
fake_firewall['id'],
|
|
||||||
'INACTIVE')
|
|
||||||
|
|
||||||
def test_delete_firewall(self):
|
|
||||||
fake_firewall = {'id': 0, 'tenant_id': 1,
|
|
||||||
'admin_state_up': True,
|
|
||||||
'add-router-ids': [],
|
|
||||||
'del-router-ids': [3, 4],
|
|
||||||
'last-router': True}
|
|
||||||
|
|
||||||
self.api.plugin_rpc = mock.Mock()
|
|
||||||
with mock.patch.object(self.api, '_get_router_info_list_for_tenant'
|
|
||||||
) as mock_get_router_info_list_for_tenant, \
|
|
||||||
mock.patch.object(self.api.fwaas_driver, 'delete_firewall'
|
|
||||||
) as mock_driver_delete_firewall, \
|
|
||||||
mock.patch.object(self.api.fwplugin_rpc, 'firewall_deleted'
|
|
||||||
) as mock_firewall_deleted:
|
|
||||||
|
|
||||||
mock_driver_delete_firewall.return_value = True
|
|
||||||
self.api.delete_firewall(
|
|
||||||
context=mock.sentinel.context,
|
|
||||||
firewall=fake_firewall, host='host')
|
|
||||||
|
|
||||||
mock_get_router_info_list_for_tenant.assert_called_once_with(
|
|
||||||
fake_firewall['del-router-ids'], fake_firewall['tenant_id'])
|
|
||||||
|
|
||||||
mock_firewall_deleted.assert_called_once_with(
|
|
||||||
mock.sentinel.context,
|
|
||||||
fake_firewall['id'])
|
|
||||||
|
|
||||||
def _prepare_router_data(self):
|
|
||||||
return router_info.RouterInfo(self.api,
|
|
||||||
self.router_id,
|
|
||||||
**self.ri_kwargs)
|
|
||||||
|
|
||||||
def test_get_router_info_list_for_tenant(self):
|
|
||||||
ri = self._prepare_router_data()
|
|
||||||
router_info = {ri.router_id: ri}
|
|
||||||
self.api.router_info = router_info
|
|
||||||
|
|
||||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
|
||||||
self.api.consume_api(api_object)
|
|
||||||
|
|
||||||
routers = [ri.router]
|
|
||||||
router_ids = [router['id'] for router in routers]
|
|
||||||
|
|
||||||
with mock.patch.object(ip_lib,
|
|
||||||
'list_network_namespaces') as mock_list_netns:
|
|
||||||
mock_list_netns.return_value = []
|
|
||||||
router_info_list = self.api._get_router_info_list_for_tenant(
|
|
||||||
router_ids,
|
|
||||||
ri.router['tenant_id'])
|
|
||||||
mock_list_netns.assert_called_once_with()
|
|
||||||
self.assertFalse(router_info_list)
|
|
||||||
|
|
||||||
def _get_router_info_list_router_without_router_info_helper(self,
|
|
||||||
rtr_with_ri):
|
|
||||||
# ri.router with associated router_info (ri)
|
|
||||||
# rtr2 has no router_info
|
|
||||||
|
|
||||||
ri = self._prepare_router_data()
|
|
||||||
rtr2 = {'id': uuidutils.generate_uuid(),
|
|
||||||
'tenant_id': ri.router['tenant_id']}
|
|
||||||
|
|
||||||
routers = [rtr2]
|
|
||||||
router_info = {}
|
|
||||||
ri_expected = []
|
|
||||||
|
|
||||||
if rtr_with_ri:
|
|
||||||
router_info[ri.router_id] = ri
|
|
||||||
routers.append(ri.router)
|
|
||||||
ri_expected.append(ri)
|
|
||||||
|
|
||||||
self.api.router_info = router_info
|
|
||||||
router_ids = [router['id'] for router in routers]
|
|
||||||
|
|
||||||
with mock.patch.object(ip_lib,
|
|
||||||
'list_network_namespaces') as mock_list_netns:
|
|
||||||
mock_list_netns.return_value = [ri.ns_name]
|
|
||||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
|
||||||
self.api.consume_api(api_object)
|
|
||||||
router_info_list = self.api._get_router_info_list_for_tenant(
|
|
||||||
router_ids,
|
|
||||||
ri.router['tenant_id'])
|
|
||||||
self.assertEqual(ri_expected, router_info_list)
|
|
||||||
|
|
||||||
def test_get_router_info_list_router_without_router_info(self):
|
|
||||||
self._get_router_info_list_router_without_router_info_helper(
|
|
||||||
rtr_with_ri=False)
|
|
||||||
|
|
||||||
def test_get_router_info_list_two_routers_one_without_router_info(self):
|
|
||||||
self._get_router_info_list_router_without_router_info_helper(
|
|
||||||
rtr_with_ri=True)
|
|
@ -1,786 +0,0 @@
|
|||||||
# Copyright 2013 Big Switch Networks, Inc.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import mock
|
|
||||||
from neutron.api import extensions as api_ext
|
|
||||||
from neutron.common import config
|
|
||||||
from neutron.tests.common import helpers
|
|
||||||
from neutron.tests.unit.extensions import test_agent
|
|
||||||
from neutron.tests.unit.extensions import test_l3 as test_l3_plugin
|
|
||||||
from neutron_lib.api import attributes as attr
|
|
||||||
from neutron_lib.api.definitions import firewall as fwaas_def
|
|
||||||
from neutron_lib.api.definitions import firewallrouterinsertion
|
|
||||||
from neutron_lib import constants as nl_constants
|
|
||||||
from neutron_lib import context
|
|
||||||
from neutron_lib.exceptions import firewall_v1 as f_exc
|
|
||||||
from neutron_lib.plugins import constants as plugin_constants
|
|
||||||
from neutron_lib.plugins import directory
|
|
||||||
from neutron_lib.tests.unit import fake_notifier
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_utils import uuidutils
|
|
||||||
import six
|
|
||||||
from webob import exc
|
|
||||||
|
|
||||||
from neutron_fwaas.db.firewall import firewall_db as fdb
|
|
||||||
import neutron_fwaas.extensions
|
|
||||||
from neutron_fwaas.extensions import firewall
|
|
||||||
from neutron_fwaas.services.firewall import fwaas_plugin
|
|
||||||
from neutron_fwaas.tests import base
|
|
||||||
from neutron_fwaas.tests.unit.db.firewall import (
|
|
||||||
test_firewall_db as test_db_firewall)
|
|
||||||
|
|
||||||
extensions_path = neutron_fwaas.extensions.__path__[0]
|
|
||||||
|
|
||||||
FW_PLUGIN_KLASS = (
|
|
||||||
"neutron_fwaas.services.firewall.fwaas_plugin.FirewallPlugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class FirewallTestExtensionManager(test_l3_plugin.L3TestExtensionManager):
|
|
||||||
|
|
||||||
def get_resources(self):
|
|
||||||
res = super(FirewallTestExtensionManager, self).get_resources()
|
|
||||||
fwaas_def.RESOURCE_ATTRIBUTE_MAP['firewalls'].update(
|
|
||||||
firewallrouterinsertion.RESOURCE_ATTRIBUTE_MAP['firewalls'])
|
|
||||||
return res + firewall.Firewall.get_resources()
|
|
||||||
|
|
||||||
def get_actions(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_request_extensions(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
class TestFirewallRouterInsertionBase(
|
|
||||||
test_db_firewall.FirewallPluginDbTestCase):
|
|
||||||
|
|
||||||
def setUp(self, core_plugin=None, fw_plugin=None, ext_mgr=None):
|
|
||||||
self.agentapi_del_fw_p = mock.patch(test_db_firewall.DELETEFW_PATH,
|
|
||||||
create=True, new=test_db_firewall.FakeAgentApi().delete_firewall)
|
|
||||||
self.agentapi_del_fw_p.start()
|
|
||||||
|
|
||||||
# the plugin without L3 support
|
|
||||||
plugin = 'neutron.tests.unit.extensions.test_l3.TestNoL3NatPlugin'
|
|
||||||
# the L3 service plugin
|
|
||||||
l3_plugin = ('neutron.tests.unit.extensions.test_l3.'
|
|
||||||
'TestL3NatAgentSchedulingServicePlugin')
|
|
||||||
|
|
||||||
cfg.CONF.set_override('api_extensions_path', extensions_path)
|
|
||||||
self.saved_attr_map = {}
|
|
||||||
for resource, attrs in six.iteritems(attr.RESOURCES):
|
|
||||||
self.saved_attr_map[resource] = attrs.copy()
|
|
||||||
if not fw_plugin:
|
|
||||||
fw_plugin = FW_PLUGIN_KLASS
|
|
||||||
service_plugins = {'l3_plugin_name': l3_plugin,
|
|
||||||
'fw_plugin_name': fw_plugin}
|
|
||||||
|
|
||||||
if not ext_mgr:
|
|
||||||
ext_mgr = FirewallTestExtensionManager()
|
|
||||||
super(test_db_firewall.FirewallPluginDbTestCase, self).setUp(
|
|
||||||
plugin=plugin, service_plugins=service_plugins, ext_mgr=ext_mgr)
|
|
||||||
|
|
||||||
self.addCleanup(self.restore_attribute_map)
|
|
||||||
self.setup_notification_driver()
|
|
||||||
|
|
||||||
self.l3_plugin = directory.get_plugin(plugin_constants.L3)
|
|
||||||
self.plugin = directory.get_plugin('FIREWALL')
|
|
||||||
self.callbacks = fwaas_plugin.FirewallCallbacks(self.plugin)
|
|
||||||
|
|
||||||
def restore_attribute_map(self):
|
|
||||||
# Remove the fwaasrouterinsertion extension
|
|
||||||
fwaas_def.RESOURCE_ATTRIBUTE_MAP['firewalls'].pop('router_ids')
|
|
||||||
# Restore the original RESOURCE_ATTRIBUTE_MAP
|
|
||||||
attr.RESOURCES = self.saved_attr_map
|
|
||||||
|
|
||||||
def _create_firewall(self, fmt, name, description, firewall_policy_id=None,
|
|
||||||
admin_state_up=True, expected_res_status=None,
|
|
||||||
**kwargs):
|
|
||||||
tenant_id = kwargs.get('tenant_id', self._tenant_id)
|
|
||||||
router_ids = kwargs.get('router_ids')
|
|
||||||
if firewall_policy_id is None:
|
|
||||||
res = self._create_firewall_policy(fmt, 'fwp',
|
|
||||||
description="firewall_policy",
|
|
||||||
shared=True,
|
|
||||||
firewall_rules=[],
|
|
||||||
audited=True)
|
|
||||||
firewall_policy = self.deserialize(fmt or self.fmt, res)
|
|
||||||
firewall_policy_id = firewall_policy["firewall_policy"]["id"]
|
|
||||||
data = {'firewall': {'name': name,
|
|
||||||
'description': description,
|
|
||||||
'firewall_policy_id': firewall_policy_id,
|
|
||||||
'admin_state_up': admin_state_up,
|
|
||||||
'tenant_id': tenant_id}}
|
|
||||||
if router_ids is not None:
|
|
||||||
data['firewall']['router_ids'] = router_ids
|
|
||||||
firewall_req = self.new_create_request('firewalls', data, fmt)
|
|
||||||
firewall_res = firewall_req.get_response(self.ext_api)
|
|
||||||
if expected_res_status:
|
|
||||||
self.assertEqual(expected_res_status, firewall_res.status_int)
|
|
||||||
return firewall_res
|
|
||||||
|
|
||||||
|
|
||||||
class TestFirewallCallbacks(TestFirewallRouterInsertionBase):
|
|
||||||
|
|
||||||
def test_set_firewall_status(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP
|
|
||||||
) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
res = self.callbacks.set_firewall_status(ctx, fw_id,
|
|
||||||
nl_constants.ACTIVE)
|
|
||||||
fw_db = self.plugin.get_firewall(ctx, fw_id)
|
|
||||||
self.assertEqual(nl_constants.ACTIVE, fw_db['status'])
|
|
||||||
self.assertTrue(res)
|
|
||||||
res = self.callbacks.set_firewall_status(ctx, fw_id,
|
|
||||||
nl_constants.ERROR)
|
|
||||||
fw_db = self.plugin.get_firewall(ctx, fw_id)
|
|
||||||
self.assertEqual(nl_constants.ERROR, fw_db['status'])
|
|
||||||
self.assertFalse(res)
|
|
||||||
|
|
||||||
def test_set_firewall_status_pending_delete(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP
|
|
||||||
) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
fw_db = self.plugin._get_firewall(ctx, fw_id)
|
|
||||||
fw_db['status'] = nl_constants.PENDING_DELETE
|
|
||||||
ctx.session.flush()
|
|
||||||
res = self.callbacks.set_firewall_status(ctx, fw_id,
|
|
||||||
nl_constants.ACTIVE)
|
|
||||||
fw_db = self.plugin.get_firewall(ctx, fw_id)
|
|
||||||
self.assertEqual(nl_constants.PENDING_DELETE, fw_db['status'])
|
|
||||||
self.assertFalse(res)
|
|
||||||
|
|
||||||
def test_firewall_deleted(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
do_delete=False) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
with ctx.session.begin(subtransactions=True):
|
|
||||||
fw_db = self.plugin._get_firewall(ctx, fw_id)
|
|
||||||
fw_db['status'] = nl_constants.PENDING_DELETE
|
|
||||||
ctx.session.flush()
|
|
||||||
res = self.callbacks.firewall_deleted(ctx, fw_id)
|
|
||||||
self.assertTrue(res)
|
|
||||||
self.assertRaises(f_exc.FirewallNotFound,
|
|
||||||
self.plugin.get_firewall,
|
|
||||||
ctx, fw_id)
|
|
||||||
|
|
||||||
def test_firewall_deleted_concurrently(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
alt_ctx = context.get_admin_context()
|
|
||||||
|
|
||||||
_get_firewall = self.plugin._get_firewall
|
|
||||||
|
|
||||||
def getdelete(context, firewall_id):
|
|
||||||
fw_db = _get_firewall(context, firewall_id)
|
|
||||||
# NOTE(cby): Use a different session to simulate a concurrent del
|
|
||||||
self.plugin.delete_db_firewall_object(alt_ctx, firewall_id)
|
|
||||||
return fw_db
|
|
||||||
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
do_delete=False
|
|
||||||
) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
with ctx.session.begin(subtransactions=True):
|
|
||||||
fw_db = self.plugin._get_firewall(ctx, fw_id)
|
|
||||||
fw_db['status'] = nl_constants.PENDING_DELETE
|
|
||||||
ctx.session.flush()
|
|
||||||
|
|
||||||
with mock.patch.object(
|
|
||||||
self.plugin, '_get_firewall', side_effect=getdelete
|
|
||||||
):
|
|
||||||
observed = self.callbacks.firewall_deleted(ctx, fw_id)
|
|
||||||
self.assertTrue(observed)
|
|
||||||
|
|
||||||
self.assertRaises(f_exc.FirewallNotFound,
|
|
||||||
self.plugin.get_firewall,
|
|
||||||
ctx, fw_id)
|
|
||||||
|
|
||||||
def test_firewall_deleted_not_found(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
observed = self.callbacks.firewall_deleted(ctx, 'notfound')
|
|
||||||
self.assertTrue(observed)
|
|
||||||
|
|
||||||
def test_firewall_deleted_error(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
res = self.callbacks.firewall_deleted(ctx, fw_id)
|
|
||||||
self.assertFalse(res)
|
|
||||||
fw_db = self.plugin._get_firewall(ctx, fw_id)
|
|
||||||
self.assertEqual(nl_constants.ERROR, fw_db['status'])
|
|
||||||
|
|
||||||
def test_get_firewall_for_tenant(self):
|
|
||||||
tenant_id = 'test-tenant'
|
|
||||||
ctx = context.Context('', tenant_id)
|
|
||||||
with self.firewall_rule(name='fwr1', tenant_id=tenant_id) as fwr1, \
|
|
||||||
self.firewall_rule(name='fwr2', tenant_id=tenant_id) as fwr2, \
|
|
||||||
self.firewall_rule(name='fwr3', tenant_id=tenant_id) as fwr3:
|
|
||||||
with self.firewall_policy(tenant_id=tenant_id) as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
fr = [fwr1, fwr2, fwr3]
|
|
||||||
fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
|
|
||||||
data = {'firewall_policy':
|
|
||||||
{'firewall_rules': fw_rule_ids}}
|
|
||||||
req = self.new_update_request('firewall_policies', data,
|
|
||||||
fwp_id)
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
attrs = self._get_test_firewall_attrs()
|
|
||||||
attrs['firewall_policy_id'] = fwp_id
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
tenant_id=tenant_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
res = self.callbacks.get_firewalls_for_tenant(ctx)
|
|
||||||
fw_rules = (
|
|
||||||
self.plugin._make_firewall_dict_with_rules(ctx,
|
|
||||||
fw_id)
|
|
||||||
)
|
|
||||||
fw_rules['add-router-ids'] = []
|
|
||||||
fw_rules['del-router-ids'] = []
|
|
||||||
self.assertEqual(fw_rules, res[0])
|
|
||||||
self._compare_firewall_rule_lists(
|
|
||||||
fwp_id, fr, res[0]['firewall_rule_list'])
|
|
||||||
|
|
||||||
|
|
||||||
class TestFirewallAgentApi(base.BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestFirewallAgentApi, self).setUp()
|
|
||||||
|
|
||||||
self.api = fwaas_plugin.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, host):
|
|
||||||
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', host)
|
|
||||||
|
|
||||||
prepare_args = {'server': host}
|
|
||||||
prepare_mock.assert_called_once_with(**prepare_args)
|
|
||||||
|
|
||||||
rpc_mock.assert_called_once_with(mock.sentinel.context, method_name,
|
|
||||||
firewall='test', host='host')
|
|
||||||
|
|
||||||
def test_create_firewall(self):
|
|
||||||
self._call_test_helper('create_firewall', 'host')
|
|
||||||
|
|
||||||
def test_update_firewall(self):
|
|
||||||
self._call_test_helper('update_firewall', 'host')
|
|
||||||
|
|
||||||
def test_delete_firewall(self):
|
|
||||||
self._call_test_helper('delete_firewall', 'host')
|
|
||||||
|
|
||||||
|
|
||||||
class TestFirewallPluginBase(TestFirewallRouterInsertionBase,
|
|
||||||
test_l3_plugin.L3NatTestCaseMixin):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestFirewallPluginBase, self).setUp(fw_plugin=FW_PLUGIN_KLASS)
|
|
||||||
fake_notifier.reset()
|
|
||||||
|
|
||||||
def test_create_firewall_routers_not_specified(self):
|
|
||||||
"""neutron firewall-create test-policy """
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
with self.router(name='router2', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
with self.firewall() as fw1:
|
|
||||||
self.assertEqual(nl_constants.PENDING_CREATE,
|
|
||||||
fw1['firewall']['status'])
|
|
||||||
|
|
||||||
def test_create_firewall_routers_specified(self):
|
|
||||||
"""neutron firewall-create test-policy --router-ids "r1 r2" """
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id) as router1:
|
|
||||||
with self.router(name='router2', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id) as router2:
|
|
||||||
router_ids = [router1['router']['id'], router2['router']['id']]
|
|
||||||
with self.firewall(router_ids=router_ids) as fw1:
|
|
||||||
self.assertEqual(nl_constants.PENDING_CREATE,
|
|
||||||
fw1['firewall']['status'])
|
|
||||||
|
|
||||||
def test_create_firewall_routers_present_empty_list_specified(self):
|
|
||||||
"""neutron firewall-create test-policy --router-ids "" """
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
with self.router(name='router2', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
router_ids = []
|
|
||||||
with self.firewall(router_ids=router_ids) as fw1:
|
|
||||||
self.assertEqual(nl_constants.INACTIVE,
|
|
||||||
fw1['firewall']['status'])
|
|
||||||
|
|
||||||
def test_create_firewall_no_routers_empty_list_specified(self):
|
|
||||||
"""neutron firewall-create test-policy --router-ids "" """
|
|
||||||
router_ids = []
|
|
||||||
with self.firewall(router_ids=router_ids) as fw1:
|
|
||||||
self.assertEqual(nl_constants.INACTIVE,
|
|
||||||
fw1['firewall']['status'])
|
|
||||||
|
|
||||||
def test_create_second_firewall_on_same_tenant(self):
|
|
||||||
"""fw1 created with default routers, fw2 no routers on same tenant."""
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
with self.router(name='router2', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
router_ids = []
|
|
||||||
with self.firewall() as fw1:
|
|
||||||
with self.firewall(router_ids=router_ids) as fw2:
|
|
||||||
self.assertEqual(nl_constants.PENDING_CREATE,
|
|
||||||
fw1['firewall']['status'])
|
|
||||||
self.assertEqual(nl_constants.INACTIVE,
|
|
||||||
fw2['firewall']['status'])
|
|
||||||
|
|
||||||
def test_create_firewall_admin_not_affected_by_other_tenant(self):
|
|
||||||
# Create fw with admin after creating fw with other tenant
|
|
||||||
with self.firewall(tenant_id='other-tenant') as fw1:
|
|
||||||
with self.firewall() as fw2:
|
|
||||||
self.assertEqual('other-tenant', fw1['firewall']['tenant_id'])
|
|
||||||
self.assertEqual(self._tenant_id, fw2['firewall']['tenant_id'])
|
|
||||||
|
|
||||||
def test_update_firewall(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
name = "new_firewall1"
|
|
||||||
attrs = self._get_test_firewall_attrs(name)
|
|
||||||
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id) as router1:
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
attrs['firewall_policy_id'] = fwp_id
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
router_ids=[router1['router']['id']]
|
|
||||||
) as firewall:
|
|
||||||
fw_id = firewall['firewall']['id']
|
|
||||||
res = self.callbacks.set_firewall_status(ctx, fw_id,
|
|
||||||
nl_constants.ACTIVE)
|
|
||||||
data = {'firewall': {'name': name}}
|
|
||||||
req = self.new_update_request('firewalls', data, fw_id)
|
|
||||||
res = self.deserialize(self.fmt,
|
|
||||||
req.get_response(self.ext_api))
|
|
||||||
attrs = self._replace_firewall_status(attrs,
|
|
||||||
nl_constants.
|
|
||||||
PENDING_CREATE,
|
|
||||||
nl_constants.
|
|
||||||
PENDING_UPDATE)
|
|
||||||
for k, v in six.iteritems(attrs):
|
|
||||||
self.assertEqual(v, res['firewall'][k])
|
|
||||||
|
|
||||||
def test_update_firewall_fails_when_firewall_pending(self):
|
|
||||||
name = "new_firewall1"
|
|
||||||
attrs = self._get_test_firewall_attrs(name)
|
|
||||||
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id) as router1:
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
attrs['firewall_policy_id'] = fwp_id
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
router_ids=[router1['router']['id']]
|
|
||||||
) as firewall:
|
|
||||||
fw_id = firewall['firewall']['id']
|
|
||||||
data = {'firewall': {'name': name}}
|
|
||||||
req = self.new_update_request('firewalls', data, fw_id)
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
self.assertEqual(exc.HTTPConflict.code, res.status_int)
|
|
||||||
|
|
||||||
def test_update_firewall_with_router_when_firewall_inactive(self):
|
|
||||||
name = "firewall1"
|
|
||||||
attrs = self._get_test_firewall_attrs(name)
|
|
||||||
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id) as router1:
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
attrs['firewall_policy_id'] = fwp_id
|
|
||||||
with self.firewall(
|
|
||||||
name=name,
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
router_ids=[]
|
|
||||||
) as firewall:
|
|
||||||
fw_id = firewall['firewall']['id']
|
|
||||||
data = {
|
|
||||||
'firewall': {'router_ids': [router1['router']['id']]}}
|
|
||||||
req = self.new_update_request('firewalls', data, fw_id)
|
|
||||||
res = self.deserialize(self.fmt,
|
|
||||||
req.get_response(self.ext_api))
|
|
||||||
attrs = self._replace_firewall_status(attrs,
|
|
||||||
nl_constants.
|
|
||||||
PENDING_CREATE,
|
|
||||||
nl_constants.
|
|
||||||
PENDING_UPDATE)
|
|
||||||
for k, v in six.iteritems(attrs):
|
|
||||||
self.assertEqual(v, res['firewall'][k])
|
|
||||||
|
|
||||||
def test_update_firewall_policy_fails_when_firewall_pending(self):
|
|
||||||
name = "new_firewall1"
|
|
||||||
attrs = self._get_test_firewall_attrs(name)
|
|
||||||
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
attrs['firewall_policy_id'] = fwp_id
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP
|
|
||||||
):
|
|
||||||
data = {'firewall_policy': {'name': name}}
|
|
||||||
req = self.new_update_request('firewall_policies',
|
|
||||||
data, fwp_id)
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
self.assertEqual(exc.HTTPConflict.code, res.status_int)
|
|
||||||
|
|
||||||
def test_update_firewall_rule_fails_when_firewall_pending(self):
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id):
|
|
||||||
with self.firewall_rule(name='fwr1') as fr:
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
fr_id = fr['firewall_rule']['id']
|
|
||||||
fw_rule_ids = [fr_id]
|
|
||||||
data = {'firewall_policy':
|
|
||||||
{'firewall_rules': fw_rule_ids}}
|
|
||||||
req = self.new_update_request('firewall_policies', data,
|
|
||||||
fwp_id)
|
|
||||||
req.get_response(self.ext_api)
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP
|
|
||||||
):
|
|
||||||
data = {'firewall_rule': {'protocol': 'udp'}}
|
|
||||||
req = self.new_update_request('firewall_rules',
|
|
||||||
data, fr_id)
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
self.assertEqual(exc.HTTPConflict.code, res.status_int)
|
|
||||||
|
|
||||||
def test_delete_firewall_with_no_routers(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
# stop the AgentRPC patch for this one to test pending states
|
|
||||||
self.agentapi_del_fw_p.stop()
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
do_delete=False
|
|
||||||
) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
req = self.new_delete_request('firewalls', fw_id)
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
self.assertEqual(exc.HTTPNoContent.code, res.status_int)
|
|
||||||
self.assertRaises(f_exc.FirewallNotFound,
|
|
||||||
self.plugin.get_firewall,
|
|
||||||
ctx, fw_id)
|
|
||||||
|
|
||||||
def test_delete_firewall_after_agent_delete(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(firewall_policy_id=fwp_id,
|
|
||||||
do_delete=False) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
req = self.new_delete_request('firewalls', fw_id)
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
self.assertEqual(exc.HTTPNoContent.code, res.status_int)
|
|
||||||
self.assertRaises(f_exc.FirewallNotFound,
|
|
||||||
self.plugin.get_firewall,
|
|
||||||
ctx, fw_id)
|
|
||||||
|
|
||||||
def test_make_firewall_dict_with_in_place_rules(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_rule(name='fwr1') as fwr1, \
|
|
||||||
self.firewall_rule(name='fwr2') as fwr2, \
|
|
||||||
self.firewall_rule(name='fwr3') as fwr3:
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fr = [fwr1, fwr2, fwr3]
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
|
|
||||||
data = {'firewall_policy':
|
|
||||||
{'firewall_rules': fw_rule_ids}}
|
|
||||||
req = self.new_update_request('firewall_policies', data,
|
|
||||||
fwp_id)
|
|
||||||
req.get_response(self.ext_api)
|
|
||||||
attrs = self._get_test_firewall_attrs()
|
|
||||||
attrs['firewall_policy_id'] = fwp_id
|
|
||||||
with self.firewall(
|
|
||||||
firewall_policy_id=fwp_id,
|
|
||||||
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
|
||||||
router_ids=[]
|
|
||||||
) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
fw_rules = (
|
|
||||||
self.plugin._make_firewall_dict_with_rules(ctx,
|
|
||||||
fw_id)
|
|
||||||
)
|
|
||||||
self.assertEqual(fw_id, fw_rules['id'])
|
|
||||||
self._compare_firewall_rule_lists(
|
|
||||||
fwp_id, fr, fw_rules['firewall_rule_list'])
|
|
||||||
|
|
||||||
def test_make_firewall_dict_with_in_place_rules_no_policy(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall() as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
fw_rules = self.plugin._make_firewall_dict_with_rules(ctx, fw_id)
|
|
||||||
self.assertEqual([], fw_rules['firewall_rule_list'])
|
|
||||||
|
|
||||||
def test_list_firewalls(self):
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(name='fw1', firewall_policy_id=fwp_id,
|
|
||||||
description='fw') as fwalls:
|
|
||||||
self._test_list_resources('firewall', [fwalls],
|
|
||||||
query_params='description=fw')
|
|
||||||
|
|
||||||
def test_list_firewalls_with_filtering(self):
|
|
||||||
with self.router(name='my_router', admin_state_up=True,
|
|
||||||
tenant_id=self._tenant_id) as router:
|
|
||||||
router_id = router['router']['id']
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(name='fw1', firewall_policy_id=fwp_id,
|
|
||||||
description='fw',
|
|
||||||
router_ids=[router_id]) as fwalls:
|
|
||||||
filter_pattern = None
|
|
||||||
fw = fwalls['firewall']
|
|
||||||
for filter_pattern in fw:
|
|
||||||
query_params = 'fields=%s' % filter_pattern
|
|
||||||
expect = [{filter_pattern: fw[filter_pattern]}]
|
|
||||||
self._test_list_resources('firewall', expect,
|
|
||||||
query_params=query_params)
|
|
||||||
|
|
||||||
def test_insert_rule(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_rule() as fwr:
|
|
||||||
fr_id = fwr['firewall_rule']['id']
|
|
||||||
rule_info = {'firewall_rule_id': fr_id}
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(firewall_policy_id=fwp_id) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
self.plugin.insert_rule(ctx, fwp_id, rule_info)
|
|
||||||
fw_rules = self.plugin._make_firewall_dict_with_rules(
|
|
||||||
ctx, fw_id)
|
|
||||||
self.assertEqual(1, len(fw_rules['firewall_rule_list']))
|
|
||||||
self.assertEqual(fr_id,
|
|
||||||
fw_rules['firewall_rule_list'][0]['id'])
|
|
||||||
|
|
||||||
def test_insert_rule_notif(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_rule() as fwr:
|
|
||||||
fr_id = fwr['firewall_rule']['id']
|
|
||||||
rule_info = {'firewall_rule_id': fr_id}
|
|
||||||
with self.firewall_policy() as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(firewall_policy_id=fwp_id):
|
|
||||||
self.plugin.insert_rule(ctx, fwp_id, rule_info)
|
|
||||||
notifications = fake_notifier.NOTIFICATIONS
|
|
||||||
expected_event_type = 'firewall_policy.update.insert_rule'
|
|
||||||
event_types = [event['event_type'] for event in notifications]
|
|
||||||
self.assertIn(expected_event_type, event_types)
|
|
||||||
|
|
||||||
def test_remove_rule(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_rule() as fwr:
|
|
||||||
fr_id = fwr['firewall_rule']['id']
|
|
||||||
rule_info = {'firewall_rule_id': fr_id}
|
|
||||||
with self.firewall_policy(firewall_rules=[fr_id]) as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(firewall_policy_id=fwp_id) as fw:
|
|
||||||
fw_id = fw['firewall']['id']
|
|
||||||
self.plugin.remove_rule(ctx, fwp_id, rule_info)
|
|
||||||
fw_rules = self.plugin._make_firewall_dict_with_rules(
|
|
||||||
ctx, fw_id)
|
|
||||||
self.assertEqual([], fw_rules['firewall_rule_list'])
|
|
||||||
|
|
||||||
def test_remove_rule_notif(self):
|
|
||||||
ctx = context.get_admin_context()
|
|
||||||
with self.firewall_rule() as fwr:
|
|
||||||
fr_id = fwr['firewall_rule']['id']
|
|
||||||
rule_info = {'firewall_rule_id': fr_id}
|
|
||||||
with self.firewall_policy(firewall_rules=[fr_id]) as fwp:
|
|
||||||
fwp_id = fwp['firewall_policy']['id']
|
|
||||||
with self.firewall(firewall_policy_id=fwp_id):
|
|
||||||
self.plugin.remove_rule(ctx, fwp_id, rule_info)
|
|
||||||
notifications = fake_notifier.NOTIFICATIONS
|
|
||||||
expected_event_type = 'firewall_policy.update.remove_rule'
|
|
||||||
event_types = [event['event_type'] for event in notifications]
|
|
||||||
self.assertIn(expected_event_type, event_types)
|
|
||||||
|
|
||||||
def test_firewall_quota_lower(self):
|
|
||||||
"""Test quota using overridden value."""
|
|
||||||
cfg.CONF.set_override('quota_firewall', 3, group='QUOTAS')
|
|
||||||
with self.firewall(name='quota1'), \
|
|
||||||
self.firewall(name='quota2'), \
|
|
||||||
self.firewall(name='quota3'):
|
|
||||||
data = {'firewall': {'name': 'quota4',
|
|
||||||
'firewall_policy_id': None,
|
|
||||||
'tenant_id': self._tenant_id}}
|
|
||||||
req = self.new_create_request('firewalls', data, 'json')
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
self.assertIn('Quota exceeded', res.body.decode('utf-8'))
|
|
||||||
self.assertEqual(exc.HTTPConflict.code, res.status_int)
|
|
||||||
|
|
||||||
def test_firewall_quota_default(self):
|
|
||||||
"""Test quota using default value."""
|
|
||||||
with self.firewall(name='quota1'), \
|
|
||||||
self.firewall(name='quota2'), \
|
|
||||||
self.firewall(name='quota3'), \
|
|
||||||
self.firewall(name='quota4'), \
|
|
||||||
self.firewall(name='quota5'), \
|
|
||||||
self.firewall(name='quota6'), \
|
|
||||||
self.firewall(name='quota7'), \
|
|
||||||
self.firewall(name='quota8'), \
|
|
||||||
self.firewall(name='quota9'), \
|
|
||||||
self.firewall(name='quota10'):
|
|
||||||
data = {'firewall': {'name': 'quota11',
|
|
||||||
'firewall_policy_id': None,
|
|
||||||
'tenant_id': self._tenant_id}}
|
|
||||||
req = self.new_create_request('firewalls', data, 'json')
|
|
||||||
res = req.get_response(self.ext_api)
|
|
||||||
self.assertIn('Quota exceeded', res.body.decode('utf-8'))
|
|
||||||
self.assertEqual(exc.HTTPConflict.code, res.status_int)
|
|
||||||
|
|
||||||
|
|
||||||
class TestFirewallRouterPluginBase(test_db_firewall.FirewallPluginDbTestCase,
|
|
||||||
test_l3_plugin.L3NatTestCaseMixin,
|
|
||||||
test_agent.AgentDBTestMixIn):
|
|
||||||
|
|
||||||
def setUp(self, core_plugin=None, fw_plugin=None, ext_mgr=None):
|
|
||||||
self.agentapi_del_fw_p = mock.patch(test_db_firewall.DELETEFW_PATH,
|
|
||||||
create=True, new=test_db_firewall.FakeAgentApi().delete_firewall)
|
|
||||||
self.agentapi_del_fw_p.start()
|
|
||||||
|
|
||||||
self.client_mock = mock.MagicMock(name="mocked client")
|
|
||||||
mock.patch('neutron.common.rpc.get_client'
|
|
||||||
).start().return_value = self.client_mock
|
|
||||||
|
|
||||||
# the L3 routing with L3 agent scheduling service plugin
|
|
||||||
l3_plugin = ('neutron.tests.unit.extensions.test_l3.'
|
|
||||||
'TestL3NatAgentSchedulingServicePlugin')
|
|
||||||
|
|
||||||
cfg.CONF.set_override('api_extensions_path', extensions_path)
|
|
||||||
if not fw_plugin:
|
|
||||||
fw_plugin = FW_PLUGIN_KLASS
|
|
||||||
service_plugins = {'l3_plugin_name': l3_plugin,
|
|
||||||
'fw_plugin_name': fw_plugin}
|
|
||||||
|
|
||||||
fdb.Firewall_db_mixin.\
|
|
||||||
supported_extension_aliases = ["fwaas",
|
|
||||||
"fwaasrouterinsertion"]
|
|
||||||
fdb.Firewall_db_mixin.path_prefix = fwaas_def.API_PREFIX
|
|
||||||
|
|
||||||
super(test_db_firewall.FirewallPluginDbTestCase, self).setUp(
|
|
||||||
ext_mgr=ext_mgr,
|
|
||||||
service_plugins=service_plugins
|
|
||||||
)
|
|
||||||
|
|
||||||
if not ext_mgr:
|
|
||||||
ext_mgr = FirewallTestExtensionManager()
|
|
||||||
app = config.load_paste_app('extensions_test_app')
|
|
||||||
self.ext_api = api_ext.ExtensionMiddleware(app, ext_mgr=ext_mgr)
|
|
||||||
|
|
||||||
self.l3_plugin = directory.get_plugin(plugin_constants.L3)
|
|
||||||
self.plugin = directory.get_plugin('FIREWALL')
|
|
||||||
|
|
||||||
def test_get_firewall_tenant_ids_on_host_with_associated_router(self):
|
|
||||||
agent = helpers.register_l3_agent("host1")
|
|
||||||
tenant_id = uuidutils.generate_uuid()
|
|
||||||
ctxt = context.get_admin_context()
|
|
||||||
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=tenant_id) as router1:
|
|
||||||
router_id = router1['router']['id']
|
|
||||||
self.l3_plugin.add_router_to_l3_agent(ctxt, agent.id,
|
|
||||||
router_id)
|
|
||||||
with self.firewall(tenant_id=tenant_id,
|
|
||||||
router_ids=[router_id]):
|
|
||||||
tenant_ids = self.plugin.get_firewall_tenant_ids_on_host(
|
|
||||||
ctxt, 'host1')
|
|
||||||
self.assertEqual([tenant_id], tenant_ids)
|
|
||||||
|
|
||||||
def test_get_firewall_tenant_ids_on_host_without_associated_router(self):
|
|
||||||
agent1 = helpers.register_l3_agent("host1")
|
|
||||||
helpers.register_l3_agent("host2")
|
|
||||||
tenant_id = uuidutils.generate_uuid()
|
|
||||||
ctxt = context.get_admin_context()
|
|
||||||
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=tenant_id) as router1:
|
|
||||||
router_id = router1['router']['id']
|
|
||||||
self.l3_plugin.add_router_to_l3_agent(ctxt, agent1.id,
|
|
||||||
router_id)
|
|
||||||
with self.firewall(tenant_id=tenant_id,
|
|
||||||
router_ids=[router_id]):
|
|
||||||
tenant_ids = self.plugin.get_firewall_tenant_ids_on_host(
|
|
||||||
ctxt, 'host_2')
|
|
||||||
self.assertEqual([], tenant_ids)
|
|
||||||
|
|
||||||
def test_get_firewall_tenant_ids_on_host_with_routers(self):
|
|
||||||
agent1 = helpers.register_l3_agent("host1")
|
|
||||||
tenant_id1 = uuidutils.generate_uuid()
|
|
||||||
tenant_id2 = uuidutils.generate_uuid()
|
|
||||||
ctxt = context.get_admin_context()
|
|
||||||
|
|
||||||
with self.router(name='router1', admin_state_up=True,
|
|
||||||
tenant_id=tenant_id1) as router1:
|
|
||||||
with self.router(name='router2', admin_state_up=True,
|
|
||||||
tenant_id=tenant_id2) as router2:
|
|
||||||
router_id1 = router1['router']['id']
|
|
||||||
router_id2 = router2['router']['id']
|
|
||||||
self.l3_plugin.add_router_to_l3_agent(ctxt, agent1.id,
|
|
||||||
router_id1)
|
|
||||||
self.l3_plugin.add_router_to_l3_agent(ctxt, agent1.id,
|
|
||||||
router_id2)
|
|
||||||
with self.firewall(tenant_id=tenant_id1,
|
|
||||||
router_ids=[router_id1]):
|
|
||||||
with self.firewall(tenant_id=tenant_id2,
|
|
||||||
router_ids=[router_id2]):
|
|
||||||
tenant_ids = (self.plugin
|
|
||||||
.get_firewall_tenant_ids_on_host(
|
|
||||||
ctxt, 'host1'))
|
|
||||||
self.assertItemsEqual([tenant_id1, tenant_id2],
|
|
||||||
tenant_ids)
|
|
7
releasenotes/notes/remove_fwaas_v1-15c6e19484f46d1b.yaml
Normal file
7
releasenotes/notes/remove_fwaas_v1-15c6e19484f46d1b.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
- FWaaS V1 is being removed from the neutron-fwaas repo. Because FWaaS V2
|
||||||
|
has been available since the Newton release.
|
||||||
|
upgrade:
|
||||||
|
- The FWaaS V1 source code will not be available in neutron-fwaas repo from
|
||||||
|
Stein. FWaaS team will provide a migration script to upgrade.
|
@ -32,15 +32,9 @@ setup-hooks =
|
|||||||
|
|
||||||
[entry_points]
|
[entry_points]
|
||||||
firewall_drivers =
|
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.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
|
iptables_v2 = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.iptables_fwaas_v2:IptablesFwaasDriver
|
||||||
neutron.service_plugins =
|
neutron.service_plugins =
|
||||||
firewall = neutron_fwaas.services.firewall.fwaas_plugin:FirewallPlugin
|
|
||||||
firewall_v2 = neutron_fwaas.services.firewall.fwaas_plugin_v2:FirewallPluginV2
|
firewall_v2 = neutron_fwaas.services.firewall.fwaas_plugin_v2:FirewallPluginV2
|
||||||
neutron.services.firewall.fwaas_plugin.FirewallPlugin = neutron_fwaas.services.firewall.fwaas_plugin:FirewallPlugin
|
|
||||||
|
|
||||||
neutron.db.alembic_migrations =
|
neutron.db.alembic_migrations =
|
||||||
neutron-fwaas = neutron_fwaas.db.migration:alembic_migrations
|
neutron-fwaas = neutron_fwaas.db.migration:alembic_migrations
|
||||||
@ -59,7 +53,6 @@ neutron.agent.l2.firewall_drivers =
|
|||||||
noop = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.noop.noop_driver:NoopFirewallL2Driver
|
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
|
ovs = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.openvswitch_firewall.firewall:OVSFirewallDriver
|
||||||
neutron.agent.l3.extensions =
|
neutron.agent.l3.extensions =
|
||||||
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
|
fwaas_v2 = neutron_fwaas.services.firewall.service_drivers.agents.l3reference.firewall_l3_agent_v2:L3WithFWaaS
|
||||||
fwaas_v2_log = neutron_fwaas.services.logapi.agents.l3.fwg_log:FWaaSL3LoggingExtension
|
fwaas_v2_log = neutron_fwaas.services.logapi.agents.l3.fwg_log:FWaaSL3LoggingExtension
|
||||||
neutron.agent.l3.firewall_drivers =
|
neutron.agent.l3.firewall_drivers =
|
||||||
|
Loading…
Reference in New Issue
Block a user