From 9b353afde499f46ebec6e8c8529eab0a99a2023b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89douard=20Thuleau?= Date: Mon, 26 Jun 2017 11:32:24 +0200 Subject: [PATCH] Implements a plugable backend driver This patch removes all related DB code from the FWaaS service plugin v2 and creates service driver interfaces that can be used by different backend drivers. The default backend driver still based on the Neutron DB model and agent RPC interface (for l3 and l2 agents) and was moved to 'service_drivers.agents.agents.FwaasAgentDriver'. It inherits from the firewall backend driver DB interface 'service_drivers.driver_api.FwaasDriverDB' to maintain the DB. It is in charge to implement all RPC API and messages. If we need to implement a backend driver which depends on the Neutron DB but not on the agent RPC service, we just have to inherit from the DB interface and if we like to develop a backend driver which not depends on the Neutron DB model, we can inherit from the base driver interface 'service_driver.driver_api.FwaasDriver'. That patch only modifies the service plugin 'firewall_v2', it does not modify the Firewall v1 service plugin. The backend DB driver provides an interface composed to a pre and post commit hooks for each FWaaSv2 API actions which permits to the driver to be warn anytimes. All that commit hooks methods does not do anything by default and the backend driver needs to overide needed hooks. The driver does not needs to implements all of them, Closes-Bug: #1702312 Change-Id: I4ebd24f1b13eb823c4d63452fd37cace5bcf5481 --- devstack/plugin.sh | 3 + devstack/settings | 3 +- .../db/firewall/v2/firewall_db_v2.py | 278 ++-- neutron_fwaas/extensions/firewall_v2.py | 43 +- neutron_fwaas/opts.py | 12 +- .../services/firewall/fwaas_plugin_v2.py | 651 ++++----- .../{agents => service_drivers}/__init__.py | 0 .../l2 => service_drivers/agents}/__init__.py | 0 .../firewall/service_drivers/agents/agents.py | 355 +++++ .../agents/drivers}/__init__.py | 0 .../agents}/drivers/conntrack_base.py | 2 +- .../agents}/drivers/fwaas_base.py | 0 .../agents}/drivers/fwaas_base_v2.py | 0 .../agents/drivers/linux}/__init__.py | 0 .../agents}/drivers/linux/iptables_fwaas.py | 6 +- .../drivers/linux/iptables_fwaas_v2.py | 6 +- .../agents/drivers/linux/l2}/__init__.py | 0 .../agents}/drivers/linux/l2/driver_base.py | 0 .../agents/drivers/linux/l2/noop}/__init__.py | 0 .../drivers/linux/l2/noop/noop_driver.py | 3 +- .../linux/l2/openvswitch_firewall/__init__.py | 4 +- .../l2/openvswitch_firewall/constants.py | 0 .../l2/openvswitch_firewall/exceptions.py | 0 .../linux/l2/openvswitch_firewall/firewall.py | 15 +- .../linux/l2/openvswitch_firewall/rules.py | 9 +- .../agents}/drivers/linux/legacy_conntrack.py | 4 +- .../drivers/linux/netlink_conntrack.py | 3 +- .../agents/firewall_agent_api.py | 0 .../agents/firewall_service.py | 0 .../agents/l2}/__init__.py | 0 .../agents/l2/fwaas_v2.py | 3 +- .../agents/l3reference}/__init__.py | 0 .../agents/l3reference/firewall_l3_agent.py | 6 +- .../l3reference/firewall_l3_agent_v2.py | 6 +- .../firewall/service_drivers/driver_api.py | 435 ++++++ .../db/firewall/v2/test_firewall_db_v2.py | 625 ++------ .../l2 => service_drivers}/__init__.py | 0 .../agents}/__init__.py | 0 .../agents}/drivers/__init__.py | 0 .../agents}/drivers/linux/__init__.py | 0 .../agents}/drivers/linux/l2/__init__.py | 0 .../agents}/drivers/linux/l2/noop/__init__.py | 0 .../drivers/linux/l2/noop/test_noop_driver.py | 3 +- .../linux/l2/openvswitch_firewall/__init__.py | 0 .../l2/openvswitch_firewall/test_firewall.py | 12 +- .../l2/openvswitch_firewall/test_rules.py | 12 +- .../drivers/linux/test_iptables_fwaas.py | 3 +- .../drivers/linux/test_iptables_fwaas_v2.py | 3 +- .../drivers/linux/test_legacy_conntrack.py | 7 +- .../drivers/linux/test_netlink_conntrack.py | 3 +- .../agents/l2}/__init__.py | 0 .../agents/l2/fake_data.py | 0 .../agents/l2/test_fwaas_v2.py | 5 +- .../agents/l3reference/__init__.py | 0 .../l3reference/test_firewall_l3_agent.py | 7 +- .../l3reference/test_firewall_l3_agent_v2.py | 11 +- .../service_drivers/agents/test_agents.py | 654 +++++++++ .../agents/test_firewall_agent_api.py | 9 +- .../agents/test_firewall_service.py | 8 +- .../services/firewall/test_fwaas_plugin_v2.py | 1296 ++++++++--------- setup.cfg | 22 +- 61 files changed, 2641 insertions(+), 1886 deletions(-) rename neutron_fwaas/services/firewall/{agents => service_drivers}/__init__.py (100%) rename neutron_fwaas/services/firewall/{agents/l2 => service_drivers/agents}/__init__.py (100%) create mode 100644 neutron_fwaas/services/firewall/service_drivers/agents/agents.py rename neutron_fwaas/services/firewall/{agents/l3reference => service_drivers/agents/drivers}/__init__.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/conntrack_base.py (96%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/fwaas_base.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/fwaas_base_v2.py (100%) rename neutron_fwaas/services/firewall/{drivers => service_drivers/agents/drivers/linux}/__init__.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/iptables_fwaas.py (99%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/iptables_fwaas_v2.py (99%) rename neutron_fwaas/services/firewall/{drivers/linux => service_drivers/agents/drivers/linux/l2}/__init__.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/driver_base.py (100%) rename neutron_fwaas/services/firewall/{drivers/linux/l2 => service_drivers/agents/drivers/linux/l2/noop}/__init__.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/noop/noop_driver.py (92%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/__init__.py (84%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/constants.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/exceptions.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/firewall.py (98%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/rules.py (98%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/legacy_conntrack.py (98%) rename neutron_fwaas/services/firewall/{ => service_drivers/agents}/drivers/linux/netlink_conntrack.py (98%) rename neutron_fwaas/services/firewall/{ => service_drivers}/agents/firewall_agent_api.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers}/agents/firewall_service.py (100%) rename neutron_fwaas/services/firewall/{drivers/linux/l2/noop => service_drivers/agents/l2}/__init__.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers}/agents/l2/fwaas_v2.py (99%) rename neutron_fwaas/{tests/unit/services/firewall/agents => services/firewall/service_drivers/agents/l3reference}/__init__.py (100%) rename neutron_fwaas/services/firewall/{ => service_drivers}/agents/l3reference/firewall_l3_agent.py (98%) rename neutron_fwaas/services/firewall/{ => service_drivers}/agents/l3reference/firewall_l3_agent_v2.py (99%) create mode 100644 neutron_fwaas/services/firewall/service_drivers/driver_api.py rename neutron_fwaas/tests/unit/services/firewall/{agents/l2 => service_drivers}/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{agents/l3reference => service_drivers/agents}/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/noop/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/noop/test_noop_driver.py (93%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/test_firewall.py (98%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/l2/openvswitch_firewall/test_rules.py (97%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/test_iptables_fwaas.py (99%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/test_iptables_fwaas_v2.py (99%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/test_legacy_conntrack.py (95%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers/agents}/drivers/linux/test_netlink_conntrack.py (98%) rename neutron_fwaas/tests/unit/services/firewall/{plugins => service_drivers/agents/l2}/__init__.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers}/agents/l2/fake_data.py (100%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers}/agents/l2/test_fwaas_v2.py (99%) create mode 100644 neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/__init__.py rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers}/agents/l3reference/test_firewall_l3_agent.py (98%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers}/agents/l3reference/test_firewall_l3_agent_v2.py (98%) create mode 100644 neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_agents.py rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers}/agents/test_firewall_agent_api.py (91%) rename neutron_fwaas/tests/unit/services/firewall/{ => service_drivers}/agents/test_firewall_service.py (91%) diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 74a43851c..f126888e0 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -43,6 +43,9 @@ function configure_fwaas_v1() { function configure_fwaas_v2() { # Add conf file cp $NEUTRON_FWAAS_DIR/etc/neutron_fwaas.conf.sample $NEUTRON_FWAAS_CONF + inicomment $NEUTRON_FWAAS_CONF service_providers service_provider + iniadd $NEUTRON_FWAAS_CONF service_providers service_provider $NEUTRON_FWAAS_SERVICE_PROVIDERV2 + neutron_fwaas_configure_driver fwaas_v2 iniset_multiline $Q_L3_CONF_FILE fwaas agent_version v2 iniset_multiline $Q_L3_CONF_FILE fwaas driver $FWAAS_DRIVER_V2 diff --git a/devstack/settings b/devstack/settings index 2a572a5bd..824f97f75 100644 --- a/devstack/settings +++ b/devstack/settings @@ -8,4 +8,5 @@ NEUTRON_FWAAS_DIR=$DEST/neutron-fwaas NEUTRON_FWAAS_CONF_FILE=neutron_fwaas.conf NEUTRON_FWAAS_CONF=$NEUTRON_CONF_DIR/$NEUTRON_FWAAS_CONF_FILE -neutron_server_config_add $NEUTRON_FWAAS_CONF + +NEUTRON_FWAAS_SERVICE_PROVIDERV2=${NEUTRON_FWAAS_SERVICE_PROVIDERV2:-FIREWALL_V2:fwaas_db:neutron_fwaas.services.firewall.service_drivers.agents.agents.FirewallAgentDriver:default} diff --git a/neutron_fwaas/db/firewall/v2/firewall_db_v2.py b/neutron_fwaas/db/firewall/v2/firewall_db_v2.py index 7dd2fbd5b..f57a8f62b 100644 --- a/neutron_fwaas/db/firewall/v2/firewall_db_v2.py +++ b/neutron_fwaas/db/firewall/v2/firewall_db_v2.py @@ -16,16 +16,16 @@ import copy import netaddr + +from neutron.db import _model_query as model_query from neutron.db import api as db_api -from neutron.db import common_db_mixin as base_db +from neutron.db import common_db_mixin from neutron_lib.api.definitions import constants as fw_const -from neutron_lib.api import validators from neutron_lib import constants as nl_constants from neutron_lib.db import constants as db_constants from neutron_lib.db import model_base from neutron_lib import exceptions from neutron_lib.exceptions import firewall_v2 as f_exc -from oslo_config import cfg from oslo_db import exception as db_exc from oslo_log import log as logging from oslo_utils import uuidutils @@ -36,7 +36,6 @@ from sqlalchemy import orm from sqlalchemy.orm import exc from neutron_fwaas.common import fwaas_constants as const -from neutron_fwaas.extensions import firewall_v2 as fw_ext LOG = logging.getLogger(__name__) @@ -86,7 +85,7 @@ class FirewallRuleV2(model_base.BASEV2, model_base.HasId, HasName, class FirewallGroup(model_base.BASEV2, model_base.HasId, HasName, HasDescription, model_base.HasProject): __tablename__ = 'firewall_groups_v2' - ports = orm.relationship( + port_associations = orm.relationship( 'FirewallGroupPortAssociation', backref=orm.backref('firewall_group_port_associations_v2', cascade='all, delete')) @@ -162,7 +161,42 @@ class FirewallPolicy(model_base.BASEV2, model_base.HasId, HasName, shared = sa.Column(sa.Boolean) -class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): +def _list_firewall_groups_result_filter_hook(query, filters): + values = filters and filters.get('ports', []) + if values: + query = query.join(FirewallGroupPortAssociation) + query = query.filter(FirewallGroupPortAssociation.port_id.in_(values)) + + return query + + +def _list_firewall_policies_result_filter_hook(query, filters): + values = filters and filters.get('firewall_rules', []) + if values: + query = query.join(FirewallPolicyRuleAssociation) + query = query.filter( + FirewallPolicyRuleAssociation.firewall_rule_id.in_(values)) + + return query + + +class FirewallPluginDb(common_db_mixin.CommonDbMixin): + + def __new__(cls, *args, **kwargs): + model_query.register_hook( + FirewallGroup, + "firewall_group_v2_filter_by_port_association", + query_hook=None, + filter_hook=None, + result_filters=_list_firewall_groups_result_filter_hook) + + model_query.register_hook( + FirewallPolicy, + "firewall_policy_v2_filter_by_firewall_rule_association", + query_hook=None, + filter_hook=None, + result_filters=_list_firewall_policies_result_filter_hook) + return super(FirewallPluginDb, cls).__new__(cls, *args, **kwargs) def _get_firewall_group(self, context, id): try: @@ -267,22 +301,21 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): 'shared': firewall_policy['shared']} return self._fields(res, fields) - def _make_firewall_group_dict(self, firewall_group, fields=None): - fwg_ports = [ - port_assoc.port_id for port_assoc in firewall_group['ports'] - ] - res = {'id': firewall_group['id'], - 'tenant_id': firewall_group['tenant_id'], - 'name': firewall_group['name'], - 'description': firewall_group['description'], + def _make_firewall_group_dict(self, firewall_group_db, fields=None): + fwg_ports = [port_assoc.port_id for port_assoc in + firewall_group_db.port_associations] + res = {'id': firewall_group_db['id'], + 'tenant_id': firewall_group_db['tenant_id'], + 'name': firewall_group_db['name'], + 'description': firewall_group_db['description'], 'ingress_firewall_policy_id': - firewall_group['ingress_firewall_policy_id'], + firewall_group_db['ingress_firewall_policy_id'], 'egress_firewall_policy_id': - firewall_group['egress_firewall_policy_id'], - 'admin_state_up': firewall_group['admin_state_up'], + firewall_group_db['egress_firewall_policy_id'], + 'admin_state_up': firewall_group_db['admin_state_up'], 'ports': fwg_ports, - 'status': firewall_group['status'], - 'shared': firewall_group['shared']} + 'status': firewall_group_db['status'], + 'shared': firewall_group_db['shared']} return self._fields(res, fields) def _get_policy_ordered_rules(self, context, policy_id): @@ -292,7 +325,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): .order_by(FirewallPolicyRuleAssociation.position)) return [self._make_firewall_rule_dict(rule) for rule in query] - def _make_firewall_group_dict_with_rules(self, context, firewall_group_id): + def make_firewall_group_dict_with_rules(self, context, firewall_group_id): firewall_group = self.get_firewall_group(context, firewall_group_id) ingress_policy_id = firewall_group['ingress_firewall_policy_id'] if ingress_policy_id: @@ -359,7 +392,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): def _get_policy_rule_association(self, context, firewall_policy_id, firewall_rule_id): """Returns the association between a firewall rule and a firewall - policy. Throws an exception if the assocaition does not exist. + policy. Throws an exception if the assocition does not exist. """ try: return self._get_policy_rule_association_query( @@ -374,7 +407,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): # configuration file makes sense. Can be done some time later # 1. Drop any IPv4 packets for ingress traffic - in_fwr_v4 = {'firewall_rule': { + in_fwr_v4 = { 'description': 'default ingress rule for IPv4', 'name': 'default ingress ipv4 (deny all)', 'shared': False, @@ -387,28 +420,25 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): 'source_ip_address': None, 'destination_port': None, 'destination_ip_address': None, - }} + } # 2. Drop any IPv6 packets for ingress traffic in_fwr_v6 = copy.deepcopy(in_fwr_v4) - in_fwr_v6[ - 'firewall_rule']['description'] = 'default ingress rule for IPv6' - in_fwr_v6['firewall_rule']['name'] = 'default ingress ipv6 (deny all)' - in_fwr_v6['firewall_rule']['ip_version'] = nl_constants.IP_VERSION_6 + in_fwr_v6['description'] = 'default ingress rule for IPv6' + in_fwr_v6['name'] = 'default ingress ipv6 (deny all)' + in_fwr_v6['ip_version'] = nl_constants.IP_VERSION_6 # 3. Allow any IPv4 packets for egress traffic eg_fwr_v4 = copy.deepcopy(in_fwr_v4) - eg_fwr_v4[ - 'firewall_rule']['description'] = 'default egress rule for IPv4' - eg_fwr_v4['firewall_rule']['action'] = fw_const.FWAAS_ALLOW - eg_fwr_v4['firewall_rule']['name'] = 'default egress ipv4 (allow all)' + eg_fwr_v4['description'] = 'default egress rule for IPv4' + eg_fwr_v4['action'] = fw_const.FWAAS_ALLOW + eg_fwr_v4['name'] = 'default egress ipv4 (allow all)' # 4. Allow any IPv6 packets for egress traffic eg_fwr_v6 = copy.deepcopy(in_fwr_v6) - eg_fwr_v6[ - 'firewall_rule']['description'] = 'default egress rule for IPv6' - eg_fwr_v6['firewall_rule']['name'] = 'default egress ipv6 (allow all)' - eg_fwr_v6['firewall_rule']['action'] = fw_const.FWAAS_ALLOW + eg_fwr_v6['description'] = 'default egress rule for IPv6' + eg_fwr_v6['name'] = 'default egress ipv6 (allow all)' + eg_fwr_v6['action'] = fw_const.FWAAS_ALLOW return { 'in_ipv4': self.create_firewall_rule(context, in_fwr_v4)['id'], @@ -418,8 +448,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): } def create_firewall_rule(self, context, firewall_rule): - LOG.debug("create_firewall_rule() called") - fwr = firewall_rule['firewall_rule'] + fwr = firewall_rule self._validate_fwr_protocol_parameters(fwr) self._validate_fwr_src_dst_ip_version(fwr) if not fwr['protocol'] and (fwr['source_port'] or @@ -450,8 +479,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): return self._make_firewall_rule_dict(fwr_db) def update_firewall_rule(self, context, id, firewall_rule): - LOG.debug("update_firewall_rule() called") - fwr = firewall_rule['firewall_rule'] + fwr = firewall_rule fwr_db = self._get_firewall_rule(context, id) self._validate_fwr_protocol_parameters(fwr, fwr_db=fwr_db) self._validate_fwr_src_dst_ip_version(fwr, fwr_db=fwr_db) @@ -478,24 +506,21 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): raise f_exc.FirewallRuleWithPortWithoutProtocolInvalid() fwr_db.update(fwr) # if the rule on a policy, fix audited flag - fwp_ids = self._get_policies_with_rule(context, id) + fwp_ids = self.get_policies_with_rule(context, id) for fwp_id in fwp_ids: fwp_db = self._get_firewall_policy(context, fwp_id) fwp_db['audited'] = False return self._make_firewall_rule_dict(fwr_db) def delete_firewall_rule(self, context, id): - LOG.debug("delete_firewall_rule() called") with context.session.begin(subtransactions=True): fwr = self._get_firewall_rule(context, id) # make sure rule is not associated with any policy - if self._get_policies_with_rule(context, id): + if self.get_policies_with_rule(context, id): raise f_exc.FirewallRuleInUse(firewall_rule_id=id) context.session.delete(fwr) def insert_rule(self, context, id, rule_info): - LOG.debug("insert_rule() called") - self._validate_insert_remove_rule_request(rule_info) firewall_rule_id = rule_info['firewall_rule_id'] # ensure rule is not already assigned to the policy self._ensure_rule_not_already_associated(context, id, firewall_rule_id) @@ -534,8 +559,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): position, None) def remove_rule(self, context, id, rule_info): - LOG.debug("remove_rule() called") - self._validate_insert_remove_rule_request(rule_info) firewall_rule_id = rule_info['firewall_rule_id'] with context.session.begin(subtransactions=True): self._get_firewall_rule(context, firewall_rule_id) @@ -545,30 +568,15 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): None, fwpra_db) def get_firewall_rule(self, context, id, fields=None): - LOG.debug("get_firewall_rule() called") fwr = self._get_firewall_rule(context, id) - policies = self._get_policies_with_rule(context, id) or None + policies = self.get_policies_with_rule(context, id) or None return self._make_firewall_rule_dict(fwr, fields, policies=policies) def get_firewall_rules(self, context, filters=None, fields=None): - LOG.debug("get_firewall_rules() called") return self._get_collection(context, FirewallRuleV2, self._make_firewall_rule_dict, filters=filters, fields=fields) - def _validate_insert_remove_rule_request(self, rule_info): - """Validate rule_info dict - - Check that all mandatory fields are present, otherwise raise - proper exception. - """ - if not rule_info or 'firewall_rule_id' not in rule_info: - raise f_exc.FirewallRuleInfoMissing() - # Validator doesn't return anything if the check passes - if validators.validate_uuid(rule_info['firewall_rule_id']): - raise f_exc.FirewallRuleNotFound( - firewall_rule_id=rule_info['firewall_rule_id']) - def _get_rules_in_policy(self, context, fwpid): """Gets rules in a firewall policy""" with context.session.begin(subtransactions=True): @@ -578,7 +586,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): fwp_rules = [entry.firewall_rule_id for entry in fw_pol_rule_qry] return fwp_rules - def _get_policies_with_rule(self, context, fwrid): + def get_policies_with_rule(self, context, fwrid): """Gets rules in a firewall policy""" with context.session.begin(subtransactions=True): fw_pol_rule_qry = context.session.query( @@ -644,7 +652,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): firewall_rule_id=fwr_db['id'], firewall_policy_id=fwp_db['id']) - def _get_fwgs_with_policy(self, context, fwp_id): + def get_fwgs_with_policy(self, context, fwp_id): with context.session.begin(subtransactions=True): fwg_ing_pol_qry = context.session.query( FirewallGroup).filter_by( @@ -719,18 +727,18 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): description = kwargs.get('description', '') name = (const.DEFAULT_FWP_INGRESS if policy_type == 'ingress' else const.DEFAULT_FWP_EGRESS) - firewall_policy = {'firewall_policy': { + firewall_policy = { 'name': name, 'description': description, 'audited': False, 'shared': False, 'firewall_rules': fwrs, 'tenant_id': tenant_id, - }} + } return self._do_create_firewall_policy(context, firewall_policy) def _do_create_firewall_policy(self, context, firewall_policy): - fwp = firewall_policy['firewall_policy'] + fwp = firewall_policy with context.session.begin(subtransactions=True): fwp_db = FirewallPolicy( id=uuidutils.generate_uuid(), @@ -744,13 +752,11 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): return self._make_firewall_policy_dict(fwp_db) def create_firewall_policy(self, context, firewall_policy): - LOG.debug("create_firewall_policy() called") self._ensure_not_default_resource(firewall_policy, 'firewall_policy') return self._do_create_firewall_policy(context, firewall_policy) def update_firewall_policy(self, context, id, firewall_policy): - LOG.debug("update_firewall_policy() called") - fwp = firewall_policy['firewall_policy'] + fwp = firewall_policy with context.session.begin(subtransactions=True): fwp_db = self._get_firewall_policy(context, id) self._ensure_not_default_resource(fwp_db, 'firewall_policy', @@ -772,7 +778,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): return self._make_firewall_policy_dict(fwp_db) def delete_firewall_policy(self, context, id): - LOG.debug("delete_firewall_policy() called") with context.session.begin(subtransactions=True): fwp_db = self._get_firewall_policy(context, id) # check if policy in use @@ -786,35 +791,14 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): context.session.delete(fwp_db) def get_firewall_policy(self, context, id, fields=None): - LOG.debug("get_firewall_policy() called") fwp = self._get_firewall_policy(context, id) return self._make_firewall_policy_dict(fwp, fields) def get_firewall_policies(self, context, filters=None, fields=None): - LOG.debug("get_firewall_policies() called") return self._get_collection(context, FirewallPolicy, self._make_firewall_policy_dict, filters=filters, fields=fields) - def _validate_tenant_for_fwg_policies(self, context, fwg, fwg_tenant_id): - # On updates, all keys will not be present so fetch and validate. - if 'ingress_firewall_policy_id' in fwg: - fwp_id = fwg['ingress_firewall_policy_id'] - if fwp_id is not None: - fwp = self._get_firewall_policy(context, fwp_id) - if fwg_tenant_id != fwp['tenant_id'] and not fwp['shared']: - raise f_exc.FirewallPolicyConflict( - firewall_policy_id=fwp_id) - - if 'egress_firewall_policy_id' in fwg: - fwp_id = fwg['egress_firewall_policy_id'] - if fwp_id is not None: - fwp = self._get_firewall_policy(context, fwp_id) - if fwg_tenant_id != fwp['tenant_id'] and not fwp['shared']: - raise f_exc.FirewallPolicyConflict( - firewall_policy_id=fwp_id) - return - def _set_ports_for_firewall_group(self, context, fwg_db, fwg): port_id_list = fwg['ports'] if not port_id_list: @@ -833,7 +817,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): if exc_ports: raise f_exc.FirewallGroupPortInUse(port_ids=exc_ports) - def _get_ports_in_firewall_group(self, context, firewall_group_id): + def get_ports_in_firewall_group(self, context, firewall_group_id): """Get the Ports associated with the firewall group.""" with context.session.begin(subtransactions=True): fw_group_port_qry = context.session.query( @@ -852,27 +836,13 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): firewall_group_id=firewall_group_id).delete() return - def _validate_if_firewall_group_on_ports( - self, context, port_ids, fwg_id=None): - """Validate if ports are not associated with any firewall_group. - If any of the ports in the list is already associated with - a firewall_group, raise an exception else just return. - """ - fwg_port_qry = context.session.query( - FirewallGroupPortAssociation.port_id) - fwg_ports = fwg_port_qry.filter( - FirewallGroupPortAssociation.port_id.in_(port_ids), - FirewallGroupPortAssociation.firewall_group_id != fwg_id).all() - if fwg_ports: - port_ids = [entry.port_id for entry in fwg_ports] - raise f_exc.FirewallGroupPortInUse(port_ids=port_ids) - def _get_default_fwg_id(self, context, tenant_id): """Returns an id of default firewall group for given tenant or None""" default_fwg = self._model_query(context, FirewallGroup).filter_by( project_id=tenant_id, name=const.DEFAULT_FWG).first() if default_fwg: return default_fwg.id + return None def _ensure_default_firewall_group(self, context, tenant_id): """Create a default firewall group if one doesn't exist for a tenant @@ -905,19 +875,18 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): context, tenant_id, 'egress', **egress_fwp) fwg = { - 'firewall_group': - {'name': const.DEFAULT_FWG, - 'tenant_id': tenant_id, - 'ingress_firewall_policy_id': ingress_fwp_db['id'], - 'egress_firewall_policy_id': egress_fwp_db['id'], - 'ports': [], - 'shared': False, - 'admin_state_up': True, - 'description': 'Default firewall group'} + 'name': const.DEFAULT_FWG, + 'tenant_id': tenant_id, + 'ingress_firewall_policy_id': ingress_fwp_db['id'], + 'egress_firewall_policy_id': egress_fwp_db['id'], + 'ports': [], + 'shared': False, + 'status': nl_constants.INACTIVE, + 'admin_state_up': True, + 'description': 'Default firewall group', } fwg_db = self._create_firewall_group( - context, fwg, status=nl_constants.INACTIVE, - default_fwg=True) + context, fwg, default_fwg=True) context.session.add(DefaultFirewallGroup( firewall_group_id=fwg_db['id'], project_id=tenant_id)) @@ -928,37 +897,36 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): LOG.debug("Default FWG was concurrently created") return self._get_default_fwg_id(context, tenant_id) - def _create_firewall_group(self, context, firewall_group, status=None, + def _create_firewall_group(self, context, firewall_group, default_fwg=False): """Create a firewall group If default_fwg is True then a default firewall group is being created for a given tenant. """ - fwg = firewall_group['firewall_group'] + fwg = firewall_group tenant_id = fwg['tenant_id'] - if not status: - status = (nl_constants.CREATED if cfg.CONF.router_distributed - else nl_constants.PENDING_CREATE) + if firewall_group.get('status') is None: + fwg['status'] = nl_constants.CREATED + if default_fwg: # A default firewall group is being created. default_fwg_id = self._get_default_fwg_id(context, tenant_id) if default_fwg_id is not None: # Default fwg for a given tenant exists, fetch it and return - return self.get_firewall_group(default_fwg_id) + return self.get_firewall_group(context, default_fwg_id) else: # An ordinary firewall group is being created BUT let's make sure # that a default firewall group for given tenant exists self._ensure_default_firewall_group(context, tenant_id) - self._validate_tenant_for_fwg_policies(context, fwg, tenant_id) with context.session.begin(subtransactions=True): fwg_db = FirewallGroup( id=uuidutils.generate_uuid(), tenant_id=tenant_id, name=fwg['name'], description=fwg['description'], - status=status, + status=fwg['status'], ingress_firewall_policy_id=fwg['ingress_firewall_policy_id'], egress_firewall_policy_id=fwg['egress_firewall_policy_id'], admin_state_up=fwg['admin_state_up'], @@ -967,15 +935,14 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): self._set_ports_for_firewall_group(context, fwg_db, fwg) return self._make_firewall_group_dict(fwg_db) - def create_firewall_group(self, context, firewall_group, status=None): + def create_firewall_group(self, context, firewall_group): self._ensure_not_default_resource(firewall_group, 'firewall_group') - return self._create_firewall_group(context, firewall_group, status) + return self._create_firewall_group(context, firewall_group) def update_firewall_group(self, context, id, firewall_group): - LOG.debug("update_firewall_group() called") - fwg = firewall_group['firewall_group'] + fwg = firewall_group # make sure that no group can be updated to have name=default - self._ensure_not_default_resource(firewall_group, 'firewall_group') + self._ensure_not_default_resource(fwg, 'firewall_group') with context.session.begin(subtransactions=True): fwg_db = self.get_firewall_group(context, id) if _is_default(fwg_db): @@ -990,8 +957,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): raise FirewallDefaultObjectUpdateRestricted( resource_type='Firewall Group', resource_id=fwg_db['id']) - self._validate_tenant_for_fwg_policies(context, - fwg, fwg_db['tenant_id']) if 'ports' in fwg: LOG.debug("Ports are updated in Firewall Group") self._delete_ports_in_firewall_group(context, id) @@ -1021,7 +986,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): def delete_firewall_group(self, context, id): # Note: Plugin should ensure that it's okay to delete if the # firewall is active - LOG.debug("delete_firewall_group() called") with context.session.begin(subtransactions=True): # if no such group exists -> don't raise an exception according to @@ -1077,12 +1041,10 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): resource_type='Firewall Policy', name=resource['name']) def get_firewall_group(self, context, id, fields=None): - LOG.debug("get_firewall_group() called") fw = self._get_firewall_group(context, id) return self._make_firewall_group_dict(fw, fields) def get_firewall_groups(self, context, filters=None, fields=None): - LOG.debug("get_firewall_groups() called") if context.tenant_id: tenant_id = filters.get('tenant_id') if filters else None tenant_id = tenant_id[0] if tenant_id else context.tenant_id @@ -1091,48 +1053,6 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): self._make_firewall_group_dict, filters=filters, fields=fields) - def get_firewall_group_for_port(self, context, port_id): - """Get firewall group is associated with a port - - :param context: context object - :param port_id: Port ID. - """ - filters = {'port_id': [port_id]} - fwg_port_binding = self._get_collection_query( - context, FirewallGroupPortAssociation, filters=filters).first() - if fwg_port_binding: - fwg_id = fwg_port_binding['firewall_group_id'] - return self._make_firewall_group_dict_with_rules(context, fwg_id) - - def _get_default_fwg(self, context, project_id): - query = self._model_query(context, DefaultFirewallGroup) - def_fwg_id = query.filter_by( - project_id=project_id).one().firewall_group_id - return self.get_firewall_group(context, def_fwg_id) - - def set_port_for_default_firewall_group(self, context, port_id, - project_id): - """Set a port into default firewall group - - :param context: Context object - :param port_id: Port ID - :param project_id: ProjectID - """ - with context.session.begin(subtransactions=True): - def_fwg_db = self._get_default_fwg(context, project_id) - try: - self._set_ports_for_firewall_group( - context, def_fwg_db, {'ports': [port_id]}) - except f_exc.FirewallGroupPortInUse: - LOG.warning("Port %s has been already associated with default " - "firewall group %s and skip association", port_id, - def_fwg_db['id']) - else: - # Update default fwg status to PENDING_UPDATE to wait updating - # from agent - self.update_firewall_group_status( - context, def_fwg_db['id'], nl_constants.PENDING_UPDATE) - def _is_default(fwg_db): return fwg_db['name'] == const.DEFAULT_FWG diff --git a/neutron_fwaas/extensions/firewall_v2.py b/neutron_fwaas/extensions/firewall_v2.py index f92d718c0..25aff1578 100644 --- a/neutron_fwaas/extensions/firewall_v2.py +++ b/neutron_fwaas/extensions/firewall_v2.py @@ -126,6 +126,7 @@ class Firewallv2PluginBase(service_base.ServicePluginBase): def get_plugin_description(self): return 'Firewall Service v2 Plugin' + # Firewall Group @abc.abstractmethod def create_firewall_group(self, context, firewall_group): pass @@ -135,7 +136,7 @@ class Firewallv2PluginBase(service_base.ServicePluginBase): pass @abc.abstractmethod - def get_firewall_group(self, context, id): + def get_firewall_group(self, context, id, fields=None): pass @abc.abstractmethod @@ -146,24 +147,13 @@ class Firewallv2PluginBase(service_base.ServicePluginBase): def update_firewall_group(self, context, id, firewall_group): pass + # Firewall Policy @abc.abstractmethod - def get_firewall_rules(self, context, filters=None, fields=None): + def create_firewall_policy(self, context, firewall_policy): pass @abc.abstractmethod - def get_firewall_rule(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_firewall_rule(self, context, firewall_rule): - pass - - @abc.abstractmethod - def update_firewall_rule(self, context, id, firewall_rule): - pass - - @abc.abstractmethod - def delete_firewall_rule(self, context, id): + def delete_firewall_policy(self, context, id): pass @abc.abstractmethod @@ -174,16 +164,29 @@ class Firewallv2PluginBase(service_base.ServicePluginBase): def get_firewall_policies(self, context, filters=None, fields=None): pass - @abc.abstractmethod - def create_firewall_policy(self, context, firewall_policy): - pass - @abc.abstractmethod def update_firewall_policy(self, context, id, firewall_policy): pass + # Firewall Rule @abc.abstractmethod - def delete_firewall_policy(self, context, id): + def create_firewall_rule(self, context, firewall_rule): + pass + + @abc.abstractmethod + def delete_firewall_rule(self, context, id): + pass + + @abc.abstractmethod + def get_firewall_rule(self, context, id, fields=None): + pass + + @abc.abstractmethod + def get_firewall_rules(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def update_firewall_rule(self, context, id, firewall_rule): pass @abc.abstractmethod diff --git a/neutron_fwaas/opts.py b/neutron_fwaas/opts.py index 017042d0a..069445d39 100644 --- a/neutron_fwaas/opts.py +++ b/neutron_fwaas/opts.py @@ -10,19 +10,25 @@ # License for the specific language governing permissions and limitations # under the License. +import neutron.conf.services.provider_configuration + +import neutron_fwaas.services.firewall.service_drivers.agents.\ + firewall_agent_api import neutron_fwaas.extensions.firewall -import neutron_fwaas.services.firewall.agents.firewall_agent_api def list_agent_opts(): return [ ('fwaas', - neutron_fwaas.services.firewall.agents.firewall_agent_api.FWaaSOpts) + neutron_fwaas.services.firewall.service_drivers.agents. + firewall_agent_api.FWaaSOpts), ] def list_opts(): return [ ('quotas', - neutron_fwaas.extensions.firewall.firewall_quota_opts) + neutron_fwaas.extensions.firewall.firewall_quota_opts), + ('service_providers', + neutron.conf.services.provider_configuration.serviceprovider_opts), ] diff --git a/neutron_fwaas/services/firewall/fwaas_plugin_v2.py b/neutron_fwaas/services/firewall/fwaas_plugin_v2.py index 0dc6457d4..8004b0427 100644 --- a/neutron_fwaas/services/firewall/fwaas_plugin_v2.py +++ b/neutron_fwaas/services/firewall/fwaas_plugin_v2.py @@ -12,238 +12,138 @@ # License for the specific language governing permissions and limitations # under the License. -from neutron.common import rpc as n_rpc from neutron.db import servicetype_db as st_db from neutron.services import provider_configuration as provider_conf +from neutron.services import service_base from neutron_lib.api.definitions import firewall_v2 from neutron_lib.api.definitions import portbindings as pb_def +from neutron_lib.api import validators from neutron_lib.callbacks import events from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources from neutron_lib import constants as nl_constants -from neutron_lib import context as neutron_context from neutron_lib.exceptions import firewall_v2 as f_exc -from neutron_lib.plugins import constants as plugin_const from neutron_lib.plugins import directory -from oslo_config import cfg +from oslo_log import helpers as log_helpers from oslo_log import log as logging -import oslo_messaging from neutron_fwaas.common import exceptions from neutron_fwaas.common import fwaas_constants -from neutron_fwaas.db.firewall.v2 import firewall_db_v2 +from neutron_fwaas.extensions.firewall_v2 import Firewallv2PluginBase LOG = logging.getLogger(__name__) -def add_provider_configuration(type_manager, service_type): - type_manager.add_provider_configuration( - service_type, - provider_conf.ProviderConfiguration('neutron_fwaas')) - - -class FirewallAgentApi(object): - """Plugin side of plugin to agent RPC API.""" - - def __init__(self, topic, host): - self.host = host - target = oslo_messaging.Target(topic=topic, version='1.0') - self.client = n_rpc.get_client(target) - - def create_firewall_group(self, context, firewall_group): - cctxt = self.client.prepare(fanout=True) - cctxt.cast(context, 'create_firewall_group', - firewall_group=firewall_group, - host=self.host) - - def update_firewall_group(self, context, firewall_group): - cctxt = self.client.prepare(fanout=True) - cctxt.cast(context, 'update_firewall_group', - firewall_group=firewall_group, - host=self.host) - - def delete_firewall_group(self, context, firewall_group): - cctxt = self.client.prepare(fanout=True) - cctxt.cast(context, 'delete_firewall_group', - firewall_group=firewall_group, - host=self.host) - - -class FirewallCallbacks(object): - target = oslo_messaging.Target(version='1.0') - - def __init__(self, plugin): - super(FirewallCallbacks, self).__init__() - self.plugin = plugin - - def set_firewall_group_status(self, context, fwg_id, status, **kwargs): - """Agent uses this to set a firewall_group's status.""" - LOG.debug("Setting firewall_group %s to status: %s", - fwg_id, status) - # Sanitize status first - if status in (nl_constants.ACTIVE, nl_constants.DOWN, - nl_constants.INACTIVE): - to_update = status - else: - to_update = nl_constants.ERROR - # ignore changing status if firewall_group expects to be deleted - # That case means that while some pending operation has been - # performed on the backend, neutron server received delete request - # and changed firewall status to PENDING_DELETE - updated = self.plugin.update_firewall_group_status( - context, fwg_id, to_update, not_in=(nl_constants.PENDING_DELETE,)) - if updated: - LOG.debug("firewall %s status set: %s", fwg_id, to_update) - return updated and to_update != nl_constants.ERROR - - def firewall_group_deleted(self, context, fwg_id, **kwargs): - """Agent uses this to indicate firewall is deleted.""" - LOG.debug("firewall_group_deleted() called") - try: - with context.session.begin(subtransactions=True): - fwg_db = self.plugin._get_firewall_group(context, fwg_id) - # allow to delete firewalls in ERROR state - if fwg_db.status in (nl_constants.PENDING_DELETE, - nl_constants.ERROR): - self.plugin.delete_db_firewall_group_object(context, - fwg_id) - return True - else: - LOG.warning(('Firewall %(fwg)s unexpectedly deleted by ' - 'agent, status was %(status)s'), - {'fwg': fwg_id, 'status': fwg_db.status}) - fwg_db.update({"status": nl_constants.ERROR}) - return False - except f_exc.FirewallGroupNotFound: - LOG.info('Firewall group %s already deleted', fwg_id) - return True - - def get_firewall_groups_for_project(self, context, **kwargs): - """Gets all firewall_groups and rules on a project.""" - LOG.debug("get_firewall_groups_for_project() called") - fwg_list = [] - for fwg in self.plugin.get_firewall_groups(context): - fwg_with_rules = self.plugin._make_firewall_group_dict_with_rules( - context, fwg['id']) - if fwg['status'] == nl_constants.PENDING_DELETE: - fwg_with_rules['add-port-ids'] = [] - fwg_with_rules['del-port-ids'] = ( - self.plugin._get_ports_in_firewall_group(context, - fwg['id'])) - else: - fwg_with_rules['add-port-ids'] = ( - self.plugin._get_ports_in_firewall_group(context, - fwg['id'])) - fwg_with_rules['del-port-ids'] = [] - fwg_list.append(fwg_with_rules) - return fwg_list - - def get_projects_with_firewall_groups(self, context, **kwargs): - """Get all projects that have firewall_groups.""" - LOG.debug("get_projects_with_firewall_groups() called") - ctx = neutron_context.get_admin_context() - fwg_list = self.plugin.get_firewall_groups(ctx) - fwg_project_list = list(set(fwg['tenant_id'] for fwg in fwg_list)) - return fwg_project_list - - def get_firewall_group_for_port(self, context, **kwargs): - """Get firewall_group is associated with a port.""" - LOG.debug("get_firewall_group_for_port() called") - ctx = context.elevated() - return self.plugin.get_firewall_group_for_port( - ctx, kwargs.get('port_id')) - - @registry.has_registry_receivers -class FirewallPluginV2( - firewall_db_v2.Firewall_db_mixin_v2): - """Implementation of the Neutron Firewall Service Plugin. +class FirewallPluginV2(Firewallv2PluginBase): + """Firewall v2 Neutron service plugin class""" - This class manages the workflow of FWaaS request/response. - Most DB related works are implemented in class - firewall_db_v2.Firewall_db_mixin_v2. - """ - supported_extension_aliases = ["fwaas_v2"] + supported_extension_aliases = [firewall_v2.ALIAS] path_prefix = firewall_v2.API_PREFIX def __init__(self): + super(FirewallPluginV2, self).__init__() """Do the initialization for the firewall service plugin here.""" - self.service_type_manager = st_db.ServiceTypeManager.get_instance() - add_provider_configuration( - self.service_type_manager, plugin_const.FIREWALL) - self.start_rpc_listeners() + # Initialize the Firewall v2 service plugin + service_type_manager = st_db.ServiceTypeManager.get_instance() + service_type_manager.add_provider_configuration( + fwaas_constants.FIREWALL_V2, + provider_conf.ProviderConfiguration('neutron_fwaas')) - self.agent_rpc = FirewallAgentApi( - fwaas_constants.FW_AGENT, - cfg.CONF.host - ) + # Load the default driver + drivers, default_provider = service_base.load_drivers( + fwaas_constants.FIREWALL_V2, self) + LOG.info("Firewall v2 Service Plugin using Service Driver: %s", + default_provider) + + if len(drivers) > 1: + LOG.warning("Multiple drivers configured for Firewall v2, " + "although running multiple drivers in parallel is " + "not yet supported") + + self.driver = drivers[default_provider] @property def _core_plugin(self): return directory.get_plugin() - def start_rpc_listeners(self): - self.endpoints = [FirewallCallbacks(self)] - - self.conn = n_rpc.Connection() - self.conn.create_consumer( - fwaas_constants.FIREWALL_PLUGIN, self.endpoints, fanout=False) - return self.conn.consume_in_threads() - - def _rpc_update_firewall_group(self, context, fwg_id): - status_update = {"firewall_group": {"status": - nl_constants.PENDING_UPDATE}} - super(FirewallPluginV2, self).update_firewall_group( - context, fwg_id, status_update) - fwg_with_rules = self._make_firewall_group_dict_with_rules(context, - fwg_id) - # this is triggered on an update to fwg rule or policy, no - # change in associated ports. - fwg_with_rules['add-port-ids'] = self._get_ports_in_firewall_group( - context, fwg_id) - fwg_with_rules['del-port-ids'] = [] - fwg_with_rules['port_details'] = self._get_fwg_port_details( - context, fwg_with_rules['add-port-ids']) - self.agent_rpc.update_firewall_group(context, fwg_with_rules) - - def _rpc_update_firewall_policy(self, context, firewall_policy_id): - firewall_policy = self.get_firewall_policy(context, firewall_policy_id) - if firewall_policy: - ing_fwg_ids, eg_fwg_ids = self._get_fwgs_with_policy(context, - firewall_policy_id) - for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)): - self._rpc_update_firewall_group(context, fwg_id) - def _ensure_update_firewall_group(self, context, fwg_id): + """Checks if the firewall group can be updated + + Raises FirewallGroupInPendingState if the firewall group is in pending + state. + :param context: neutron context + :param fwg_id: firewall group ID to check + :return: Firewall group dict + """ fwg = self.get_firewall_group(context, fwg_id) if fwg['status'] in [nl_constants.PENDING_CREATE, nl_constants.PENDING_UPDATE, nl_constants.PENDING_DELETE]: - raise f_exc.FirewallGroupInPendingState(firewall_id=fwg_id, - pending_state=fwg['status']) + raise f_exc.FirewallGroupInPendingState( + firewall_id=fwg_id, pending_state=fwg['status']) + return fwg - def _ensure_update_firewall_policy(self, context, firewall_policy_id): - firewall_policy = self.get_firewall_policy(context, firewall_policy_id) - if firewall_policy: - ing_fwg_ids, eg_fwg_ids = self._get_fwgs_with_policy( - context, firewall_policy_id) - for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)): - self._ensure_update_firewall_group(context, fwg_id) + def _ensure_update_firewall_policy(self, context, fwp_id): + """Checks if the firewall policy can be updated + + Fetch firewall group associated to the policy and checks if they can be + updated. + :param context: neutron context + :param fwp_id: firewall policy ID to check + """ + fwp = self.get_firewall_policy(context, fwp_id) + ing_fwg_ids, eg_fwg_ids = self._get_fwgs_with_policy(context, fwp) + for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)): + self._ensure_update_firewall_group(context, fwg_id) def _ensure_update_firewall_rule(self, context, fwr_id): - fwp_ids = self._get_policies_with_rule(context, fwr_id) + """Checks if the firewall rule can be updated + + Fetch firewall policy associated to the rule and checks if they can be + updated. + :param context: neutron context + :param fwr_id: firewall policy ID to check + """ + fwr = self.get_firewall_rule(context, fwr_id) + fwp_ids = self._get_policies_with_rule(context, fwr) for fwp_id in fwp_ids: self._ensure_update_firewall_policy(context, fwp_id) + def _validate_firewall_policies_for_firewall_group(self, context, fwg): + """Validate firewall group and policy owner + + Check if the firewall policy is not shared, it have the same project + owner than the friewall group. + :param context: neutron context + :param fwg: firewall group to validate + """ + for policy_type in ['ingress_firewall_policy_id', + 'egress_firewall_policy_id']: + if fwg.get(policy_type): + fwp = self.get_firewall_policy(context, fwg[policy_type]) + if fwg['tenant_id'] != fwp['tenant_id'] and not fwp['shared']: + raise f_exc.FirewallPolicyConflict( + firewall_policy_id=fwg[policy_type]) + def _validate_ports_for_firewall_group(self, context, tenant_id, fwg_ports): + """Validate firewall group associated ports + + Check if the firewall group associated ports have the same project + owner and is router interface type or a compute layer 2. + :param context: neutron context + :param tenant_id: firewall group project ID + :param fwg_ports: firewall group associated ports + """ # TODO(sridar): elevated context and do we want to use public ? for port_id in fwg_ports: - port_db = self._core_plugin._get_port(context, port_id) - if port_db['tenant_id'] != tenant_id: + port = self._core_plugin.get_port(context, port_id) + + if port['tenant_id'] != tenant_id: raise f_exc.FirewallGroupPortInvalidProject( - port_id=port_id, project_id=port_db['tenant_id']) - device_owner = port_db.get('device_owner', '') + port_id=port_id, project_id=port['tenant_id']) + device_owner = port.get('device_owner', '') if (device_owner not in [nl_constants.DEVICE_OWNER_ROUTER_INTF] and not device_owner.startswith( nl_constants.DEVICE_OWNER_COMPUTE_PREFIX)): @@ -253,6 +153,8 @@ class FirewallPluginV2( self._is_supported_by_fw_l2_driver(context, port_id)): raise exceptions.FirewallGroupPortNotSupported(port_id=port_id) + # TODO(ethuleau): move that check in the driver. Each driver can have + # different support def _is_supported_by_fw_l2_driver(self, context, port_id): """Whether this port is supported by firewall l2 driver""" @@ -277,49 +179,80 @@ class FirewallPluginV2( LOG.warning("Doesn't support vif type %s", port[pb_def.VIF_TYPE]) return False - def _check_no_need_pending(self, context, fwg_id, fwg_body): - fwg_db = self._get_firewall_group(context, fwg_id) - fwp_req_in = fwg_body.get('ingress_firewall_policy_id', None) - fwp_req_eg = fwg_body.get('egress_firewall_policy_id', None) + def _validate_if_firewall_group_on_ports(self, context, firewall_group, + id=None): + """Validate if ports are not associated with any firewall_group. - if ((not fwg_db.ingress_firewall_policy_id and - fwp_req_in is fwg_db.ingress_firewall_policy_id) and - (not fwg_db.egress_firewall_policy_id and - fwp_req_eg is fwg_db.ingress_firewall_policy_id)): - return True - return False + If any of the ports in the list is already associated with + a firewall group, raise an exception else just return. + :param context: neutron context + :param fwg: firewall group to validate + """ + if 'ports' not in firewall_group or not firewall_group['ports']: + return - def _get_fwg_port_details(self, context, fwg_ports): - """Returns a dictionary list of port details. """ - port_details = {} - for port_id in fwg_ports: - port_db = self._core_plugin.get_port(context, port_id) - # Add more parameters below based on requirement. - device_owner = port_db['device_owner'] - port_details[port_id] = { - 'device_owner': device_owner, - 'device': port_db['id'], - 'network_id': port_db['network_id'], - 'fixed_ips': port_db['fixed_ips'], - 'allowed_address_pairs': - port_db.get('allowed_address_pairs', []), - 'port_security_enabled': - port_db.get('port_security_enabled', True), - 'id': port_db['id'] - } - if device_owner.startswith( - nl_constants.DEVICE_OWNER_COMPUTE_PREFIX): - port_details[port_id].update( - {'host': port_db[pb_def.HOST_ID]}) - return port_details + filters = { + 'tenant_id': [firewall_group['tenant_id']], + 'ports': firewall_group['ports'], + } + ports_in_use = set() + for fwg in self.get_firewall_groups(context, filters=filters): + if id is not None and fwg['id'] == id: + continue + ports_in_use |= set(fwg.get('ports', [])) & \ + set(firewall_group['ports']) + if ports_in_use: + raise f_exc.FirewallGroupPortInUse(port_ids=list(ports_in_use)) - def get_project_id_from_port_id(self, context, port_id): - """Returns an ID of project for specified port_id. """ - return self._core_plugin.get_port(context, port_id)['project_id'] + def _get_fwgs_with_policy(self, context, firewall_policy): + """List firewall group IDs which use a firewall policy + + List all firewall group IDs which have the given firewall policy as + ingress or egress. + :param context: neutron context + :param firewall_policy: firewall policy to filter + """ + filters = { + 'tenant_id': [firewall_policy['tenant_id']], + 'ingress_firewall_policy_id': [firewall_policy['id']], + } + ingress_fwp_ids = [fwg['id'] + for fwg in self.get_firewall_groups( + context, filters=filters)] + + filters = { + 'tenant_id': [firewall_policy['tenant_id']], + 'egress_firewall_policy_id': [firewall_policy['id']], + } + egress_fwp_ids = [fwg['id'] + for fwg in self.get_firewall_groups( + context, filters=filters)] + + return ingress_fwp_ids, egress_fwp_ids + + def _get_policies_with_rule(self, context, firewall_rule): + filters = { + 'tenant_id': [firewall_rule['tenant_id']], + 'firewall_rules': [firewall_rule['id']], + } + return [fwp['id'] for fwp in self.get_firewall_policies( + context, filters=filters)] + + def _validate_insert_remove_rule_request(self, rule_info): + """Validate rule_info dict + + Check that all mandatory fields are present, otherwise raise + proper exception. + """ + if not rule_info or 'firewall_rule_id' not in rule_info: + raise f_exc.FirewallRuleInfoMissing() + # Validator doesn't return anything if the check passes + if validators.validate_uuid(rule_info['firewall_rule_id']): + raise f_exc.FirewallRuleNotFound( + firewall_rule_id=rule_info['firewall_rule_id']) @registry.receives(resources.PORT, [events.AFTER_UPDATE]) def handle_update_port(self, resource, event, trigger, **kwargs): - updated_port = kwargs['port'] if not updated_port['device_owner'].startswith( nl_constants.DEVICE_OWNER_COMPUTE_PREFIX): @@ -340,169 +273,145 @@ class FirewallPluginV2( return project_id = updated_port['project_id'] - LOG.debug("Try to associate port %s at %s", port_id, project_id) - self.set_port_for_default_firewall_group(context, port_id, project_id) + fwgs = self.get_firewall_groups( + context, + filters={ + 'tenant_id': [project_id], + 'name': [fwaas_constants.DEFAULT_FWG], + }, + fields=['id', 'ports'], + ) + if len(fwgs) != 1: + # Cannot found default Firewall Group, abandon + LOG.warning("Cannot found default firewall group of project %s", + project_id) + return + default_fwg = fwgs[0] + # Add default firewall group to the port + port_ids = default_fwg.get('ports', []) + [port_id] + try: + self.update_firewall_group(context, default_fwg['id'], + {'firewall_group': {'ports': port_ids}}) + except f_exc.FirewallGroupPortInUse: + LOG.warning("Port %s has been already associated with default " + "firewall group %s and skip association", port_id, + default_fwg['id']) + + # Firewall Group + @log_helpers.log_method_call def create_firewall_group(self, context, firewall_group): - LOG.debug("create_firewall_group() called") - fwgrp = firewall_group['firewall_group'] - fwg_ports = fwgrp['ports'] + firewall_group = firewall_group['firewall_group'] + ports = firewall_group.get('ports', []) - if not fwg_ports: - # no messaging to agent needed, and fw needs to go - # to INACTIVE(no associated ports) state. - status = nl_constants.INACTIVE - fwg = super(FirewallPluginV2, self).create_firewall_group( - context, firewall_group, status) - fwg['ports'] = [] - return fwg - else: - # Validate ports - self._validate_ports_for_firewall_group(context, - firewall_group['firewall_group']['tenant_id'], fwg_ports) + self._validate_firewall_policies_for_firewall_group(context, + firewall_group) + # Validate ports owner type and project + self._validate_ports_for_firewall_group(context, + firewall_group['tenant_id'], + ports) - if (not fwgrp['ingress_firewall_policy_id'] and - not fwgrp['egress_firewall_policy_id']): - # No policy configured - status = nl_constants.INACTIVE - fwg = super(FirewallPluginV2, self).create_firewall_group( - context, firewall_group, status) - return fwg + self._validate_if_firewall_group_on_ports(context, firewall_group) - fwg = super(FirewallPluginV2, self).create_firewall_group( - context, firewall_group) - fwg['ports'] = fwg_ports - - fwg_with_rules = ( - self._make_firewall_group_dict_with_rules(context, fwg['id'])) - - fwg_with_rules['add-port-ids'] = fwg_ports - fwg_with_rules['del-port-ids'] = [] - fwg_with_rules['port_details'] = self._get_fwg_port_details( - context, fwg_ports) - - self.agent_rpc.create_firewall_group(context, fwg_with_rules) - - return fwg - - def update_firewall_group(self, context, id, firewall_group): - LOG.debug("update_firewall_group() called on firewall_group %s", id) - - self._ensure_update_firewall_group(context, id) - - # TODO(sridar): need closure on status when no policy associated. - fwg_current_ports = fwg_new_ports = self._get_ports_in_firewall_group( - context, id) - if 'ports' in firewall_group['firewall_group']: - fwg_new_ports = firewall_group['firewall_group']['ports'] - if len(fwg_new_ports) > 0: - self._validate_ports_for_firewall_group( - context, context.project_id, fwg_new_ports) - - if ((not fwg_new_ports and not fwg_current_ports) or - self._check_no_need_pending(context, - id, firewall_group['firewall_group'])): - # no messaging to agent needed, and we need to continue - # in INACTIVE state - firewall_group['firewall_group']['status'] = nl_constants.INACTIVE - fwg = super(FirewallPluginV2, self).update_firewall_group( - context, id, firewall_group) - if fwg_new_ports: - fwg['ports'] = fwg_new_ports - elif not fwg_new_ports and fwg_current_ports: - fwg['ports'] = fwg_current_ports - else: - fwg['ports'] = [] - return fwg - else: - firewall_group['firewall_group']['status'] = (nl_constants. - PENDING_UPDATE) - fwg = super(FirewallPluginV2, self).update_firewall_group( - context, id, firewall_group) - fwg['ports'] = fwg_new_ports - - fwg_with_rules = ( - self._make_firewall_group_dict_with_rules(context, fwg['id'])) - - # determine ports to add fw to and del from - fwg_with_rules['add-port-ids'] = fwg_new_ports - fwg_with_rules['del-port-ids'] = list( - set(fwg_current_ports).difference(set(fwg_new_ports))) - - # last-port drives agent to ack with status to set state to INACTIVE - fwg_with_rules['last-port'] = not fwg_new_ports - - LOG.debug("update_firewall_group %s: Add Ports: %s, Del Ports: %s", - fwg['id'], - fwg_with_rules['add-port-ids'], - fwg_with_rules['del-port-ids']) - - fwg_with_rules['port_details'] = self._get_fwg_port_details( - context, fwg_with_rules['del-port-ids']) - fwg_with_rules['port_details'].update(self._get_fwg_port_details( - context, fwg_with_rules['add-port-ids'])) - self.agent_rpc.update_firewall_group(context, fwg_with_rules) - - return fwg - - def delete_db_firewall_group_object(self, context, id): - super(FirewallPluginV2, self).delete_firewall_group(context, id) + return self.driver.create_firewall_group(context, firewall_group) + @log_helpers.log_method_call def delete_firewall_group(self, context, id): - LOG.debug("delete_firewall_group() called on firewall_group %s", id) + # if no such group exists -> don't raise an exception according to + # 80fe2ba1, return None + try: + fwg = self.get_firewall_group(context, id) + except f_exc.FirewallGroupNotFound: + return - fwg_db = self._get_firewall_group(context, id) - - if fwg_db['status'] == nl_constants.ACTIVE: + if fwg['status'] == nl_constants.ACTIVE: raise f_exc.FirewallGroupInUse(firewall_id=id) - fwg_with_rules = ( - self._make_firewall_group_dict_with_rules(context, id)) - fwg_with_rules['del-port-ids'] = self._get_ports_in_firewall_group( - context, id) - fwg_with_rules['add-port-ids'] = [] - if not fwg_with_rules['del-port-ids']: - # no ports, no need to talk to the agent - self.delete_db_firewall_group_object(context, id) - else: - status = {"firewall_group": {"status": - nl_constants.PENDING_DELETE}} - super(FirewallPluginV2, self).update_firewall_group( - context, id, status) - # Reflect state change in fwg_with_rules - fwg_with_rules['status'] = status['firewall_group']['status'] - fwg_with_rules['port_details'] = self._get_fwg_port_details( - context, fwg_with_rules['del-port-ids']) - self.agent_rpc.delete_firewall_group(context, fwg_with_rules) + self.driver.delete_firewall_group(context, id) + @log_helpers.log_method_call + def get_firewall_group(self, context, id, fields=None): + return self.driver.get_firewall_group(context, id, fields=fields) + + @log_helpers.log_method_call + def get_firewall_groups(self, context, filters=None, fields=None): + return self.driver.get_firewall_groups(context, filters, fields) + + @log_helpers.log_method_call + def update_firewall_group(self, context, id, firewall_group): + firewall_group = firewall_group['firewall_group'] + ports = firewall_group.get('ports', []) + + old_firewall_group = self._ensure_update_firewall_group(context, id) + firewall_group['tenant_id'] = old_firewall_group['tenant_id'] + + self._validate_firewall_policies_for_firewall_group(context, + firewall_group) + # Validate ports owner type and project + self._validate_ports_for_firewall_group(context, + firewall_group['tenant_id'], + ports) + self._validate_if_firewall_group_on_ports(context, firewall_group, + id=id) + + return self.driver.update_firewall_group(context, id, firewall_group) + + # Firewall Policy + @log_helpers.log_method_call + def create_firewall_policy(self, context, firewall_policy): + firewall_policy = firewall_policy['firewall_policy'] + return self.driver.create_firewall_policy(context, firewall_policy) + + @log_helpers.log_method_call + def delete_firewall_policy(self, context, id): + self.driver.delete_firewall_policy(context, id) + + @log_helpers.log_method_call + def get_firewall_policy(self, context, id, fields=None): + return self.driver.get_firewall_policy(context, id, fields) + + @log_helpers.log_method_call + def get_firewall_policies(self, context, filters=None, fields=None): + return self.driver.get_firewall_policies(context, filters, fields) + + @log_helpers.log_method_call def update_firewall_policy(self, context, id, firewall_policy): - LOG.debug("update_firewall_policy() called") + firewall_policy = firewall_policy['firewall_policy'] self._ensure_update_firewall_policy(context, id) - fwp = super(FirewallPluginV2, - self).update_firewall_policy(context, id, firewall_policy) - self._rpc_update_firewall_policy(context, id) - return fwp + return self.driver.update_firewall_policy(context, id, firewall_policy) + # Firewall Rule + @log_helpers.log_method_call + def create_firewall_rule(self, context, firewall_rule): + firewall_rule = firewall_rule['firewall_rule'] + return self.driver.create_firewall_rule(context, firewall_rule) + + @log_helpers.log_method_call + def delete_firewall_rule(self, context, id): + self.driver.delete_firewall_rule(context, id) + + @log_helpers.log_method_call + def get_firewall_rule(self, context, id, fields=None): + return self.driver.get_firewall_rule(context, id, fields) + + @log_helpers.log_method_call + def get_firewall_rules(self, context, filters=None, fields=None): + return self.driver.get_firewall_rules(context, filters, fields) + + @log_helpers.log_method_call def update_firewall_rule(self, context, id, firewall_rule): - LOG.debug("update_firewall_rule() called") + firewall_rule = firewall_rule['firewall_rule'] self._ensure_update_firewall_rule(context, id) - fwr = super(FirewallPluginV2, - self).update_firewall_rule(context, id, firewall_rule) - fwp_ids = self._get_policies_with_rule(context, id) - for fwp_id in fwp_ids: - self._rpc_update_firewall_policy(context, fwp_id) - return fwr + return self.driver.update_firewall_rule(context, id, firewall_rule) - def insert_rule(self, context, id, rule_info): - LOG.debug("insert_rule() called") - self._ensure_update_firewall_policy(context, id) - fwp = super(FirewallPluginV2, self).insert_rule(context, id, rule_info) - self._rpc_update_firewall_policy(context, id) - return fwp + @log_helpers.log_method_call + def insert_rule(self, context, policy_id, rule_info): + self._ensure_update_firewall_policy(context, policy_id) + self._validate_insert_remove_rule_request(rule_info) + return self.driver.insert_rule(context, policy_id, rule_info) - def remove_rule(self, context, id, rule_info): - LOG.debug("remove_rule() called") - self._ensure_update_firewall_policy(context, id) - fwp = super(FirewallPluginV2, self).remove_rule(context, id, rule_info) - self._rpc_update_firewall_policy(context, id) - return fwp + @log_helpers.log_method_call + def remove_rule(self, context, policy_id, rule_info): + self._ensure_update_firewall_policy(context, policy_id) + self._validate_insert_remove_rule_request(rule_info) + return self.driver.remove_rule(context, policy_id, rule_info) diff --git a/neutron_fwaas/services/firewall/agents/__init__.py b/neutron_fwaas/services/firewall/service_drivers/__init__.py similarity index 100% rename from neutron_fwaas/services/firewall/agents/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/__init__.py diff --git a/neutron_fwaas/services/firewall/agents/l2/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/__init__.py similarity index 100% rename from neutron_fwaas/services/firewall/agents/l2/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/__init__.py diff --git a/neutron_fwaas/services/firewall/service_drivers/agents/agents.py b/neutron_fwaas/services/firewall/service_drivers/agents/agents.py new file mode 100644 index 000000000..be9a3d48e --- /dev/null +++ b/neutron_fwaas/services/firewall/service_drivers/agents/agents.py @@ -0,0 +1,355 @@ +# Copyright (c) 2013 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from neutron.common import rpc as neutron_rpc +from neutron_lib.api.definitions import portbindings as pb_def +from neutron_lib import constants as nl_constants +from neutron_lib import context as neutron_context +from neutron_lib.exceptions import firewall_v2 as f_exc +from oslo_config import cfg +from oslo_log import helpers as log_helpers +from oslo_log import log as logging +import oslo_messaging + +from neutron_fwaas.common import fwaas_constants as constants +from neutron_fwaas.services.firewall.service_drivers import driver_api + + +LOG = logging.getLogger(__name__) + + +class FirewallAgentCallbacks(object): + target = oslo_messaging.Target(version='1.0') + + def __init__(self, firewall_db): + self.firewall_db = firewall_db + + @log_helpers.log_method_call + def set_firewall_group_status(self, context, fwg_id, status, **kwargs): + """Agent uses this to set a firewall_group's status.""" + # Sanitize status first + if status in (nl_constants.ACTIVE, nl_constants.DOWN, + nl_constants.INACTIVE): + to_update = status + else: + to_update = nl_constants.ERROR + # ignore changing status if firewall_group expects to be deleted + # That case means that while some pending operation has been + # performed on the backend, neutron server received delete request + # and changed firewall status to PENDING_DELETE + updated = self.firewall_db.update_firewall_group_status( + context, fwg_id, to_update, not_in=(nl_constants.PENDING_DELETE,)) + if updated: + LOG.debug("firewall %s status set: %s", fwg_id, to_update) + return updated and to_update != nl_constants.ERROR + + @log_helpers.log_method_call + def firewall_group_deleted(self, context, fwg_id, **kwargs): + """Agent uses this to indicate firewall is deleted.""" + try: + fwg = self.firewall_db.get_firewall_group(context, fwg_id) + # allow to delete firewalls in ERROR state + if fwg['status'] in (nl_constants.PENDING_DELETE, + nl_constants.ERROR): + self.firewall_db.delete_firewall_group(context, fwg_id) + return True + LOG.warning('Firewall %(fwg)s unexpectedly deleted by agent, ' + 'status was %(status)s', + {'fwg': fwg_id, 'status': fwg['status']}) + fwg['status'] = nl_constants.ERROR + self.firewall_db.update_firewall_group(context, fwg_id, fwg) + return False + except f_exc.FirewallGroupNotFound: + LOG.info('Firewall group %s already deleted', fwg_id) + return True + + @log_helpers.log_method_call + def get_firewall_groups_for_project(self, context, **kwargs): + """Gets all firewall_groups and rules on a project.""" + fwg_list = [] + for fwg in self.firewall_db.get_firewall_groups(context): + fwg_with_rules =\ + self.firewall_db.make_firewall_group_dict_with_rules( + context, fwg['id']) + if fwg['status'] == nl_constants.PENDING_DELETE: + fwg_with_rules['add-port-ids'] = [] + fwg_with_rules['del-port-ids'] = ( + self.firewall_db.get_ports_in_firewall_group( + context, fwg['id'])) + else: + fwg_with_rules['add-port-ids'] = ( + self.firewall_db.get_ports_in_firewall_group( + context, fwg['id'])) + fwg_with_rules['del-port-ids'] = [] + fwg_list.append(fwg_with_rules) + return fwg_list + + @log_helpers.log_method_call + def get_projects_with_firewall_groups(self, context, **kwargs): + """Get all projects that have firewall_groups.""" + ctx = neutron_context.get_admin_context() + fwg_list = self.firewall_db.get_firewall_groups(ctx) + fwg_project_list = list(set(fwg['tenant_id'] for fwg in fwg_list)) + return fwg_project_list + + @log_helpers.log_method_call + def get_firewall_group_for_port(self, context, **kwargs): + """Get firewall_group is associated with a port.""" + ctx = context.elevated() + # Only one Firewall Group can be associated to a port at a time + fwg_port_binding = self.firewall_db.get_firewall_groups( + ctx, filters={'ports': [kwargs.get('port_id')]}) + if len(fwg_port_binding) != 1: + return + fwg = fwg_port_binding[0] + + fwg['ingress_rule_list'] = [] + for rule_id in self.firewall_db.get_firewall_policy( + context, fwg['ingress_firewall_policy_id'], + fields=['firewall_rules'])['firewall_rules']: + fwg['ingress_rule_list'].append( + self.firewall_db.get_firewall_rule(context, rule_id)) + fwg['egress_rule_list'] = [] + for rule_id in self.firewall_db.get_firewall_policy( + context, fwg['egress_firewall_policy_id'], + fields=['firewall_rules'])['firewall_rules']: + fwg['egress_rule_list'].append( + self.firewall_db.get_firewall_rule(context, rule_id)) + return fwg + + +class FirewallAgentApi(object): + """Plugin side of plugin to agent RPC API""" + + def __init__(self, topic, host): + self.host = host + target = oslo_messaging.Target(topic=topic, version='1.0') + self.client = neutron_rpc.get_client(target) + + def create_firewall_group(self, context, firewall_group): + cctxt = self.client.prepare(fanout=True) + cctxt.cast(context, 'create_firewall_group', + firewall_group=firewall_group, host=self.host) + + def update_firewall_group(self, context, firewall_group): + cctxt = self.client.prepare(fanout=True) + cctxt.cast(context, 'update_firewall_group', + firewall_group=firewall_group, host=self.host) + + def delete_firewall_group(self, context, firewall_group): + cctxt = self.client.prepare(fanout=True) + cctxt.cast(context, 'delete_firewall_group', + firewall_group=firewall_group, host=self.host) + + +class FirewallAgentDriver(driver_api.FirewallDriverDB): + """Firewall driver to implement agent messages and callback methods + + Implement RPC Firewall v2 API and callback methods for agents based on + Neutron DB model. + """ + + def __init__(self, service_plugin): + super(FirewallAgentDriver, self).__init__(service_plugin) + self.agent_rpc = FirewallAgentApi(constants.FW_AGENT, cfg.CONF.host) + self.start_rpc_listeners() + + def start_rpc_listeners(self): + self.endpoints = [FirewallAgentCallbacks(self.firewall_db)] + + self.rpc_connection = neutron_rpc.Connection() + self.rpc_connection.create_consumer(constants.FIREWALL_PLUGIN, + self.endpoints, fanout=False) + self.rpc_connection.consume_in_threads() + + def _rpc_update_firewall_group(self, context, fwg_id): + status_update = {"status": nl_constants.PENDING_UPDATE} + self.update_firewall_group(context, fwg_id, status_update) + fwg_with_rules = self.firewall_db.make_firewall_group_dict_with_rules( + context, fwg_id) + # this is triggered on an update to fwg rule or policy, no + # change in associated ports. + fwg_with_rules['add-port-ids'] = \ + self.firewall_db.get_ports_in_firewall_group(context, fwg_id) + fwg_with_rules['del-port-ids'] = [] + fwg_with_rules['port_details'] = self._get_fwg_port_details( + context, fwg_with_rules['add-port-ids']) + self.agent_rpc.update_firewall_group(context, fwg_with_rules) + + def _rpc_update_firewall_policy(self, context, firewall_policy_id): + firewall_policy = self.get_firewall_policy(context, firewall_policy_id) + if firewall_policy: + ing_fwg_ids, eg_fwg_ids = self.firewall_db.get_fwgs_with_policy( + context, firewall_policy_id) + for fwg_id in list(set(ing_fwg_ids + eg_fwg_ids)): + self._rpc_update_firewall_group(context, fwg_id) + + def _get_fwg_port_details(self, context, fwg_ports): + """Returns a dictionary list of port details. """ + port_details = {} + for port_id in fwg_ports: + port_db = self._core_plugin.get_port(context, port_id) + # Add more parameters below based on requirement. + device_owner = port_db['device_owner'] + port_details[port_id] = { + 'device_owner': device_owner, + 'device': port_db['id'], + 'network_id': port_db['network_id'], + 'fixed_ips': port_db['fixed_ips'], + 'allowed_address_pairs': + port_db.get('allowed_address_pairs', []), + 'port_security_enabled': + port_db.get('port_security_enabled', True), + 'id': port_db['id'], + 'status': port_db['status'], + } + if device_owner.startswith( + nl_constants.DEVICE_OWNER_COMPUTE_PREFIX): + port_details[port_id].update( + {'host': port_db[pb_def.HOST_ID]}) + return port_details + + def create_firewall_group_precommit(self, context, firewall_group): + ports = firewall_group['ports'] + + if (not ports or (not firewall_group['ingress_firewall_policy_id'] and + not firewall_group['egress_firewall_policy_id'])): + # no messaging to agent needed and fw needs to go to INACTIVE state + # as no associated ports and/or no policy configured. + status = nl_constants.INACTIVE + else: + status = (nl_constants.CREATED if cfg.CONF.router_distributed + else nl_constants.PENDING_CREATE) + firewall_group['status'] = status + + def create_firewall_group_postcommit(self, context, firewall_group): + if firewall_group['status'] != nl_constants.INACTIVE: + fwg_with_rules =\ + self.firewall_db.make_firewall_group_dict_with_rules( + context, firewall_group['id']) + fwg_with_rules['add-port-ids'] = firewall_group['ports'] + fwg_with_rules['del-ports-id'] = [] + fwg_with_rules['port_details'] = self._get_fwg_port_details( + context, firewall_group['ports']) + self.agent_rpc.create_firewall_group(context, fwg_with_rules) + + def delete_firewall_group_precommit(self, context, firewall_group): + if firewall_group['status'] == nl_constants.ACTIVE: + raise f_exc.FirewallGroupInUse(firewall_id=firewall_group['id']) + elif firewall_group['status'] != nl_constants.INACTIVE: + # Firewall group is in inconsistent state, remove it + return + if not firewall_group['ports']: + # No associated port, can safety remove it + return + + # Need to prevent agent to delete the firewall group before delete it + self.firewall_db.update_firewall_group_status( + context, firewall_group['id'], nl_constants.PENDING_DELETE) + firewall_group['status'] = nl_constants.PENDING_DELETE + + fwg_with_rules = self.firewall_db.make_firewall_group_dict_with_rules( + context, firewall_group['id']) + fwg_with_rules['del-port-ids'] = firewall_group['ports'] + fwg_with_rules['add-port-ids'] = [] + # Reflect state change in fwg_with_rules + fwg_with_rules['status'] = nl_constants.PENDING_DELETE + fwg_with_rules['port_details'] = self._get_fwg_port_details( + context, fwg_with_rules['del-port-ids']) + self.agent_rpc.delete_firewall_group(context, fwg_with_rules) + + def _need_pending_update(self, old_firewall_group, new_firewall_group): + port_updated = (set(new_firewall_group['ports']) != + set(old_firewall_group['ports'])) + policies_updated = ( + new_firewall_group['ingress_firewall_policy_id'] != + old_firewall_group['ingress_firewall_policy_id'] or + new_firewall_group['egress_firewall_policy_id'] != + old_firewall_group['egress_firewall_policy_id'] + ) + if (port_updated and + (new_firewall_group['ingress_firewall_policy_id'] or + new_firewall_group['egress_firewall_policy_id'])): + return True + if policies_updated and new_firewall_group['ports']: + return True + return False + + def update_firewall_group_precommit(self, context, old_firewall_group, + new_firewall_group): + if self._need_pending_update(old_firewall_group, new_firewall_group): + new_firewall_group['status'] = nl_constants.PENDING_UPDATE + + def update_firewall_group_postcommit(self, context, old_firewall_group, + new_firewall_group): + if not self._need_pending_update(old_firewall_group, + new_firewall_group): + return + + fwg_with_rules = self.firewall_db.make_firewall_group_dict_with_rules( + context, new_firewall_group['id']) + + # determine ports to add fw to and del from + fwg_with_rules['add-port-ids'] = list( + set(new_firewall_group['ports']) - set(old_firewall_group['ports']) + ) + fwg_with_rules['del-port-ids'] = list( + set(old_firewall_group['ports']) - set(new_firewall_group['ports']) + ) + + # last-port drives agent to ack with status to set state to INACTIVE + fwg_with_rules['last-port'] = not ( + set(new_firewall_group['ports']) - set(old_firewall_group['ports']) + ) + + LOG.debug("update_firewall_group %s: Add Ports: %s, Del Ports: %s", + new_firewall_group['id'], + fwg_with_rules['add-port-ids'], + fwg_with_rules['del-port-ids']) + + fwg_with_rules['port_details'] = self._get_fwg_port_details( + context, fwg_with_rules['del-port-ids']) + fwg_with_rules['port_details'].update(self._get_fwg_port_details( + context, fwg_with_rules['add-port-ids'])) + + if (new_firewall_group['name'] == constants.DEFAULT_FWG and + len(fwg_with_rules['add-port-ids']) == 1 and + not fwg_with_rules['del-port-ids']): + port_id = fwg_with_rules['add-port-ids'][0] + if (fwg_with_rules['port_details'][port_id].get('status') != + nl_constants.ACTIVE): + # If port not yet active, just associate to default firewall + # group. When agent will set it to UP, it'll found FG + # association and enforce default policies + return + # Warn agents Firewall Group port list updated + self.agent_rpc.update_firewall_group(context, fwg_with_rules) + + def update_firewall_policy_postcommit(self, context, old_firewall_policy, + new_firewall_group): + self._rpc_update_firewall_policy(context, new_firewall_group['id']) + + def update_firewall_rule_postcommit(self, context, old_firewall_rule, + new_firewall_rule): + firewall_policy_ids = self.firewall_db.get_policies_with_rule( + context, new_firewall_rule['id']) + for firewall_policy_id in firewall_policy_ids: + self._rpc_update_firewall_policy(context, firewall_policy_id) + + def insert_rule_postcommit(self, context, policy_id, rule_info): + self._rpc_update_firewall_policy(context, policy_id) + + def remove_rule_postcommit(self, context, policy_id, rule_info): + self._rpc_update_firewall_policy(context, policy_id) diff --git a/neutron_fwaas/services/firewall/agents/l3reference/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/__init__.py similarity index 100% rename from neutron_fwaas/services/firewall/agents/l3reference/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/__init__.py diff --git a/neutron_fwaas/services/firewall/drivers/conntrack_base.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/conntrack_base.py similarity index 96% rename from neutron_fwaas/services/firewall/drivers/conntrack_base.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/conntrack_base.py index 36145b348..536869632 100644 --- a/neutron_fwaas/services/firewall/drivers/conntrack_base.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/conntrack_base.py @@ -29,7 +29,7 @@ def load_and_init_conntrack_driver(*args, **kwargs): driver = cfg.CONF.fwaas.conntrack_driver try: conntrack_driver_cls = runtime.load_class_by_alias_or_classname( - 'neutron_fwaas.services.firewall.drivers.linux', driver) + 'neutron.agent.l3.firewall_drivers', driver) except ImportError: with excutils.save_and_reraise_exception(): LOG.exception("Driver '%s' not found.", driver) diff --git a/neutron_fwaas/services/firewall/drivers/fwaas_base.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/fwaas_base.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/fwaas_base.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/fwaas_base.py diff --git a/neutron_fwaas/services/firewall/drivers/fwaas_base_v2.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/fwaas_base_v2.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/fwaas_base_v2.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/fwaas_base_v2.py diff --git a/neutron_fwaas/services/firewall/drivers/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/__init__.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/__init__.py diff --git a/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/iptables_fwaas.py similarity index 99% rename from neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/iptables_fwaas.py index 5860f3763..523837af7 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/iptables_fwaas.py @@ -20,8 +20,10 @@ from neutron_lib.exceptions import firewall_v1 as f_exc from oslo_log import log as logging from neutron_fwaas.common import fwaas_constants as f_const -from neutron_fwaas.services.firewall.drivers import conntrack_base -from neutron_fwaas.services.firewall.drivers import fwaas_base +from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\ + conntrack_base +from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\ + fwaas_base LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas_v2.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/iptables_fwaas_v2.py similarity index 99% rename from neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas_v2.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/iptables_fwaas_v2.py index 48f640519..4f2bf578c 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas_v2.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/iptables_fwaas_v2.py @@ -19,8 +19,10 @@ from neutron_lib import constants from neutron_lib.exceptions import firewall_v2 as fw_ext from oslo_log import log as logging -from neutron_fwaas.services.firewall.drivers import conntrack_base -from neutron_fwaas.services.firewall.drivers import fwaas_base_v2 +from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\ + conntrack_base +from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\ + fwaas_base_v2 LOG = logging.getLogger(__name__) FWAAS_DRIVER_NAME = 'Fwaas iptables driver' diff --git a/neutron_fwaas/services/firewall/drivers/linux/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/__init__.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/linux/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/__init__.py diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/driver_base.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/driver_base.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/linux/l2/driver_base.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/driver_base.py diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/noop/__init__.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/linux/l2/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/noop/__init__.py diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/noop/noop_driver.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/noop/noop_driver.py similarity index 92% rename from neutron_fwaas/services/firewall/drivers/linux/l2/noop/noop_driver.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/noop/noop_driver.py index ff40c0e2c..41f581540 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/l2/noop/noop_driver.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/noop/noop_driver.py @@ -14,7 +14,8 @@ from oslo_log import helpers as log_helpers -from neutron_fwaas.services.firewall.drivers.linux.l2 import driver_base +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2\ + import driver_base class NoopFirewallL2Driver(driver_base.FirewallL2DriverBase): diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/__init__.py similarity index 84% rename from neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/__init__.py index 299d82632..892e565fb 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/__init__.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/__init__.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import firewall +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import firewall OVSFirewallDriver = firewall.OVSFirewallDriver diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/constants.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/constants.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/constants.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/constants.py diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/exceptions.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/exceptions.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/exceptions.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/exceptions.py diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/firewall.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/firewall.py similarity index 98% rename from neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/firewall.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/firewall.py index 1f1b6c402..ab828d1a1 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/firewall.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/firewall.py @@ -24,13 +24,14 @@ from neutron.common import constants from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \ as ovs_consts -from neutron_fwaas.services.firewall.drivers.linux.l2 import driver_base -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import constants as fwaas_ovs_consts -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import exceptions -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import rules +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2\ + import driver_base +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import constants as fwaas_ovs_consts +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import exceptions +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import rules LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/rules.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/rules.py similarity index 98% rename from neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/rules.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/rules.py index 7fcfe1636..529112f57 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/l2/openvswitch_firewall/rules.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/rules.py @@ -14,14 +14,15 @@ # under the License. import netaddr -from neutron_lib import constants as n_consts -from oslo_log import log as logging from neutron.common import utils from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \ as ovs_consts -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import constants as fwaas_ovs_consts +from neutron_lib import constants as n_consts +from oslo_log import log as logging + +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import constants as fwaas_ovs_consts LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/services/firewall/drivers/linux/legacy_conntrack.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/legacy_conntrack.py similarity index 98% rename from neutron_fwaas/services/firewall/drivers/linux/legacy_conntrack.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/legacy_conntrack.py index c63051143..eefb5d407 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/legacy_conntrack.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/legacy_conntrack.py @@ -17,8 +17,8 @@ from neutron.agent.linux import utils as linux_utils from neutron_lib import constants from oslo_log import log as logging -from neutron_fwaas.services.firewall.drivers import conntrack_base - +from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\ + conntrack_base LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/services/firewall/drivers/linux/netlink_conntrack.py b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/netlink_conntrack.py similarity index 98% rename from neutron_fwaas/services/firewall/drivers/linux/netlink_conntrack.py rename to neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/netlink_conntrack.py index 7058a9e01..a43cc5e39 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/netlink_conntrack.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/drivers/linux/netlink_conntrack.py @@ -17,7 +17,8 @@ from neutron_lib import constants from oslo_log import log as logging from neutron_fwaas.privileged import netlink_lib as nl_lib -from neutron_fwaas.services.firewall.drivers import conntrack_base +from neutron_fwaas.services.firewall.service_drivers.agents.drivers import\ + conntrack_base LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/services/firewall/agents/firewall_agent_api.py b/neutron_fwaas/services/firewall/service_drivers/agents/firewall_agent_api.py similarity index 100% rename from neutron_fwaas/services/firewall/agents/firewall_agent_api.py rename to neutron_fwaas/services/firewall/service_drivers/agents/firewall_agent_api.py diff --git a/neutron_fwaas/services/firewall/agents/firewall_service.py b/neutron_fwaas/services/firewall/service_drivers/agents/firewall_service.py similarity index 100% rename from neutron_fwaas/services/firewall/agents/firewall_service.py rename to neutron_fwaas/services/firewall/service_drivers/agents/firewall_service.py diff --git a/neutron_fwaas/services/firewall/drivers/linux/l2/noop/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/l2/__init__.py similarity index 100% rename from neutron_fwaas/services/firewall/drivers/linux/l2/noop/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/l2/__init__.py diff --git a/neutron_fwaas/services/firewall/agents/l2/fwaas_v2.py b/neutron_fwaas/services/firewall/service_drivers/agents/l2/fwaas_v2.py similarity index 99% rename from neutron_fwaas/services/firewall/agents/l2/fwaas_v2.py rename to neutron_fwaas/services/firewall/service_drivers/agents/l2/fwaas_v2.py index 304e060b3..ea95f8c2e 100644 --- a/neutron_fwaas/services/firewall/agents/l2/fwaas_v2.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/l2/fwaas_v2.py @@ -28,7 +28,8 @@ from neutron_lib.utils import net as nl_net from neutron_fwaas._i18n import _ from neutron_fwaas.common import fwaas_constants as consts -from neutron_fwaas.services.firewall.agents import firewall_agent_api as api +from neutron_fwaas.services.firewall.service_drivers.agents import\ + firewall_agent_api as api LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/__init__.py b/neutron_fwaas/services/firewall/service_drivers/agents/l3reference/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/agents/__init__.py rename to neutron_fwaas/services/firewall/service_drivers/agents/l3reference/__init__.py diff --git a/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent.py b/neutron_fwaas/services/firewall/service_drivers/agents/l3reference/firewall_l3_agent.py similarity index 98% rename from neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent.py rename to neutron_fwaas/services/firewall/service_drivers/agents/l3reference/firewall_l3_agent.py index eda5f9a77..909b697fd 100644 --- a/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/l3reference/firewall_l3_agent.py @@ -24,8 +24,10 @@ from oslo_log import log as logging from neutron_fwaas.common import fwaas_constants from neutron_fwaas.common import resources as f_resources -from neutron_fwaas.services.firewall.agents import firewall_agent_api as api -from neutron_fwaas.services.firewall.agents import firewall_service +from neutron_fwaas.services.firewall.service_drivers.agents \ + import firewall_agent_api as api +from neutron_fwaas.services.firewall.service_drivers.agents \ + import firewall_service LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent_v2.py b/neutron_fwaas/services/firewall/service_drivers/agents/l3reference/firewall_l3_agent_v2.py similarity index 99% rename from neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent_v2.py rename to neutron_fwaas/services/firewall/service_drivers/agents/l3reference/firewall_l3_agent_v2.py index 6e4b00951..4024678e4 100644 --- a/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent_v2.py +++ b/neutron_fwaas/services/firewall/service_drivers/agents/l3reference/firewall_l3_agent_v2.py @@ -25,8 +25,10 @@ from oslo_log import log as logging from neutron_fwaas.common import fwaas_constants from neutron_fwaas.common import resources as f_resources -from neutron_fwaas.services.firewall.agents import firewall_agent_api as api -from neutron_fwaas.services.firewall.agents import firewall_service +from neutron_fwaas.services.firewall.service_drivers.agents import\ + firewall_agent_api as api +from neutron_fwaas.services.firewall.service_drivers.agents import\ + firewall_service LOG = logging.getLogger(__name__) diff --git a/neutron_fwaas/services/firewall/service_drivers/driver_api.py b/neutron_fwaas/services/firewall/service_drivers/driver_api.py new file mode 100644 index 000000000..aa2a9f282 --- /dev/null +++ b/neutron_fwaas/services/firewall/service_drivers/driver_api.py @@ -0,0 +1,435 @@ +# Copyright (c) 2017 Juniper Networks, Inc. All rights reserved. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc +import copy + +import six + +from neutron_lib import constants as nl_constants +from neutron_lib.plugins import directory +from oslo_log import log as logging + +from neutron_fwaas.db.firewall.v2 import firewall_db_v2 + + +LOG = logging.getLogger(__name__) + + +@six.add_metaclass(abc.ABCMeta) +class FirewallDriver(object): + """Firewall v2 interface for driver + + That driver interface does not persist Firewall v2 data in any database. + The driver needs to do it by itself. + """ + + def __init__(self, service_plugin): + self.service_plugin = service_plugin + + @property + def _core_plugin(self): + return directory.get_plugin() + + # Firewall Group + @abc.abstractmethod + def create_firewall_group(self, context, firewall_group): + pass + + @abc.abstractmethod + def delete_firewall_group(self, context, id): + pass + + @abc.abstractmethod + def get_firewall_group(self, context, id, fields=None): + pass + + @abc.abstractmethod + def get_firewall_groups(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def update_firewall_group(self, context, id, firewall_group): + pass + + # Firewall Policy + @abc.abstractmethod + def create_firewall_policy(self, context, firewall_policy): + pass + + @abc.abstractmethod + def delete_firewall_policy(self, context, id): + pass + + @abc.abstractmethod + def get_firewall_policy(self, context, id, fields=None): + pass + + @abc.abstractmethod + def get_firewall_policies(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def update_firewall_policy(self, context, id, firewall_policy): + pass + + # Firewall Rule + @abc.abstractmethod + def create_firewall_rule(self, context, firewall_rule): + pass + + @abc.abstractmethod + def delete_firewall_rule(self, context, id): + pass + + @abc.abstractmethod + def get_firewall_rule(self, context, id, fields=None): + pass + + @abc.abstractmethod + def get_firewall_rules(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def update_firewall_rule(self, context, id, firewall_rule): + pass + + @abc.abstractmethod + def insert_rule(self, context, policy_id, rule_info): + pass + + @abc.abstractmethod + def remove_rule(self, context, policy_id, rule_info): + pass + + +@six.add_metaclass(abc.ABCMeta) +class FirewallDriverDBMixin(FirewallDriver): + """FirewallDriverDB mixin to provision the database on behalf of the driver + + That driver interface persists Firewall data in its database and forwards + the result to pre and post commit methods. + """ + + def __init__(self, *args, **kwargs): + super(FirewallDriverDBMixin, self).__init__(*args, **kwargs) + self.firewall_db = firewall_db_v2.FirewallPluginDb() + + @staticmethod + def _update_resource_status(context, resource_type, resource_dict): + with context.session.begin(subtransactions=True): + context.session.query(resource_type).\ + filter_by(id=resource_dict['id']).\ + update({'status': resource_dict['status']}) + + # Firewall Group + def create_firewall_group(self, context, firewall_group): + with context.session.begin(subtransactions=True): + firewall_group = self.firewall_db.create_firewall_group( + context, firewall_group) + self.create_firewall_group_precommit(context, firewall_group) + self._update_resource_status(context, firewall_db_v2.FirewallGroup, + firewall_group) + self.create_firewall_group_postcommit(context, firewall_group) + return firewall_group + + @abc.abstractmethod + def create_firewall_group_precommit(self, context, firewall_group): + pass + + @abc.abstractmethod + def create_firewall_group_postcommit(self, context, firewall_group): + pass + + def delete_firewall_group(self, context, id): + firewall_group = self.firewall_db.get_firewall_group(context, id) + if firewall_group['status'] == nl_constants.PENDING_DELETE: + firewall_group['status'] = nl_constants.ERROR + self.delete_firewall_group_precommit(context, firewall_group) + if firewall_group['status'] != nl_constants.PENDING_DELETE: + # lets driver deleting firewall group later + self.firewall_db.delete_firewall_group(context, id) + self.delete_firewall_group_postcommit(context, firewall_group) + + @abc.abstractmethod + def delete_firewall_group_precommit(self, context, firewall_group): + pass + + @abc.abstractmethod + def delete_firewall_group_postcommit(self, context, firewall_group): + pass + + def get_firewall_group(self, context, id, fields=None): + return self.firewall_db.get_firewall_group(context, id, fields=fields) + + def get_firewall_groups(self, context, filters=None, fields=None): + return self.firewall_db.get_firewall_groups(context, filters, fields) + + def update_firewall_group(self, context, id, firewall_group_delta): + old_firewall_group = self.firewall_db.get_firewall_group(context, id) + new_firewall_group = copy.deepcopy(old_firewall_group) + new_firewall_group.update(firewall_group_delta) + self.update_firewall_group_precommit(context, old_firewall_group, + new_firewall_group) + firewall_group_delta['status'] = new_firewall_group['status'] + firewall_group = self.firewall_db.update_firewall_group( + context, id, firewall_group_delta) + self.update_firewall_group_postcommit(context, old_firewall_group, + firewall_group) + return firewall_group + + @abc.abstractmethod + def update_firewall_group_precommit(self, context, old_firewall_group, + new_firewall_group): + pass + + @abc.abstractmethod + def update_firewall_group_postcommit(self, context, old_firewall_group, + new_firewall_group): + pass + + # Firewall Policy + def create_firewall_policy(self, context, firewall_policy): + with context.session.begin(subtransactions=True): + firewall_policy = self.firewall_db.create_firewall_policy( + context, firewall_policy) + self.create_firewall_policy_precommit(context, firewall_policy) + self.create_firewall_policy_postcommit(context, firewall_policy) + return firewall_policy + + @abc.abstractmethod + def create_firewall_policy_precommit(self, context, firewall_policy): + pass + + @abc.abstractmethod + def create_firewall_policy_postcommit(self, context, firewall_policy): + pass + + def delete_firewall_policy(self, context, id): + firewall_policy = self.firewall_db.get_firewall_policy(context, id) + self.delete_firewall_policy_precommit(context, firewall_policy) + self.firewall_db.delete_firewall_policy(context, id) + self.delete_firewall_policy_postcommit(context, firewall_policy) + + @abc.abstractmethod + def delete_firewall_policy_precommit(self, context, firewall_policy): + pass + + @abc.abstractmethod + def delete_firewall_policy_postcommit(self, context, firewall_policy): + pass + + def get_firewall_policy(self, context, id, fields=None): + return self.firewall_db.get_firewall_policy(context, id, fields) + + def get_firewall_policies(self, context, filters=None, fields=None): + return self.firewall_db.get_firewall_policies(context, filters, fields) + + def update_firewall_policy(self, context, id, firewall_policy_delta): + old_firewall_policy = self.firewall_db.get_firewall_policy(context, id) + new_firewall_policy = copy.deepcopy(old_firewall_policy) + new_firewall_policy.update(firewall_policy_delta) + self.update_firewall_policy_precommit(context, old_firewall_policy, + new_firewall_policy) + firewall_policy = self.firewall_db.update_firewall_policy( + context, id, firewall_policy_delta) + self.update_firewall_policy_postcommit(context, old_firewall_policy, + firewall_policy) + return firewall_policy + + @abc.abstractmethod + def update_firewall_policy_precommit(self, context, old_firewall_policy, + new_firewall_policy): + pass + + @abc.abstractmethod + def update_firewall_policy_postcommit(self, context, old_firewall_policy, + new_firewall_policy): + pass + + # Firewall Rule + def create_firewall_rule(self, context, firewall_rule): + with context.session.begin(subtransactions=True): + firewall_rule = self.firewall_db.create_firewall_rule( + context, firewall_rule) + self.create_firewall_rule_precommit(context, firewall_rule) + self.create_firewall_rule_postcommit(context, firewall_rule) + return firewall_rule + + @abc.abstractmethod + def create_firewall_rule_precommit(self, context, firewall_rule): + pass + + @abc.abstractmethod + def create_firewall_rule_postcommit(self, context, firewall_rule): + pass + + def delete_firewall_rule(self, context, id): + firewall_rule = self.firewall_db.get_firewall_rule(context, id) + self.delete_firewall_rule_precommit(context, firewall_rule) + self.firewall_db.delete_firewall_rule(context, id) + self.delete_firewall_rule_postcommit(context, firewall_rule) + + @abc.abstractmethod + def delete_firewall_rule_precommit(self, context, firewall_rule): + pass + + @abc.abstractmethod + def delete_firewall_rule_postcommit(self, context, firewall_rule): + pass + + def get_firewall_rule(self, context, id, fields=None): + return self.firewall_db.get_firewall_rule(context, id, fields) + + def get_firewall_rules(self, context, filters=None, fields=None): + return self.firewall_db.get_firewall_rules(context, filters, fields) + + def update_firewall_rule(self, context, id, firewall_rule_delta): + old_firewall_rule = self.firewall_db.get_firewall_rule(context, id) + new_firewall_rule = copy.deepcopy(old_firewall_rule) + new_firewall_rule.update(firewall_rule_delta) + self.update_firewall_rule_precommit(context, old_firewall_rule, + new_firewall_rule) + firewall_rule = self.firewall_db.update_firewall_rule( + context, id, firewall_rule_delta) + self.update_firewall_rule_postcommit(context, old_firewall_rule, + firewall_rule) + return firewall_rule + + @abc.abstractmethod + def update_firewall_rule_precommit(self, context, old_firewall_rule, + new_firewall_rule): + pass + + @abc.abstractmethod + def update_firewall_rule_postcommit(self, context, old_firewall_rule, + new_firewall_rule): + pass + + def insert_rule(self, context, policy_id, rule_info): + self.insert_rule_precommit(context, policy_id, rule_info) + firewall_policy = self.firewall_db.insert_rule(context, policy_id, + rule_info) + self.insert_rule_postcommit(context, policy_id, rule_info) + return firewall_policy + + @abc.abstractmethod + def insert_rule_precommit(self, context, policy_id, rule_info): + pass + + @abc.abstractmethod + def insert_rule_postcommit(self, context, policy_id, rule_info): + pass + + def remove_rule(self, context, policy_id, rule_info): + self.remove_rule_precommit(context, policy_id, rule_info) + firewall_policy = self.firewall_db.remove_rule(context, policy_id, + rule_info) + self.remove_rule_postcommit(context, policy_id, rule_info) + return firewall_policy + + @abc.abstractmethod + def remove_rule_precommit(self, context, policy_id, rule_info): + pass + + @abc.abstractmethod + def remove_rule_postcommit(self, context, policy_id, rule_info): + pass + + +class FirewallDriverDB(FirewallDriverDBMixin): + """FirewallDriverDBMixin interface for driver with database. + + Each firewall backend driver that needs a database persistency should + inherit from this driver. + It can overload needed methods from the following pre/postcommit methods. + Any exception raised during a precommit method will result in not having + related records in the databases. + """ + + #Firewal Group + def create_firewall_group_precommit(self, context, firewall_group): + pass + + def create_firewall_group_postcommit(self, context, firewall_group): + pass + + def update_firewall_group_precommit(self, context, old_firewall_group, + new_firewall_group): + pass + + def update_firewall_group_postcommit(self, context, old_firewall_group, + new_firewall_group): + pass + + def delete_firewall_group_precommit(self, context, firewall_group): + pass + + def delete_firewall_group_postcommit(self, context, firewall_group): + pass + + #Firewall Policy + def create_firewall_policy_precommit(self, context, firewall_policy): + pass + + def create_firewall_policy_postcommit(self, context, firewall_policy): + pass + + def update_firewall_policy_precommit(self, context, old_firewall_policy, + new_firewall_policy): + pass + + def update_firewall_policy_postcommit(self, context, old_firewall_policy, + new_firewall_policy): + pass + + def delete_firewall_policy_precommit(self, context, firewall_policy): + pass + + def delete_firewall_policy_postcommit(self, context, firewall_policy): + pass + + #Firewall Rule + def create_firewall_rule_precommit(self, context, firewall_rule): + pass + + def create_firewall_rule_postcommit(self, context, firewall_rule): + pass + + def update_firewall_rule_precommit(self, context, old_firewall_rule, + new_firewall_rule): + pass + + def update_firewall_rule_postcommit(self, context, old_firewall_rule, + new_firewall_rule): + pass + + def delete_firewall_rule_precommit(self, context, firewall_rule): + pass + + def delete_firewall_rule_postcommit(self, context, firewall_rule): + pass + + def insert_rule_precommit(self, context, policy_id, rule_info): + pass + + def insert_rule_postcommit(self, context, policy_id, rule_info): + pass + + def remove_rule_precommit(self, context, policy_id, rule_info): + pass + + def remove_rule_postcommit(self, context, policy_id, rule_info): + pass diff --git a/neutron_fwaas/tests/unit/db/firewall/v2/test_firewall_db_v2.py b/neutron_fwaas/tests/unit/db/firewall/v2/test_firewall_db_v2.py index 34038f044..913aca6e3 100644 --- a/neutron_fwaas/tests/unit/db/firewall/v2/test_firewall_db_v2.py +++ b/neutron_fwaas/tests/unit/db/firewall/v2/test_firewall_db_v2.py @@ -13,387 +13,26 @@ # License for the specific language governing permissions and limitations # under the License. -import contextlib - import mock -from neutron.api import extensions as api_ext -from neutron.common import config -from neutron_lib.api.definitions import firewall_v2 -from neutron_lib import constants as nl_constants -from neutron_lib import context -from neutron_lib.exceptions import firewall_v2 as f_exc -from neutron_lib.plugins import directory -from oslo_config import cfg -from oslo_utils import importutils -from oslo_utils import uuidutils import six import testtools import webob.exc +from neutron_lib import constants as nl_constants +from neutron_lib.exceptions import firewall_v2 as f_exc +from oslo_utils import uuidutils + from neutron_fwaas.common import fwaas_constants as constants -from neutron_fwaas.db.firewall.v2 import firewall_db_v2 as fdb -from neutron_fwaas import extensions -from neutron_fwaas.services.firewall import fwaas_plugin_v2 -from neutron_fwaas.tests import base +from neutron_fwaas.tests.unit.services.firewall import test_fwaas_plugin_v2 -DB_FW_PLUGIN_KLASS = ( - "neutron_fwaas.db.firewall.v2.firewall_db_v2.Firewall_db_mixin_v2" -) -FWAAS_PLUGIN = 'neutron_fwaas.services.firewall.fwaas_plugin_v2' -DELETEFW_PATH = FWAAS_PLUGIN + '.FirewallAgentApi.delete_firewall_group' -extensions_path = ':'.join(extensions.__path__) -DESCRIPTION = 'default description' -PROTOCOL = 'tcp' -IP_VERSION = 4 -SOURCE_IP_ADDRESS_RAW = '1.1.1.1' -DESTINATION_IP_ADDRESS_RAW = '2.2.2.2' -SOURCE_PORT = '55000:56000' -DESTINATION_PORT = '56000:57000' -ACTION = 'allow' -AUDITED = True -ENABLED = True -ADMIN_STATE_UP = True -SHARED = True +class TestFirewallDBPluginV2(test_fwaas_plugin_v2.FirewallPluginV2TestCase): - -class FakeAgentApi(fwaas_plugin_v2.FirewallCallbacks): - """ - This class used to mock the AgentAPI delete method inherits from - FirewallCallbacks because it needs access to the firewall_deleted method. - The delete_firewall method belongs to the FirewallAgentApi, which has - no access to the firewall_deleted method normally because it's not - responsible for deleting the firewall from the DB. However, it needs - to in the unit tests since there is no agent to call back. - """ - def __init__(self): - pass - - def delete_firewall_group(self, context, firewall_group, **kwargs): - self.plugin = directory.get_plugin('FIREWALL_V2') - self.firewall_group_deleted(context, firewall_group['id'], **kwargs) - - -class FirewallPluginV2DbTestCase(base.NeutronDbPluginV2TestCase): - resource_prefix_map = dict( - (k, firewall_v2.API_PREFIX) - for k in firewall_v2.RESOURCE_ATTRIBUTE_MAP.keys() - ) - - def setUp(self, core_plugin=None, fw_plugin=None, ext_mgr=None): - self.agentapi_delf_p = mock.patch( - DELETEFW_PATH, create=True, - new=FakeAgentApi().delete_firewall_group) - self.agentapi_delf_p.start() - if not fw_plugin: - fw_plugin = DB_FW_PLUGIN_KLASS - service_plugins = {'fw_plugin_name': fw_plugin} - - fdb.Firewall_db_mixin_v2.supported_extension_aliases = ["fwaas_v2"] - fdb.Firewall_db_mixin_v2.path_prefix = firewall_v2.API_PREFIX - super(FirewallPluginV2DbTestCase, self).setUp( - ext_mgr=ext_mgr, - service_plugins=service_plugins - ) - - if not ext_mgr: - self.plugin = importutils.import_object(fw_plugin) - ext_mgr = api_ext.PluginAwareExtensionManager( - extensions_path, - {'FIREWALL': self.plugin} - ) - app = config.load_paste_app('extensions_test_app') - self.ext_api = api_ext.ExtensionMiddleware(app, ext_mgr=ext_mgr) - router_distributed_opts = [ - cfg.BoolOpt( - 'router_distributed', - default=False, - help=("System-wide flag to determine the type of router " - "that tenants can create. Only admin can override.")), - ] - cfg.CONF.register_opts(router_distributed_opts) - - def _get_admin_context(self): - # FIXME NOTE(ivasilevskaya) seems that test framework treats context - # with user_id=None/tenant_id=None (return value of - # context._get_admin_context() method) in a somewhat special way. - # So as a workaround to have the framework behave properly right now - # let's implement our own _get_admin_context method and look into the - # matter some other time. - return context.Context(user_id='admin', - tenant_id='admin-tenant', - is_admin=True) - - def _get_nonadmin_context(self, user_id=None, tenant_id=None): - return context.Context(user_id=user_id or 'non-admin', - tenant_id=tenant_id or 'tenant1') - - def _test_list_resources(self, resource, items, - neutron_context=None, - query_params=None): - if resource.endswith('y'): - resource_plural = resource.replace('y', 'ies') - else: - resource_plural = resource + 's' - - res = self._list(resource_plural, - neutron_context=neutron_context, - query_params=query_params) - resource = resource.replace('-', '_') - self.assertEqual( - sorted([i[resource]['id'] for i in items]), - sorted([i['id'] for i in res[resource_plural]])) - - def _list_req(self, resource_plural, ctx=None): - if not ctx: - ctx = self._get_admin_context() - req = self.new_list_request(resource_plural) - req.environ['neutron.context'] = ctx - return self.deserialize( - self.fmt, req.get_response(self.ext_api))[resource_plural] - - def _show_req(self, resource_plural, obj_id, ctx=None): - req = self.new_show_request(resource_plural, obj_id, fmt=self.fmt) - if not ctx: - ctx = self._get_admin_context() - req.environ['neutron.context'] = ctx - res = self.deserialize( - self.fmt, req.get_response(self.ext_api)) - return res - - def _build_default_fwg(self, ctx=None, is_one=True): - res = self._list_req('firewall_groups', ctx=ctx) - if is_one: - self.assertEqual(1, len(res)) - return res[0] - return res - - def _get_test_firewall_rule_attrs(self, name='firewall_rule1'): - attrs = {'name': name, - 'tenant_id': self._tenant_id, - 'project_id': self._tenant_id, - 'protocol': PROTOCOL, - 'ip_version': IP_VERSION, - 'source_ip_address': SOURCE_IP_ADDRESS_RAW, - 'destination_ip_address': DESTINATION_IP_ADDRESS_RAW, - 'source_port': SOURCE_PORT, - 'destination_port': DESTINATION_PORT, - 'action': ACTION, - 'enabled': ENABLED, - 'shared': SHARED} - return attrs - - def _get_test_firewall_policy_attrs(self, name='firewall_policy1', - audited=AUDITED): - attrs = {'name': name, - 'description': DESCRIPTION, - 'tenant_id': self._tenant_id, - 'project_id': self._tenant_id, - 'firewall_rules': [], - 'audited': audited, - 'shared': SHARED} - return attrs - - def _get_test_firewall_group_attrs(self, name='firewall_1', - status='PENDING_CREATE'): - attrs = {'name': name, - 'tenant_id': self._tenant_id, - 'project_id': self._tenant_id, - 'admin_state_up': ADMIN_STATE_UP, - 'status': status} - - return attrs - - def _create_firewall_policy(self, fmt, name, description, shared, - firewall_rules, audited, - expected_res_status=None, **kwargs): - tenant_id = kwargs.get('tenant_id', self._tenant_id) - data = {'firewall_policy': {'name': name, - 'description': description, - 'tenant_id': tenant_id, - 'project_id': tenant_id, - 'firewall_rules': firewall_rules, - 'audited': audited, - 'shared': shared}} - - fw_policy_req = self.new_create_request('firewall_policies', data, fmt) - fw_policy_res = fw_policy_req.get_response(self.ext_api) - if expected_res_status: - self.assertEqual(expected_res_status, fw_policy_res.status_int) - - return fw_policy_res - - def _replace_firewall_status(self, attrs, old_status, new_status): - if attrs['status'] is old_status: - attrs['status'] = new_status - return attrs - - @contextlib.contextmanager - def firewall_policy(self, fmt=None, name='firewall_policy1', - description=DESCRIPTION, shared=SHARED, - firewall_rules=None, audited=True, - do_delete=True, **kwargs): - if firewall_rules is None: - firewall_rules = [] - if not fmt: - fmt = self.fmt - res = self._create_firewall_policy(fmt, name, description, shared, - firewall_rules, audited, **kwargs) - if res.status_int >= 400: - raise webob.exc.HTTPClientError(code=res.status_int) - firewall_policy = self.deserialize(fmt or self.fmt, res) - yield firewall_policy - if do_delete: - self._delete('firewall_policies', - firewall_policy['firewall_policy']['id']) - - def _create_firewall_rule(self, fmt, name, shared, protocol, - ip_version, source_ip_address, - destination_ip_address, source_port, - destination_port, action, enabled, - expected_res_status=None, **kwargs): - tenant_id = kwargs.get('tenant_id', self._tenant_id) - data = {'firewall_rule': {'name': name, - 'tenant_id': tenant_id, - 'project_id': tenant_id, - 'protocol': protocol, - 'ip_version': ip_version, - 'source_ip_address': source_ip_address, - 'destination_ip_address': - destination_ip_address, - 'source_port': source_port, - 'destination_port': destination_port, - 'action': action, - 'enabled': enabled, - 'shared': shared}} - - fw_rule_req = self.new_create_request('firewall_rules', data, fmt) - fw_rule_res = fw_rule_req.get_response(self.ext_api) - if expected_res_status: - self.assertEqual(expected_res_status, fw_rule_res.status_int) - - return fw_rule_res - - @contextlib.contextmanager - def firewall_rule(self, fmt=None, name='firewall_rule1', - shared=SHARED, protocol=PROTOCOL, ip_version=IP_VERSION, - source_ip_address=SOURCE_IP_ADDRESS_RAW, - destination_ip_address=DESTINATION_IP_ADDRESS_RAW, - source_port=SOURCE_PORT, - destination_port=DESTINATION_PORT, - action=ACTION, enabled=ENABLED, - do_delete=True, **kwargs): - if not fmt: - fmt = self.fmt - res = self._create_firewall_rule(fmt, name, shared, protocol, - ip_version, source_ip_address, - destination_ip_address, - source_port, destination_port, - action, enabled, **kwargs) - if res.status_int >= 400: - raise webob.exc.HTTPClientError(code=res.status_int) - firewall_rule = self.deserialize(fmt or self.fmt, res) - yield firewall_rule - if do_delete: - self._delete('firewall_rules', - firewall_rule['firewall_rule']['id']) - - def _create_firewall_group(self, fmt, name, description, - ingress_firewall_policy_id, - egress_firewall_policy_id, - ports=None, admin_state_up=True, - expected_res_status=None, **kwargs): - tenant_id = kwargs.get('tenant_id', self._tenant_id) - if ingress_firewall_policy_id is None: - default_policy = kwargs.get('default_policy', True) - if default_policy: - res = self._create_firewall_policy(fmt, 'fwp', - description=DESCRIPTION, - shared=SHARED, - firewall_rules=[], - audited=AUDITED) - firewall_policy = self.deserialize(fmt or self.fmt, res) - fwp_id = firewall_policy["firewall_policy"]["id"] - ingress_firewall_policy_id = fwp_id - data = {'firewall_group': {'name': name, - 'description': description, - 'ingress_firewall_policy_id': ingress_firewall_policy_id, - 'egress_firewall_policy_id': egress_firewall_policy_id, - 'admin_state_up': admin_state_up}} - ctx = kwargs.get('context', None) - if ctx is None or ctx.is_admin: - data['firewall_group'].update({'tenant_id': tenant_id}) - data['firewall_group'].update({'project_id': tenant_id}) - if ports is not None: - data['firewall_group'].update({'ports': ports}) - - firewall_req = self.new_create_request('firewall_groups', data, fmt, - context=ctx) - firewall_res = firewall_req.get_response(self.ext_api) - if expected_res_status: - self.assertEqual(expected_res_status, firewall_res.status_int) - - return firewall_res - - @contextlib.contextmanager - def firewall_group(self, fmt=None, name='firewall_1', - description=DESCRIPTION, - ingress_firewall_policy_id=None, - egress_firewall_policy_id=None, - ports=None, admin_state_up=True, - do_delete=True, **kwargs): - if not fmt: - fmt = self.fmt - res = self._create_firewall_group(fmt, name, description, - ingress_firewall_policy_id, - egress_firewall_policy_id, - ports=ports, - admin_state_up=admin_state_up, - **kwargs) - if res.status_int >= 400: - raise webob.exc.HTTPClientError(code=res.status_int) - firewall_group = self.deserialize(fmt or self.fmt, res) - yield firewall_group - if do_delete: - self._delete('firewall_groups', - firewall_group['firewall_group']['id']) - - def _rule_action(self, action, id, firewall_rule_id, insert_before=None, - insert_after=None, expected_code=webob.exc.HTTPOk.code, - expected_body=None, body_data=None): - # We intentionally do this check for None since we want to distinguish - # from empty dictionary - if body_data is None: - if action == 'insert': - body_data = {'firewall_rule_id': firewall_rule_id, - 'insert_before': insert_before, - 'insert_after': insert_after} - else: - body_data = {'firewall_rule_id': firewall_rule_id} - - req = self.new_action_request('firewall_policies', - body_data, id, - "%s_rule" % action) - res = req.get_response(self.ext_api) - self.assertEqual(expected_code, res.status_int) - response = self.deserialize(self.fmt, res) - if expected_body: - self.assertEqual(expected_body, response) - return response - - def _compare_firewall_rule_lists(self, firewall_policy_id, - observed_list, expected_list): - position = 0 - for r1, r2 in zip(observed_list, expected_list): - rule = r1['firewall_rule'] - rule['firewall_policy_id'] = firewall_policy_id - position += 1 - rule['position'] = position - for k in rule: - self.assertEqual(r2[k], rule[k]) - - -class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): + def setUp(self): + provider = ('neutron_fwaas.services.firewall.service_drivers.' + 'driver_api.FirewallDriverDB') + super(TestFirewallDBPluginV2, self).setUp(service_provider=provider) + self.db = self.plugin.driver.firewall_db def test_get_policy_ordered_rules(self): with self.firewall_rule(name='alone'), \ @@ -405,7 +44,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): with self.firewall_policy(firewall_rules=expected_ids) as fwp: ctx = self._get_admin_context() fwp_id = fwp['firewall_policy']['id'] - observeds = self.plugin._get_policy_ordered_rules(ctx, fwp_id) + observeds = self.db._get_policy_ordered_rules(ctx, fwp_id) observed_ids = [r['id'] for r in observeds] self.assertEqual(expected_ids, observed_ids) @@ -413,8 +52,8 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): name = "firewall_policy1" attrs = self._get_test_firewall_policy_attrs(name) - with self.firewall_policy(name=name, shared=SHARED, - firewall_rules=None, audited=AUDITED + with self.firewall_policy(name=name, shared=self.SHARED, + firewall_rules=None, audited=self.AUDITED ) as firewall_policy: for k, v in six.iteritems(attrs): self.assertEqual(v, firewall_policy['firewall_policy'][k]) @@ -429,49 +68,29 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): fr = [fwr1, fwr2, fwr3] fw_rule_ids = [r['firewall_rule']['id'] for r in fr] attrs['firewall_rules'] = fw_rule_ids - with self.firewall_policy(name=name, shared=SHARED, + with self.firewall_policy(name=name, shared=self.SHARED, firewall_rules=fw_rule_ids, - audited=AUDITED) as fwp: + audited=self.AUDITED) as fwp: for k, v in six.iteritems(attrs): self.assertEqual(v, fwp['firewall_policy'][k]) - def test_create_admin_firewall_policy_with_other_tenant_rules(self): - with self.firewall_rule(shared=False) as fr: - fw_rule_ids = [fr['firewall_rule']['id']] - res = self._create_firewall_policy(None, 'firewall_policy1', - description=DESCRIPTION, - shared=SHARED, - firewall_rules=fw_rule_ids, - audited=AUDITED, - tenant_id='admin-tenant') - self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int) - def test_create_firewall_policy_with_previously_associated_rule(self): with self.firewall_rule() as fwr: fw_rule_ids = [fwr['firewall_rule']['id']] with self.firewall_policy(firewall_rules=fw_rule_ids): - with self.firewall_policy(shared=SHARED, + with self.firewall_policy(shared=self.SHARED, firewall_rules=fw_rule_ids) as fwp2: self.assertEqual( fwr['firewall_rule']['id'], fwp2['firewall_policy']['firewall_rules'][0]) - def test_create_shared_firewall_policy_with_nonshared_rule(self): - with self.firewall_rule(shared=False) as fwr: - fw_rule_ids = [fwr['firewall_rule']['id']] - res = self._create_firewall_policy(None, 'firewall_policy1', - description=DESCRIPTION, - shared=SHARED, - firewall_rules=fw_rule_ids, - audited=AUDITED) - self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int) - def test_show_firewall_policy(self): name = "firewall_policy1" attrs = self._get_test_firewall_policy_attrs(name) - with self.firewall_policy(name=name, shared=SHARED, - firewall_rules=None, audited=AUDITED) as fwp: + with self.firewall_policy(name=name, shared=self.SHARED, + firewall_rules=None, + audited=self.AUDITED) as fwp: res = self._show_req('firewall_policies', fwp['firewall_policy']['id']) for k, v in six.iteritems(attrs): @@ -490,8 +109,8 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): name = "new_firewall_policy1" attrs = self._get_test_firewall_policy_attrs(name, audited=False) - with self.firewall_policy(shared=SHARED, firewall_rules=None, - audited=AUDITED) as fwp: + with self.firewall_policy(shared=self.SHARED, firewall_rules=None, + audited=self.AUDITED) as fwp: data = {'firewall_policy': {'name': name}} req = self.new_update_request('firewall_policies', data, fwp['firewall_policy']['id']) @@ -501,7 +120,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): def _test_update_firewall_policy(self, with_audited): with self.firewall_policy(name='firewall_policy1', description='fwp', - audited=AUDITED) as fwp: + audited=self.AUDITED) as fwp: attrs = self._get_test_firewall_policy_attrs(audited=with_audited) data = {'firewall_policy': {'description': 'fw_p1'}} @@ -658,7 +277,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): with self.firewall_policy(shared=False) as fwp: fw_rule_ids = [fr['firewall_rule']['id']] # update shared policy with shared attr and nonshared rule - data = {'firewall_policy': {'shared': SHARED, + data = {'firewall_policy': {'shared': self.SHARED, 'firewall_rules': fw_rule_ids}} req = self.new_update_request('firewall_policies', data, fwp['firewall_policy']['id']) @@ -671,14 +290,15 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): with self.firewall_policy(shared=False, firewall_rules=fw_rule_ids) as fwp: # update policy with shared attr - data = {'firewall_policy': {'shared': SHARED}} + data = {'firewall_policy': {'shared': self.SHARED}} req = self.new_update_request('firewall_policies', data, fwp['firewall_policy']['id']) res = req.get_response(self.ext_api) self.assertEqual(webob.exc.HTTPConflict.code, res.status_int) def test_update_firewall_policy_assoc_with_other_tenant_firewall(self): - with self.firewall_policy(shared=SHARED, tenant_id='tenant1') as fwp: + with self.firewall_policy(shared=self.SHARED, + tenant_id='tenant1') as fwp: fwp_id = fwp['firewall_policy']['id'] with self.firewall_group(ingress_firewall_policy_id=fwp_id, egress_firewall_policy_id=fwp_id): @@ -790,13 +410,11 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): self.assertIsNone(fw_rule['ingress_firewall_policy_id']) def test_delete_firewall_policy_with_firewall_group_association(self): - attrs = self._get_test_firewall_group_attrs() with self.firewall_policy() as fwp: fwp_id = fwp['firewall_policy']['id'] - attrs['firewall_policy_id'] = fwp_id with self.firewall_group( ingress_firewall_policy_id=fwp_id, - admin_state_up=ADMIN_STATE_UP): + admin_state_up=self.ADMIN_STATE_UP): req = self.new_delete_request('firewall_policies', fwp_id) res = req.get_response(self.ext_api) self.assertEqual(409, res.status_int) @@ -832,20 +450,20 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): def test_create_firewall_src_port_illegal_range(self): attrs = self._get_test_firewall_rule_attrs() attrs['source_port'] = '65535:1024' - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) def test_create_firewall_dest_port_illegal_range(self): attrs = self._get_test_firewall_rule_attrs() attrs['destination_port'] = '65535:1024' - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) def test_create_firewall_rule_icmp_with_port(self): attrs = self._get_test_firewall_rule_attrs() attrs['protocol'] = 'icmp' - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) def test_create_firewall_rule_icmp_without_port(self): attrs = self._get_test_firewall_rule_attrs() @@ -862,28 +480,28 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): def test_create_firewall_without_source(self): attrs = self._get_test_firewall_rule_attrs() attrs['source_ip_address'] = None - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(201, res.status_int) + attrs['expected_res_status'] = 201 + self._create_firewall_rule(self.fmt, **attrs) def test_create_firewall_rule_without_destination(self): attrs = self._get_test_firewall_rule_attrs() attrs['destination_ip_address'] = None - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(201, res.status_int) + attrs['expected_res_status'] = 201 + self._create_firewall_rule(self.fmt, **attrs) def test_create_firewall_rule_without_protocol_with_dport(self): attrs = self._get_test_firewall_rule_attrs() attrs['protocol'] = None attrs['source_port'] = None - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) def test_create_firewall_rule_without_protocol_with_sport(self): attrs = self._get_test_firewall_rule_attrs() attrs['protocol'] = None attrs['destination_port'] = None - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) def test_show_firewall_rule_with_fw_policy_not_associated(self): attrs = self._get_test_firewall_rule_attrs() @@ -916,22 +534,22 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): attrs['source_ip_address'] = '::/0' attrs['destination_ip_address'] = '2001:db8:3::/64' attrs['ip_version'] = 4 - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) attrs = self._get_test_firewall_rule_attrs() attrs['source_ip_address'] = None attrs['destination_ip_address'] = '2001:db8:3::/64' attrs['ip_version'] = 4 - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) attrs = self._get_test_firewall_rule_attrs() attrs['source_ip_address'] = '::/0' attrs['destination_ip_address'] = None attrs['ip_version'] = 4 - res = self._create_firewall_rule(self.fmt, **attrs) - self.assertEqual(400, res.status_int) + attrs['expected_res_status'] = 400 + self._create_firewall_rule(self.fmt, **attrs) def test_list_firewall_rules(self): with self.firewall_rule(name='fwr1') as fwr1, \ @@ -950,7 +568,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): attrs['destination_port'] = '30:40' with self.firewall_rule() as fwr: data = {'firewall_rule': {'name': name, - 'protocol': PROTOCOL, + 'protocol': self.PROTOCOL, 'source_port': '10:20', 'destination_port': '30:40'}} req = self.new_update_request('firewall_rules', data, @@ -964,7 +582,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): attrs['destination_port'] = '80' with self.firewall_rule() as fwr: data = {'firewall_rule': {'name': name, - 'protocol': PROTOCOL, + 'protocol': self.PROTOCOL, 'source_port': 10000, 'destination_port': 80}} req = self.new_update_request('firewall_rules', data, @@ -978,7 +596,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): attrs['destination_port'] = '80' with self.firewall_rule() as fwr: data = {'firewall_rule': {'name': name, - 'protocol': PROTOCOL, + 'protocol': self.PROTOCOL, 'source_port': '10000', 'destination_port': '80'}} req = self.new_update_request('firewall_rules', data, @@ -1095,7 +713,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): @testtools.skip('bug/1614680') def test_update_firewall_rule_associated_with_other_tenant_policy(self): - with self.firewall_rule(shared=SHARED, tenant_id='tenant1') as fwr: + with self.firewall_rule(shared=self, tenant_id='tenant1') as fwr: fwr_id = [fwr['firewall_rule']['id']] with self.firewall_policy(shared=False, firewall_rules=fwr_id): data = {'firewall_rule': {'shared': False}} @@ -1138,21 +756,6 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): res = req.get_response(self.ext_api) self.assertEqual(409, res.status_int) - def _test_create_firewall_group(self, attrs): - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - attrs['ingress_firewall_policy_id'] = fwp_id - attrs['egress_firewall_policy_id'] = fwp_id - with self.firewall_group( - name=attrs['name'], - ingress_firewall_policy_id=fwp_id, - egress_firewall_policy_id=fwp_id, - admin_state_up=ADMIN_STATE_UP, - ports=attrs['ports'] if 'ports' in attrs else None, - ) as firewall_group: - for k, v in six.iteritems(attrs): - self.assertEqual(v, firewall_group['firewall_group'][k]) - def test_create_firewall_group(self): attrs = self._get_test_firewall_group_attrs("firewall1") self._test_create_firewall_group(attrs) @@ -1247,11 +850,6 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): attrs = self._get_test_firewall_group_attrs("firewall1") self._test_create_firewall_group(attrs) - def test_create_firewall_group_with_dvr(self): - cfg.CONF.set_override('router_distributed', True) - attrs = self._get_test_firewall_group_attrs("firewall1", "CREATED") - self._test_create_firewall_group(attrs) - def test_create_firewall_group_with_fwp_does_not_exist(self): fmt = self.fmt fwg_name = "firewall1" @@ -1260,7 +858,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): self._create_firewall_group(fmt, fwg_name, description, not_found_fwp_id, not_found_fwp_id, ports=None, - admin_state_up=ADMIN_STATE_UP, + admin_state_up=self.ADMIN_STATE_UP, expected_res_status=404) def test_create_firewall_group_with_fwp_on_different_tenant(self): @@ -1296,10 +894,12 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): fwp_id = fwp['firewall_policy']['id'] ctx = self._get_admin_context() target_tenant = 'tenant1' - with self.firewall_group(name=fwg_name, - ingress_firewall_policy_id=fwp_id, - tenant_id=target_tenant, context=ctx, - admin_state_up=ADMIN_STATE_UP) as fwg: + with self.firewall_group( + name=fwg_name, + ingress_firewall_policy_id=fwp_id, + tenant_id=target_tenant, + context=ctx, + admin_state_up=self.ADMIN_STATE_UP) as fwg: self.assertEqual(target_tenant, fwg['firewall_group']['tenant_id']) @@ -1308,13 +908,12 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): fwp_id = fwp['firewall_policy']['id'] attrs['ingress_firewall_policy_id'] = fwp_id attrs['egress_firewall_policy_id'] = fwp_id - attrs['status'] = 'PENDING_CREATE' with self.firewall_group( name=attrs['name'], ports=attrs['ports'] if 'ports' in attrs else None, ingress_firewall_policy_id=fwp_id, egress_firewall_policy_id=fwp_id, - admin_state_up=ADMIN_STATE_UP) as firewall_group: + admin_state_up=self.ADMIN_STATE_UP) as firewall_group: res = self._show_req('firewall_groups', firewall_group['firewall_group']['id']) for k, v in six.iteritems(attrs): @@ -1362,7 +961,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): fwp_id = fwp['firewall_policy']['id'] with self.firewall_group( ingress_firewall_policy_id=fwp_id, - admin_state_up=ADMIN_STATE_UP) as firewall: + admin_state_up=self.ADMIN_STATE_UP) as firewall: data = {'firewall_group': {'name': name}} req = self.new_update_request('firewall_groups', data, firewall['firewall_group']['id']) @@ -1385,7 +984,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): def_fwg_id = self._build_default_fwg(ctx=ctx)['id'] with self.port( device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF, - ctx=ctx) as dummy_port: + tenant_id=ctx.project_id) as dummy_port: port_id = dummy_port['port']['id'] success_cases = [ {'ports': [port_id]}, @@ -1406,7 +1005,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): def_fwg_id = self._build_default_fwg(ctx=ctx)['id'] with self.port( device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF, - ctx=ctx) as dummy_port: + tenant_id=ctx.project_id) as dummy_port: port_id = dummy_port['port']['id'] conflict_cases = [ {'name': ''}, @@ -1432,7 +1031,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): ctx = self._get_admin_context() with self.port( device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF, - ctx=ctx) as dummy_port: + tenant_id=ctx.project_id) as dummy_port: port_id = dummy_port['port']['id'] def_fwg_id = self._build_default_fwg(ctx=ctx)['id'] success_cases = [ @@ -1457,7 +1056,7 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): ctx = self._get_admin_context() with self.port( device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF, - ctx=ctx) as dummy_port: + tenant_id=ctx.project_id) as dummy_port: port_id = dummy_port['port']['id'] def_fwg_id = self._build_default_fwg(ctx=ctx)['id'] conflict_cases = [ @@ -1547,26 +1146,29 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): self.assertEqual(404, res.status_int) def test_update_firewall_group_fwp_not_found_on_different_tenant(self): - with self.firewall_policy(name='fwp1', tenant_id='tenant1', - do_delete=False) as fwp1, \ - self.firewall_policy(name='fwp2', shared=False, - tenant_id='tenant2') as fwp2: + ctx_tenant1 = self._get_nonadmin_context(tenant_id='tenant1') + ctx_tenant2 = self._get_nonadmin_context(tenant_id='tenant2') - fwps = [fwp1, fwp2] - # create firewall using fwp1 exists the same tenant. - fwp1_id = fwps[0]['firewall_policy']['id'] - fwp2_id = fwps[1]['firewall_policy']['id'] - ctx = self._get_nonadmin_context() - with self.firewall_group(ingress_firewall_policy_id=fwp1_id, - context=ctx) as firewall: - fw_id = firewall['firewall_group']['id'] - fw_db = self.plugin._get_firewall_group(ctx, fw_id) - fw_db['status'] = nl_constants.ACTIVE - # update firewall from fwp1 to fwp2(different tenant) - data = {'firewall_group': - {'ingress_firewall_policy_id': fwp2_id}} - req = self.new_update_request('firewall_groups', data, fw_id, - context=ctx) + with self.firewall_policy(name='fwp1', context=ctx_tenant1, + shared=False, do_delete=False) as fwp1, \ + self.firewall_group( + ingress_firewall_policy_id=fwp1['firewall_policy']['id'], + context=ctx_tenant1, do_delete=False) as fwg: + fwg_id = fwg['firewall_group']['id'] + # fw_db = self.db._get_firewall_group(ctx_tenant1, fwg_id) + # fw_db['status'] = nl_constants.ACTIVE + + # update firewall from fwp1 to fwp2 (different tenant) + with self.firewall_policy(name='fwp2', context=ctx_tenant2, + shared=False) as fwp2: + data = { + 'firewall_group': { + 'ingress_firewall_policy_id': + fwp2['firewall_policy']['id'], + }, + } + req = self.new_update_request('firewall_groups', data, fwg_id, + context=ctx_tenant1) res = req.get_response(self.ext_api) self.assertEqual(404, res.status_int) @@ -1586,11 +1188,11 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): def test_delete_firewall_group_already_deleted(self): ctx = self._get_admin_context() - deleted_id = uuidutils.generate_uuid() - with self.firewall_group(do_delete=False) as fwg: + with self.firewall_group(do_delete=False, context=ctx) as fwg: fwg_id = fwg['firewall_group']['id'] self.assertIsNone(self.plugin.delete_firewall_group(ctx, fwg_id)) - self.assertIsNone(self.plugin.delete_firewall_group(ctx, deleted_id)) + # No error raise is fwg not found on delete + self.assertIsNone(self.plugin.delete_firewall_group(ctx, fwg_id)) def test_delete_default_firewall_group_with_admin(self): ctx_a = self._get_admin_context() @@ -1980,45 +1582,36 @@ class TestFirewallDBPluginV2(FirewallPluginV2DbTestCase): def test_set_port_in_use_for_firewall_group(self): fwg_db = {'id': 'fake_id'} new_ports = {'ports': ['fake_port1', 'fake_port2']} - m_context = context.get_admin_context() + m_context = self._get_admin_context() with mock.patch.object(m_context.session, 'add', side_effect=[None, f_exc.FirewallGroupPortInUse( port_ids=['fake_port2'])]): self.assertRaises(f_exc.FirewallGroupPortInUse, - self.plugin._set_ports_for_firewall_group, + self.db._set_ports_for_firewall_group, m_context, fwg_db, new_ports) def test_set_port_for_default_firewall_group(self): ctx = self._get_nonadmin_context() - self._build_default_fwg(ctx=ctx) - with self.port(project_id=ctx.tenant_id) as port1, \ - self.port(project_id=ctx.tenant_id) as port2: + default_fwg = self._build_default_fwg(ctx=ctx) + port_args = { + 'tenant_id': ctx.tenant_id, + 'device_owner': 'compute:nova', + 'binding:vif_type': 'ovs', + } + self.plugin._is_supported_by_fw_l2_driver = mock.Mock( + return_value=True) + with self.port(**port_args) as port1, self.port(**port_args) as port2: port1_id = port1['port']['id'] port2_id = port2['port']['id'] port_ids = [port1_id, port2_id] - project_id = ctx.tenant_id - self.plugin.set_port_for_default_firewall_group( - ctx, port1_id, project_id) - self.plugin.set_port_for_default_firewall_group( - ctx, port2_id, project_id) - def_fwg_db = self.plugin._get_default_fwg(ctx, project_id) - self.assertEqual('PENDING_UPDATE', def_fwg_db['status']) - self.assertEqual(sorted(port_ids), sorted(def_fwg_db['ports'])) - - def test_set_port_for_default_firewall_group_raised_port_in_use(self): - ctx = self._get_nonadmin_context() - self._build_default_fwg(ctx=ctx) - self.plugin.update_firewall_group_status = mock.Mock() - with self.port(project_id=ctx.tenant_id) as port1: - port1_id = port1['port']['id'] - port_ids = [port1_id] - self.plugin._set_ports_for_firewall_group = mock.Mock( - side_effect=f_exc.FirewallGroupPortInUse(port_ids=port_ids)) - project_id = ctx.tenant_id - - self.plugin.set_port_for_default_firewall_group( - ctx, port1_id, project_id) - self.plugin.update_firewall_group_status.assert_not_called() + self.plugin.update_firewall_group( + ctx, + default_fwg['id'], + {'firewall_group': {'ports': port_ids}}, + ) + default_fwg = self.plugin.get_firewall_group(ctx, + default_fwg['id']) + self.assertEqual(sorted(port_ids), sorted(default_fwg['ports'])) diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/l2/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/agents/l2/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/l3reference/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/agents/l3reference/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/drivers/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/noop/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/noop/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/noop/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/noop/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/noop/test_noop_driver.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/noop/test_noop_driver.py similarity index 93% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/noop/test_noop_driver.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/noop/test_noop_driver.py index 2c23e40f7..fea3c29f3 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/noop/test_noop_driver.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/noop/test_noop_driver.py @@ -16,7 +16,8 @@ import mock from neutron import manager -from neutron_fwaas.services.firewall.drivers.linux.l2.noop import noop_driver +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + noop import noop_driver from neutron_fwaas.tests import base diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/test_firewall.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/test_firewall.py similarity index 98% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/test_firewall.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/test_firewall.py index f4fe762ae..86d96b493 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/test_firewall.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/test_firewall.py @@ -24,12 +24,12 @@ from neutron.plugins.ml2.drivers.openvswitch.agent import \ ovs_agent_extension_api as ovs_ext_api from neutron.tests import base -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import constants as fwaas_ovs_consts -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import exceptions -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import firewall as ovsfw +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import constants as fwaas_ovs_consts +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import exceptions +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import firewall as ovsfw TESTING_VLAN_TAG = 1 diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/test_rules.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/test_rules.py similarity index 97% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/test_rules.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/test_rules.py index 7d36ef1b8..5c776827b 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/l2/openvswitch_firewall/test_rules.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/l2/openvswitch_firewall/test_rules.py @@ -20,12 +20,12 @@ from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \ as ovs_consts from neutron.tests import base -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import constants as fwaas_ovs_consts -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import firewall as ovsfw -from neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall \ - import rules +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import constants as fwaas_ovs_consts +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import firewall as ovsfw +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.\ + openvswitch_firewall import rules TESTING_VLAN_TAG = 1 diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_iptables_fwaas.py similarity index 99% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_iptables_fwaas.py index eef0264c3..3b5bb59a6 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_iptables_fwaas.py @@ -19,7 +19,8 @@ import mock from neutron.tests import base from neutron.tests.unit.api.v2 import test_base as test_api_v2 -import neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas as fwaas +import neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.\ + iptables_fwaas as fwaas _uuid = test_api_v2._uuid diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas_v2.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_iptables_fwaas_v2.py similarity index 99% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas_v2.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_iptables_fwaas_v2.py index e3eb640e0..61caae69c 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas_v2.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_iptables_fwaas_v2.py @@ -19,7 +19,8 @@ import mock from neutron.tests import base from neutron.tests.unit.api.v2 import test_base as test_api_v2 -import neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas_v2 as fwaas +import neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.\ + iptables_fwaas_v2 as fwaas _uuid = test_api_v2._uuid diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_legacy_conntrack.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_legacy_conntrack.py similarity index 95% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_legacy_conntrack.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_legacy_conntrack.py index d23f8c305..a04f2935a 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_legacy_conntrack.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_legacy_conntrack.py @@ -17,7 +17,8 @@ import mock import testtools from neutron.tests import base -from neutron_fwaas.services.firewall.drivers.linux import legacy_conntrack +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux \ + import legacy_conntrack from neutron_lib import constants @@ -128,8 +129,8 @@ class ConntrackLegacyTestCase(base.BaseTestCase): def test_delete_entries(self): list_entries_mock = mock.patch( - 'neutron_fwaas.services.firewall.drivers.linux' - '.legacy_conntrack.ConntrackLegacy.list_entries') + 'neutron_fwaas.services.firewall.service_drivers.agents.drivers.' + 'linux.legacy_conntrack.ConntrackLegacy.list_entries') self.list_entries = list_entries_mock.start() self.conntrack_driver.list_entries.return_value = [ diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_netlink_conntrack.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_netlink_conntrack.py similarity index 98% rename from neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_netlink_conntrack.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_netlink_conntrack.py index 33258690e..0637459df 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_netlink_conntrack.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/drivers/linux/test_netlink_conntrack.py @@ -15,7 +15,8 @@ import mock -from neutron_fwaas.services.firewall.drivers.linux import netlink_conntrack +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux \ + import netlink_conntrack from neutron_fwaas.tests import base FW_RULES = [ diff --git a/neutron_fwaas/tests/unit/services/firewall/plugins/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l2/__init__.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/plugins/__init__.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l2/__init__.py diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/l2/fake_data.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l2/fake_data.py similarity index 100% rename from neutron_fwaas/tests/unit/services/firewall/agents/l2/fake_data.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l2/fake_data.py diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/l2/test_fwaas_v2.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l2/test_fwaas_v2.py similarity index 99% rename from neutron_fwaas/tests/unit/services/firewall/agents/l2/test_fwaas_v2.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l2/test_fwaas_v2.py index cc1c5c20d..f3e850a18 100644 --- a/neutron_fwaas/tests/unit/services/firewall/agents/l2/test_fwaas_v2.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l2/test_fwaas_v2.py @@ -21,9 +21,10 @@ from neutron_lib.exceptions import firewall_v2 as f_exc from oslo_config import cfg from neutron_fwaas.common import fwaas_constants as consts -from neutron_fwaas.services.firewall.agents.l2 import fwaas_v2 +from neutron_fwaas.services.firewall.service_drivers.agents.l2 import fwaas_v2 from neutron_fwaas.tests import base -from neutron_fwaas.tests.unit.services.firewall.agents.l2 import fake_data +from neutron_fwaas.tests.unit.services.firewall.service_drivers.agents.l2\ + import fake_data class TestFWaasV2AgentExtensionBase(base.BaseTestCase): diff --git a/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/__init__.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/l3reference/test_firewall_l3_agent.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/test_firewall_l3_agent.py similarity index 98% rename from neutron_fwaas/tests/unit/services/firewall/agents/l3reference/test_firewall_l3_agent.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/test_firewall_l3_agent.py index 9c68aac10..5e29d6aa8 100644 --- a/neutron_fwaas/tests/unit/services/firewall/agents/l3reference/test_firewall_l3_agent.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/test_firewall_l3_agent.py @@ -24,11 +24,12 @@ from oslo_utils import uuidutils import testtools from neutron_fwaas.common import fwaas_constants -from neutron_fwaas.services.firewall.agents import firewall_agent_api -from neutron_fwaas.services.firewall.agents.l3reference \ +from neutron_fwaas.services.firewall.service_drivers.agents \ + import firewall_agent_api +from neutron_fwaas.services.firewall.service_drivers.agents.l3reference \ import firewall_l3_agent from neutron_fwaas.tests import base -from neutron_fwaas.tests.unit.services.firewall.agents \ +from neutron_fwaas.tests.unit.services.firewall.service_drivers.agents \ import test_firewall_agent_api diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/l3reference/test_firewall_l3_agent_v2.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/test_firewall_l3_agent_v2.py similarity index 98% rename from neutron_fwaas/tests/unit/services/firewall/agents/l3reference/test_firewall_l3_agent_v2.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/test_firewall_l3_agent_v2.py index 58f980389..c1b7646e1 100644 --- a/neutron_fwaas/tests/unit/services/firewall/agents/l3reference/test_firewall_l3_agent_v2.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/l3reference/test_firewall_l3_agent_v2.py @@ -23,13 +23,14 @@ from oslo_config import cfg from oslo_utils import uuidutils from neutron_fwaas.common import fwaas_constants -from neutron_fwaas.services.firewall.agents import firewall_agent_api -from neutron_fwaas.services.firewall.agents.l3reference \ - import firewall_l3_agent_v2 -from neutron_fwaas.services.firewall.drivers.linux \ +from neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux \ import iptables_fwaas_v2 +from neutron_fwaas.services.firewall.service_drivers.agents \ + import firewall_agent_api +from neutron_fwaas.services.firewall.service_drivers.agents.l3reference \ + import firewall_l3_agent_v2 from neutron_fwaas.tests import base -from neutron_fwaas.tests.unit.services.firewall.agents \ +from neutron_fwaas.tests.unit.services.firewall.service_drivers.agents \ import test_firewall_agent_api diff --git a/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_agents.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_agents.py new file mode 100644 index 000000000..b24e6338f --- /dev/null +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_agents.py @@ -0,0 +1,654 @@ +# Copyright 2016 +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock +import six + +from neutron import extensions as neutron_extensions +from neutron.tests.unit.extensions import test_l3 +from neutron_lib import constants as nl_constants +from neutron_lib import context +from neutron_lib.exceptions import firewall_v2 as f_exc +from neutron_lib.plugins import directory +from oslo_config import cfg + +from neutron_fwaas._i18n import _ +from neutron_fwaas.db.firewall.v2.firewall_db_v2 import FirewallGroup +from neutron_fwaas.services.firewall.service_drivers.agents import agents +from neutron_fwaas.tests import base +from neutron_fwaas.tests.unit.services.firewall import test_fwaas_plugin_v2 + + +FIREWALL_AGENT_PLUGIN = ('neutron_fwaas.services.firewall.service_drivers.' + 'agents.agents') +FIREWALL_AGENT_PLUGIN_KLASS = FIREWALL_AGENT_PLUGIN + '.FirewallAgentDriver' +DELETEFW_PATH = (FIREWALL_AGENT_PLUGIN + '.FirewallAgentApi.' + 'delete_firewall_group') + + +class FakeAgentApi(agents.FirewallAgentCallbacks): + """ + This class used to mock the AgentAPI delete method inherits from + FirewallCallbacks because it needs access to the firewall_deleted method. + The delete_firewall method belongs to the FirewallAgentApi, which has + no access to the firewall_deleted method normally because it's not + responsible for deleting the firewall from the DB. However, it needs + to in the unit tests since there is no agent to call back. + """ + def __init__(self): + return + + def delete_firewall_group(self, context, firewall_group, **kwargs): + self.plugin = directory.get_plugin('FIREWALL_V2') + self.firewall_db = self.plugin.driver.firewall_db + self.firewall_group_deleted(context, firewall_group['id'], **kwargs) + + +class TestFirewallAgentApi(base.BaseTestCase): + def setUp(self): + super(TestFirewallAgentApi, self).setUp() + + self.api = agents.FirewallAgentApi('topic', 'host') + + def test_init(self): + self.assertEqual('topic', self.api.client.target.topic) + self.assertEqual('host', self.api.host) + + def _call_test_helper(self, method_name): + with mock.patch.object(self.api.client, 'cast') as rpc_mock, \ + mock.patch.object(self.api.client, 'prepare') as prepare_mock: + prepare_mock.return_value = self.api.client + getattr(self.api, method_name)(mock.sentinel.context, 'test') + + prepare_args = {'fanout': True} + prepare_mock.assert_called_once_with(**prepare_args) + + rpc_mock.assert_called_once_with(mock.sentinel.context, method_name, + firewall_group='test', host='host') + + def test_create_firewall_group(self): + self._call_test_helper('create_firewall_group') + + def test_update_firewall_group(self): + self._call_test_helper('update_firewall_group') + + def test_delete_firewall_group(self): + self._call_test_helper('delete_firewall_group') + + +class TestAgentDriver(test_fwaas_plugin_v2.FirewallPluginV2TestCase, + test_l3.L3NatTestCaseMixin): + + def setUp(self): + self.agentapi_del_fw_p = mock.patch( + DELETEFW_PATH, create=True, + new=FakeAgentApi().delete_firewall_group, + ).start() + mock.patch.object(agents.neutron_rpc, 'get_client').start() + mock.patch.object(agents.neutron_rpc, 'Connection').start() + + l3_plugin_str = ('neutron.tests.unit.extensions.test_l3.' + 'TestL3NatServicePlugin') + l3_plugin = {'l3_plugin_name': l3_plugin_str} + super(TestAgentDriver, self).setUp( + service_provider=FIREWALL_AGENT_PLUGIN_KLASS, + extra_service_plugins=l3_plugin, + extra_extension_paths=neutron_extensions.__path__) + + self.callbacks = self.plugin.driver.endpoints[0] + self.db = self.plugin.driver.firewall_db + + router_distributed_opts = [ + cfg.BoolOpt( + 'router_distributed', + default=False, + help=_("System-wide flag to determine the type of router " + "that tenants can create. Only admin can override.")), + ] + cfg.CONF.register_opts(router_distributed_opts) + + @property + def _self_context(self): + return context.Context('', self._tenant_id) + + def _get_test_firewall_group_attrs(self, name, + status=nl_constants.INACTIVE): + return super(TestAgentDriver, self)._get_test_firewall_group_attrs( + name, status=status) + + def test_set_firewall_group_status(self): + ctx = context.get_admin_context() + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + ingress_firewall_policy_id=fwp_id, + admin_state_up=self.ADMIN_STATE_UP + ) as fwg: + fwg_id = fwg['firewall_group']['id'] + res = self.callbacks.set_firewall_group_status(ctx, fwg_id, + nl_constants.ACTIVE) + fwg_db = self.plugin.get_firewall_group(ctx, fwg_id) + self.assertEqual(nl_constants.ACTIVE, fwg_db['status']) + self.assertTrue(res) + res = self.callbacks.set_firewall_group_status(ctx, fwg_id, + nl_constants.ERROR) + fwg_db = self.plugin.get_firewall_group(ctx, fwg_id) + self.assertEqual(nl_constants.ERROR, fwg_db['status']) + self.assertFalse(res) + + def test_firewall_group_deleted(self): + ctx = context.get_admin_context() + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + ingress_firewall_policy_id=fwp_id, + admin_state_up=self.ADMIN_STATE_UP, + do_delete=False + ) as fwg: + fwg_id = fwg['firewall_group']['id'] + with ctx.session.begin(subtransactions=True): + fwg_db = self.db._get_firewall_group(ctx, fwg_id) + fwg_db['status'] = nl_constants.PENDING_DELETE + + observed = self.callbacks.firewall_group_deleted(ctx, fwg_id) + self.assertTrue(observed) + + self.assertRaises(f_exc.FirewallGroupNotFound, + self.plugin.get_firewall_group, + ctx, fwg_id) + + def test_firewall_group_deleted_concurrently(self): + ctx = context.get_admin_context() + alt_ctx = context.get_admin_context() + + _get_firewall_group = self.db._get_firewall_group + + def getdelete(context, fwg_id): + fwg_db = _get_firewall_group(context, fwg_id) + # NOTE(cby): Use a different session to simulate a concurrent del + with alt_ctx.session.begin(subtransactions=True): + alt_ctx.session.query(FirewallGroup).filter_by( + id=fwg_id).delete() + return fwg_db + + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + firewall_policy_id=fwp_id, + admin_state_up=self.ADMIN_STATE_UP, + do_delete=False + ) as fwg: + fwg_id = fwg['firewall_group']['id'] + with ctx.session.begin(subtransactions=True): + fwg_db = self.db._get_firewall_group(ctx, fwg_id) + fwg_db['status'] = nl_constants.PENDING_DELETE + ctx.session.flush() + + with mock.patch.object( + self.db, '_get_firewall_group', side_effect=getdelete + ): + observed = self.callbacks.firewall_group_deleted( + ctx, fwg_id) + self.assertTrue(observed) + + self.assertRaises(f_exc.FirewallGroupNotFound, + self.plugin.get_firewall_group, + ctx, fwg_id) + + def test_firewall_group_deleted_not_found(self): + ctx = context.get_admin_context() + observed = self.callbacks.firewall_group_deleted( + ctx, 'notfound') + self.assertTrue(observed) + + def test_firewall_group_deleted_error(self): + ctx = context.get_admin_context() + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + firewall_policy_id=fwp_id, + admin_state_up=self.ADMIN_STATE_UP, + ) as fwg: + fwg_id = fwg['firewall_group']['id'] + observed = self.callbacks.firewall_group_deleted( + ctx, fwg_id) + self.assertFalse(observed) + fwg_db = self.db._get_firewall_group(ctx, fwg_id) + self.assertEqual(nl_constants.ERROR, fwg_db['status']) + + def test_create_firewall_group_ports_not_specified(self): + """neutron firewall-create test-policy """ + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + name='test', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.INACTIVE, + fwg1['firewall_group']['status']) + + def test_create_firewall_group_with_ports(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1, \ + self.subnet(cidr='20.0.0.0/24') as s2: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s2['subnet']['id'], + None) + port_id2 = body['port_id'] + fwg_ports = [port_id1, port_id2] + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + name='test', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.PENDING_CREATE, + fwg1['firewall_group']['status']) + + def test_create_firewall_group_with_ports_on_diff_routers(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1, \ + self.subnet(cidr='20.0.0.0/24') as s2: + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + body = self._router_interface_action( + 'add', + r['router']['id'], + s2['subnet']['id'], + None) + port_id2 = body['port_id'] + + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r2, \ + self.subnet() as s3: + + body = self._router_interface_action( + 'add', + r2['router']['id'], + s3['subnet']['id'], + None) + port_id3 = body['port_id'] + + fwg_ports = [port_id1, port_id2, port_id3] + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + name='test', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, + ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.PENDING_CREATE, + fwg1['firewall_group']['status']) + + def test_create_firewall_group_with_ports_no_policy(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1, \ + self.subnet(cidr='20.0.0.0/24') as s2: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s2['subnet']['id'], + None) + port_id2 = body['port_id'] + fwg_ports = [port_id1, port_id2] + with self.firewall_group( + name='test', + default_policy=False, + ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.INACTIVE, + fwg1['firewall_group']['status']) + + def test_update_firewall_group_with_new_ports_no_policy(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1, \ + self.subnet(cidr='20.0.0.0/24') as s2, \ + self.subnet(cidr='30.0.0.0/24') as s3: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s2['subnet']['id'], + None) + port_id2 = body['port_id'] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s3['subnet']['id'], + None) + port_id3 = body['port_id'] + + fwg_ports = [port_id1, port_id2] + with self.firewall_group( + name='test', + default_policy=False, + ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.INACTIVE, + fwg1['firewall_group']['status']) + data = {'firewall_group': {'ports': [port_id2, port_id3]}} + req = self.new_update_request('firewall_groups', data, + fwg1['firewall_group']['id'], + context=self._self_context) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + + self.assertEqual(sorted([port_id2, port_id3]), + sorted(res['firewall_group']['ports'])) + + self.assertEqual(nl_constants.INACTIVE, + res['firewall_group']['status']) + + def test_update_firewall_group_with_new_ports_status_pending(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1, \ + self.subnet(cidr='20.0.0.0/24') as s2, \ + self.subnet(cidr='30.0.0.0/24') as s3: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s2['subnet']['id'], + None) + port_id2 = body['port_id'] + fwg_ports = [port_id1, port_id2] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s3['subnet']['id'], + None) + port_id3 = body['port_id'] + + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + name='test', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.PENDING_CREATE, + fwg1['firewall_group']['status']) + data = {'firewall_group': {'ports': [port_id2, port_id3]}} + req = self.new_update_request('firewall_groups', data, + fwg1['firewall_group']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(409, res.status_int) + + def test_update_firewall_group_with_new_ports_status_active(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1, \ + self.subnet(cidr='20.0.0.0/24') as s2, \ + self.subnet(cidr='30.0.0.0/24') as s3: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s2['subnet']['id'], + None) + port_id2 = body['port_id'] + fwg_ports = [port_id1, port_id2] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s3['subnet']['id'], + None) + port_id3 = body['port_id'] + + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + name='test', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.PENDING_CREATE, + fwg1['firewall_group']['status']) + + ctx = context.get_admin_context() + self.callbacks.set_firewall_group_status(ctx, + fwg1['firewall_group']['id'], nl_constants.ACTIVE) + data = {'firewall_group': {'ports': [port_id2, port_id3]}} + req = self.new_update_request('firewall_groups', data, + fwg1['firewall_group']['id'], + context=self._self_context) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + self.assertEqual(sorted([port_id2, port_id3]), + sorted(res['firewall_group']['ports'])) + + def test_update_firewall_rule_on_active_fwg(self): + name = "new_firewall_rule1" + attrs = self._get_test_firewall_rule_attrs(name) + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + with self.firewall_rule() as fwr: + with self.firewall_policy( + firewall_rules=[fwr['firewall_rule']['id']]) as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + name='test', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, ports=[port_id1], + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.PENDING_CREATE, + fwg1['firewall_group']['status']) + + ctx = context.get_admin_context() + self.callbacks.set_firewall_group_status(ctx, + fwg1['firewall_group']['id'], nl_constants.ACTIVE) + data = {'firewall_rule': {'name': name}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_rule'][k]) + + def test_update_firewall_rule_on_pending_create_fwg(self): + """update should fail""" + name = "new_firewall_rule1" + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet() as s1: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + with self.firewall_rule() as fwr: + with self.firewall_policy( + firewall_rules=[fwr['firewall_rule']['id']]) as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group( + name='test', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, ports=[port_id1], + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.PENDING_CREATE, + fwg1['firewall_group']['status']) + + data = {'firewall_rule': {'name': name}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(409, res.status_int) + + def test_update_firewall_group_with_non_exist_ports(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r, \ + self.subnet(cidr='30.0.0.0/24') as s: + body = self._router_interface_action( + 'add', + r['router']['id'], + s['subnet']['id'], + None) + port_id1 = body['port_id'] + foo_port_id = 'caef152d-b118-4b9b-bc77-800661bf082d' + fwg_ports = [port_id1] + with self.firewall_group( + name='test', + default_policy=False, + ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.INACTIVE, + fwg1['firewall_group']['status']) + data = {'firewall_group': {'ports': [foo_port_id]}} + req = self.new_update_request('firewall_groups', data, + fwg1['firewall_group']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + self.assertEqual('PortNotFound', + res['NeutronError']['type']) + + def test_update_firewall_group_with_ports_and_policy(self): + """neutron firewall_group create test-policy """ + with self.router(name='router1', admin_state_up=True, + tenant_id=self._tenant_id) as r,\ + self.subnet() as s1,\ + self.subnet(cidr='20.0.0.0/24') as s2: + + body = self._router_interface_action( + 'add', + r['router']['id'], + s1['subnet']['id'], + None) + port_id1 = body['port_id'] + + body = self._router_interface_action( + 'add', + r['router']['id'], + s2['subnet']['id'], + None) + port_id2 = body['port_id'] + + fwg_ports = [port_id1, port_id2] + with self.firewall_rule() as fwr: + with self.firewall_policy( + firewall_rules=[fwr['firewall_rule']['id']]) as fwp: + with self.firewall_group( + name='test', + default_policy=False, + ports=fwg_ports, + admin_state_up=True) as fwg1: + self.assertEqual(nl_constants.INACTIVE, + fwg1['firewall_group']['status']) + fwp_id = fwp["firewall_policy"]["id"] + + data = {'firewall_group': {'ports': fwg_ports}} + req = (self. + new_update_request('firewall_groups', data, + fwg1['firewall_group']['id'], + context=self._self_context)) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + self.assertEqual(nl_constants.INACTIVE, + res['firewall_group']['status']) + + data = {'firewall_group': { + 'ingress_firewall_policy_id': fwp_id}} + req = (self. + new_update_request('firewall_groups', data, + fwg1['firewall_group']['id'], + context=self._self_context)) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + self.assertEqual(nl_constants.PENDING_UPDATE, + res['firewall_group']['status']) + + def test_create_firewall_group_with_dvr(self): + cfg.CONF.set_override('router_distributed', True) + attrs = self._get_test_firewall_group_attrs("firewall1") + self._test_create_firewall_group(attrs) + + def test_create_firewall_group(self): + attrs = self._get_test_firewall_group_attrs("firewall1") + self._test_create_firewall_group(attrs) + + def test_create_firewall_group_with_empty_ports(self): + attrs = self._get_test_firewall_group_attrs("fwg1") + attrs['ports'] = [] + self._test_create_firewall_group(attrs) diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/test_firewall_agent_api.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_firewall_agent_api.py similarity index 91% rename from neutron_fwaas/tests/unit/services/firewall/agents/test_firewall_agent_api.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_firewall_agent_api.py index b82f48c15..3115b09ab 100644 --- a/neutron_fwaas/tests/unit/services/firewall/agents/test_firewall_agent_api.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_firewall_agent_api.py @@ -15,9 +15,12 @@ import mock -from neutron_fwaas.services.firewall.agents import firewall_agent_api as api -from neutron_fwaas.services.firewall.drivers import fwaas_base -from neutron_fwaas.services.firewall.drivers import fwaas_base_v2 +from neutron_fwaas.services.firewall.service_drivers.agents.drivers \ + import fwaas_base +from neutron_fwaas.services.firewall.service_drivers.agents.drivers \ + import fwaas_base_v2 +from neutron_fwaas.services.firewall.service_drivers.agents \ + import firewall_agent_api as api from neutron_fwaas.tests import base diff --git a/neutron_fwaas/tests/unit/services/firewall/agents/test_firewall_service.py b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_firewall_service.py similarity index 91% rename from neutron_fwaas/tests/unit/services/firewall/agents/test_firewall_service.py rename to neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_firewall_service.py index d3dc83f0e..950cd4ed1 100644 --- a/neutron_fwaas/tests/unit/services/firewall/agents/test_firewall_service.py +++ b/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_firewall_service.py @@ -16,10 +16,12 @@ from neutron.tests import base from oslo_config import cfg -from neutron_fwaas.services.firewall.agents import firewall_service +from neutron_fwaas.services.firewall.service_drivers.agents import\ + firewall_service -FWAAS_NOP_DEVICE = ('neutron_fwaas.tests.unit.services.firewall.agents.' - 'test_firewall_agent_api.NoopFwaasDriver') +FWAAS_NOP_DEVICE = ('neutron_fwaas.tests.unit.services.firewall.' + 'service_drivers.agents.test_firewall_agent_api.' + 'NoopFwaasDriver') class TestFirewallDeviceDriverLoading(base.BaseTestCase): diff --git a/neutron_fwaas/tests/unit/services/firewall/test_fwaas_plugin_v2.py b/neutron_fwaas/tests/unit/services/firewall/test_fwaas_plugin_v2.py index 3431dda98..2bde6541d 100644 --- a/neutron_fwaas/tests/unit/services/firewall/test_fwaas_plugin_v2.py +++ b/neutron_fwaas/tests/unit/services/firewall/test_fwaas_plugin_v2.py @@ -13,798 +13,618 @@ # License for the specific language governing permissions and limitations # under the License. +import contextlib + import mock -from neutron.tests import fake_notifier -from neutron.tests.unit.extensions import test_l3 as test_l3_plugin +import six +import webob.exc + +from neutron.api import extensions as api_ext +from neutron.db import servicetype_db as sdb +from neutron_lib.api.definitions import firewall_v2 from neutron_lib import constants as nl_constants from neutron_lib import context from neutron_lib.exceptions import firewall_v2 as f_exc -from neutron_lib.plugins import constants as plugin_constants from neutron_lib.plugins import directory -from oslo_config import cfg -import six +from oslo_utils import importutils -from neutron_fwaas.db.firewall.v2 import firewall_db_v2 -import neutron_fwaas.extensions -from neutron_fwaas.extensions import firewall_v2 +from neutron_fwaas.common import fwaas_constants +from neutron_fwaas import extensions from neutron_fwaas.services.firewall import fwaas_plugin_v2 from neutron_fwaas.tests import base -from neutron_fwaas.tests.unit.db.firewall.v2 import ( - test_firewall_db_v2 as test_db_firewall) -extensions_path = neutron_fwaas.extensions.__path__[0] - -FW_PLUGIN_KLASS = ( - "neutron_fwaas.services.firewall.fwaas_plugin_v2.FirewallPluginV2" -) +def http_client_error(req, res): + explanation = "Request '%s %s %s' failed: %s" % (req.method, req.url, + req.body, res.body) + return webob.exc.HTTPClientError(code=res.status_int, + explanation=explanation) -class FirewallTestExtensionManager(test_l3_plugin.L3TestExtensionManager): +class FirewallPluginV2TestCase(base.NeutronDbPluginV2TestCase): + DESCRIPTION = 'default description' + PROTOCOL = 'tcp' + IP_VERSION = 4 + SOURCE_IP_ADDRESS_RAW = '1.1.1.1' + DESTINATION_IP_ADDRESS_RAW = '2.2.2.2' + SOURCE_PORT = '55000:56000' + DESTINATION_PORT = '56000:57000' + ACTION = 'allow' + AUDITED = True + ENABLED = True + ADMIN_STATE_UP = True + SHARED = True - def get_resources(self): - res = super(FirewallTestExtensionManager, self).get_resources() - res = res + firewall_v2.Firewall_v2.get_resources() + resource_prefix_map = dict( + (k, firewall_v2.API_PREFIX) + for k in firewall_v2.RESOURCE_ATTRIBUTE_MAP.keys() + ) + + def setUp(self, service_provider=None, core_plugin=None, + extra_service_plugins=None, extra_extension_paths=None): + provider = fwaas_constants.FIREWALL_V2 + if not service_provider: + provider += (':dummy:neutron_fwaas.services.firewall.' + 'service_drivers.driver_api.FirewallDriverDB:default') + else: + provider += ':test:' + service_provider + ':default' + + bits = provider.split(':') + provider = { + 'service_type': bits[0], + 'name': bits[1], + 'driver': bits[2], + 'default': True, + } + # override the default service provider + self.service_providers = ( + mock.patch.object(sdb.ServiceTypeManager, + 'get_service_providers').start()) + self.service_providers.return_value = [provider] + + plugin_str = ('neutron_fwaas.services.firewall.fwaas_plugin_v2.' + 'FirewallPluginV2') + service_plugins = {'fw_plugin_name': plugin_str} + service_plugins.update(extra_service_plugins or {}) + + # we need to provide a plugin instance, although the extension manager + # will create a new instance of the plugin + plugins = { + fwaas_constants.FIREWALL_V2: fwaas_plugin_v2.FirewallPluginV2(), + } + for plugin_name, plugin_str in (extra_service_plugins or {}).items(): + plugins[plugin_name] = importutils.import_object(plugin_str) + ext_mgr = api_ext.PluginAwareExtensionManager( + ':'.join(extensions.__path__ + (extra_extension_paths or [])), + plugins, + ) + + super(FirewallPluginV2TestCase, self).setUp( + plugin=core_plugin, + service_plugins=service_plugins, + ext_mgr=ext_mgr, + ) + + # find the Firewall plugin that was instantiated by the extension + # manager + self.plugin = directory.get_plugin(fwaas_constants.FIREWALL_V2) + + def _get_admin_context(self): + # FIXME NOTE(ivasilevskaya) seems that test framework treats context + # with user_id=None/tenant_id=None (return value of + # context._get_admin_context() method) in a somewhat special way. + # So as a workaround to have the framework behave properly right now + # let's implement our own _get_admin_context method and look into the + # matter some other time. + return context.Context(user_id='admin', + tenant_id='admin-tenant', + is_admin=True) + + def _get_nonadmin_context(self, user_id='non-admin', tenant_id='tenant1'): + return context.Context(user_id=user_id, tenant_id=tenant_id) + + def _test_list_resources(self, resource, items, + neutron_context=None, + query_params=None): + if resource.endswith('y'): + resource_plural = resource.replace('y', 'ies') + else: + resource_plural = resource + 's' + + res = self._list(resource_plural, + neutron_context=neutron_context, + query_params=query_params) + resource = resource.replace('-', '_') + self.assertEqual( + sorted([i[resource]['id'] for i in items]), + sorted([i['id'] for i in res[resource_plural]])) + + def _list_req(self, resource_plural, ctx=None): + if not ctx: + ctx = self._get_admin_context() + req = self.new_list_request(resource_plural) + req.environ['neutron.context'] = ctx + return self.deserialize( + self.fmt, req.get_response(self.ext_api))[resource_plural] + + def _show_req(self, resource_plural, obj_id, ctx=None): + req = self.new_show_request(resource_plural, obj_id, fmt=self.fmt) + if not ctx: + ctx = self._get_admin_context() + req.environ['neutron.context'] = ctx + res = self.deserialize( + self.fmt, req.get_response(self.ext_api)) return res - def get_actions(self): - return [] + def _build_default_fwg(self, ctx=None, is_one=True): + res = self._list_req('firewall_groups', ctx=ctx) + if is_one: + self.assertEqual(1, len(res)) + return res[0] + return res - def get_request_extensions(self): - return [] + def _get_test_firewall_rule_attrs(self, name='firewall_rule1'): + attrs = {'name': name, + 'tenant_id': self._tenant_id, + 'project_id': self._tenant_id, + 'protocol': self.PROTOCOL, + 'ip_version': self.IP_VERSION, + 'source_ip_address': self.SOURCE_IP_ADDRESS_RAW, + 'destination_ip_address': self.DESTINATION_IP_ADDRESS_RAW, + 'source_port': self.SOURCE_PORT, + 'destination_port': self.DESTINATION_PORT, + 'action': self.ACTION, + 'enabled': self.ENABLED, + 'shared': self.SHARED} + return attrs + def _get_test_firewall_policy_attrs(self, name='firewall_policy1', + audited=AUDITED): + attrs = {'name': name, + 'description': self.DESCRIPTION, + 'tenant_id': self._tenant_id, + 'project_id': self._tenant_id, + 'firewall_rules': [], + 'audited': audited, + 'shared': self.SHARED} + return attrs -class TestFirewallAgentApi(base.BaseTestCase): - def setUp(self): - super(TestFirewallAgentApi, self).setUp() + def _get_test_firewall_group_attrs(self, name='firewall_1', + status=nl_constants.CREATED): + attrs = {'name': name, + 'tenant_id': self._tenant_id, + 'project_id': self._tenant_id, + 'admin_state_up': self.ADMIN_STATE_UP, + 'status': status} - self.api = fwaas_plugin_v2.FirewallAgentApi('topic', 'host') + return attrs - def test_init(self): - self.assertEqual('topic', self.api.client.target.topic) - self.assertEqual('host', self.api.host) + def _create_firewall_policy(self, fmt, name, description, shared, + firewall_rules, audited, + expected_res_status=None, **kwargs): + data = {'firewall_policy': {'name': name, + 'description': description, + 'firewall_rules': firewall_rules, + 'audited': audited, + 'shared': shared}} + ctx = kwargs.get('context', None) + if ctx is None or ctx.is_admin: + tenant_id = kwargs.get('tenant_id', self._tenant_id) + data['firewall_policy'].update({'tenant_id': tenant_id}) + data['firewall_policy'].update({'project_id': tenant_id}) - def _call_test_helper(self, method_name): - with mock.patch.object(self.api.client, 'cast') as rpc_mock, \ - mock.patch.object(self.api.client, 'prepare') as prepare_mock: - prepare_mock.return_value = self.api.client - getattr(self.api, method_name)(mock.sentinel.context, 'test') + req = self.new_create_request('firewall_policies', data, fmt, + context=ctx) + res = req.get_response(self.ext_api) + if expected_res_status: + self.assertEqual(expected_res_status, res.status_int) + elif res.status_int >= 400: + raise http_client_error(req, res) - prepare_args = {'fanout': True} - prepare_mock.assert_called_once_with(**prepare_args) + return res - rpc_mock.assert_called_once_with(mock.sentinel.context, method_name, - firewall_group='test', host='host') + def _replace_firewall_status(self, attrs, old_status, new_status): + if attrs['status'] is old_status: + attrs['status'] = new_status + return attrs - def test_create_firewall_group(self): - self._call_test_helper('create_firewall_group') + @contextlib.contextmanager + def firewall_policy(self, fmt=None, name='firewall_policy1', + description=DESCRIPTION, shared=SHARED, + firewall_rules=None, audited=True, + do_delete=True, **kwargs): + if firewall_rules is None: + firewall_rules = [] + if not fmt: + fmt = self.fmt + res = self._create_firewall_policy(fmt, name, description, shared, + firewall_rules, audited, **kwargs) + if res.status_int >= 400: + raise webob.exc.HTTPClientError(code=res.status_int) + firewall_policy = self.deserialize(fmt or self.fmt, res) + yield firewall_policy + if do_delete: + self._delete('firewall_policies', + firewall_policy['firewall_policy']['id']) - def test_update_firewall_group(self): - self._call_test_helper('update_firewall_group') + def _create_firewall_rule(self, fmt, name, shared, protocol, + ip_version, source_ip_address, + destination_ip_address, source_port, + destination_port, action, enabled, + expected_res_status=None, **kwargs): + tenant_id = kwargs.get('tenant_id', self._tenant_id) + data = {'firewall_rule': {'name': name, + 'protocol': protocol, + 'ip_version': ip_version, + 'source_ip_address': source_ip_address, + 'destination_ip_address': + destination_ip_address, + 'source_port': source_port, + 'destination_port': destination_port, + 'action': action, + 'enabled': enabled, + 'shared': shared}} + ctx = kwargs.get('context', None) + if ctx is None or ctx.is_admin: + tenant_id = kwargs.get('tenant_id', self._tenant_id) + data['firewall_rule'].update({'tenant_id': tenant_id}) + data['firewall_rule'].update({'project_id': tenant_id}) - def test_delete_firewall_group(self): - self._call_test_helper('delete_firewall_group') + req = self.new_create_request('firewall_rules', data, fmt, context=ctx) + res = req.get_response(self.ext_api) + if expected_res_status: + self.assertEqual(expected_res_status, res.status_int) + elif res.status_int >= 400: + raise http_client_error(req, res) + return res -class TestFirewallRouterPortBase( - test_db_firewall.FirewallPluginV2DbTestCase): + @contextlib.contextmanager + def firewall_rule(self, fmt=None, name='firewall_rule1', + shared=SHARED, protocol=PROTOCOL, ip_version=IP_VERSION, + source_ip_address=SOURCE_IP_ADDRESS_RAW, + destination_ip_address=DESTINATION_IP_ADDRESS_RAW, + source_port=SOURCE_PORT, + destination_port=DESTINATION_PORT, + action=ACTION, enabled=ENABLED, + do_delete=True, **kwargs): + if not fmt: + fmt = self.fmt + res = self._create_firewall_rule(fmt, name, shared, protocol, + ip_version, source_ip_address, + destination_ip_address, + source_port, destination_port, + action, enabled, **kwargs) + if res.status_int >= 400: + raise webob.exc.HTTPClientError(code=res.status_int) + firewall_rule = self.deserialize(fmt or self.fmt, res) + yield firewall_rule + if do_delete: + self._delete('firewall_rules', + firewall_rule['firewall_rule']['id']) - def 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_group) - self.agentapi_del_fw_p.start() + def _create_firewall_group(self, fmt, name, description, + ingress_firewall_policy_id=None, + egress_firewall_policy_id=None, + ports=None, admin_state_up=True, + expected_res_status=None, **kwargs): + if ingress_firewall_policy_id is None: + default_policy = kwargs.get('default_policy', True) + if default_policy: + res = self._create_firewall_policy( + fmt, + 'fwp', + description=self.DESCRIPTION, + shared=self.SHARED, + firewall_rules=[], + audited=self.AUDITED, + ) + firewall_policy = self.deserialize(fmt or self.fmt, res) + fwp_id = firewall_policy["firewall_policy"]["id"] + ingress_firewall_policy_id = fwp_id + data = {'firewall_group': {'name': name, + 'description': description, + 'ingress_firewall_policy_id': ingress_firewall_policy_id, + 'egress_firewall_policy_id': egress_firewall_policy_id, + 'admin_state_up': admin_state_up}} + ctx = kwargs.get('context', None) + if ctx is None or ctx.is_admin: + tenant_id = kwargs.get('tenant_id', self._tenant_id) + data['firewall_group'].update({'tenant_id': tenant_id}) + data['firewall_group'].update({'project_id': tenant_id}) + if ports is not None: + data['firewall_group'].update({'ports': ports}) - # 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.' - 'TestL3NatServicePlugin') + req = self.new_create_request('firewall_groups', data, fmt, + context=ctx) + res = req.get_response(self.ext_api) + if expected_res_status: + self.assertEqual(expected_res_status, res.status_int) + elif res.status_int >= 400: + raise http_client_error(req, res) + return res - 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} + @contextlib.contextmanager + def firewall_group(self, fmt=None, name='firewall_1', + description=DESCRIPTION, + ingress_firewall_policy_id=None, + egress_firewall_policy_id=None, + ports=None, admin_state_up=True, + do_delete=True, **kwargs): + if not fmt: + fmt = self.fmt + res = self._create_firewall_group(fmt, name, description, + ingress_firewall_policy_id, + egress_firewall_policy_id, + ports=ports, + admin_state_up=admin_state_up, + **kwargs) + if res.status_int >= 400: + raise webob.exc.HTTPClientError(code=res.status_int) + firewall_group = self.deserialize(fmt or self.fmt, res) + yield firewall_group + if do_delete: + self._delete('firewall_groups', + firewall_group['firewall_group']['id']) - if not ext_mgr: - ext_mgr = FirewallTestExtensionManager() - super(test_db_firewall.FirewallPluginV2DbTestCase, self).setUp( - plugin=plugin, service_plugins=service_plugins, ext_mgr=ext_mgr) + def _rule_action(self, action, id, firewall_rule_id, insert_before=None, + insert_after=None, expected_code=webob.exc.HTTPOk.code, + expected_body=None, body_data=None): + # We intentionally do this check for None since we want to distinguish + # from empty dictionary + if body_data is None: + if action == 'insert': + body_data = {'firewall_rule_id': firewall_rule_id, + 'insert_before': insert_before, + 'insert_after': insert_after} + else: + body_data = {'firewall_rule_id': firewall_rule_id} - self.setup_notification_driver() + req = self.new_action_request('firewall_policies', + body_data, id, + "%s_rule" % action) + res = req.get_response(self.ext_api) + self.assertEqual(expected_code, res.status_int) + response = self.deserialize(self.fmt, res) + if expected_body: + self.assertEqual(expected_body, response) + return response - self.l3_plugin = directory.get_plugin(plugin_constants.L3) - self.plugin = directory.get_plugin('FIREWALL_V2') - self.callbacks = self.plugin.endpoints[0] + def _compare_firewall_rule_lists(self, firewall_policy_id, + observed_list, expected_list): + position = 0 + for r1, r2 in zip(observed_list, expected_list): + rule = r1['firewall_rule'] + rule['firewall_policy_id'] = firewall_policy_id + position += 1 + rule['position'] = position + for k in rule: + self.assertEqual(r2[k], rule[k]) - -class TestFirewallCallbacks(TestFirewallRouterPortBase): - - def setUp(self): - super(TestFirewallCallbacks, self).setUp(fw_plugin=FW_PLUGIN_KLASS) - self.callbacks = self.plugin.endpoints[0] - - def test_set_firewall_group_status(self): - ctx = context.get_admin_context() + def _test_create_firewall_group(self, attrs): with self.firewall_policy() as fwp: fwp_id = fwp['firewall_policy']['id'] + attrs['ingress_firewall_policy_id'] = fwp_id + attrs['egress_firewall_policy_id'] = fwp_id with self.firewall_group( - ingress_firewall_policy_id=fwp_id, - admin_state_up=test_db_firewall.ADMIN_STATE_UP - ) as fwg: - fwg_id = fwg['firewall_group']['id'] - res = self.callbacks.set_firewall_group_status(ctx, fwg_id, - nl_constants.ACTIVE) - fwg_db = self.plugin.get_firewall_group(ctx, fwg_id) - self.assertEqual(nl_constants.ACTIVE, fwg_db['status']) - self.assertTrue(res) - res = self.callbacks.set_firewall_group_status(ctx, fwg_id, - nl_constants.ERROR) - fwg_db = self.plugin.get_firewall_group(ctx, fwg_id) - self.assertEqual(nl_constants.ERROR, fwg_db['status']) - self.assertFalse(res) - - def test_firewall_group_deleted(self): - ctx = context.get_admin_context() - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - ingress_firewall_policy_id=fwp_id, - admin_state_up=test_db_firewall.ADMIN_STATE_UP, - do_delete=False - ) as fwg: - fwg_id = fwg['firewall_group']['id'] - with ctx.session.begin(subtransactions=True): - fwg_db = self.plugin._get_firewall_group(ctx, fwg_id) - fwg_db['status'] = nl_constants.PENDING_DELETE - - observed = self.callbacks.firewall_group_deleted(ctx, fwg_id) - self.assertTrue(observed) - - self.assertRaises(f_exc.FirewallGroupNotFound, - self.plugin.get_firewall_group, - ctx, fwg_id) - - def test_firewall_group_deleted_concurrently(self): - ctx = context.get_admin_context() - alt_ctx = context.get_admin_context() - - _get_firewall_group = self.plugin._get_firewall_group - - def getdelete(context, fwg_id): - fwg_db = _get_firewall_group(context, fwg_id) - # NOTE(cby): Use a different session to simulate a concurrent del - with mock.patch.object( - firewall_db_v2.Firewall_db_mixin_v2, - 'delete_firewall_group', - return_value=None): - self.plugin.delete_db_firewall_group_object(alt_ctx, fwg_id) - return fwg_db - - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - firewall_policy_id=fwp_id, - admin_state_up=test_db_firewall.ADMIN_STATE_UP, - do_delete=False - ) as fwg: - fwg_id = fwg['firewall_group']['id'] - with ctx.session.begin(subtransactions=True): - fwg_db = self.plugin._get_firewall_group(ctx, fwg_id) - fwg_db['status'] = nl_constants.PENDING_DELETE - ctx.session.flush() - with mock.patch.object( - self.plugin, '_get_firewall_group', side_effect=getdelete - ): - observed = self.callbacks.firewall_group_deleted( - ctx, fwg_id) - self.assertTrue(observed) - - self.assertRaises(f_exc.FirewallGroupNotFound, - self.plugin.get_firewall_group, - ctx, fwg_id) - - def test_firewall_group_deleted_not_found(self): - ctx = context.get_admin_context() - observed = self.callbacks.firewall_group_deleted( - ctx, 'notfound') - self.assertTrue(observed) - - def test_firewall_group_deleted_error(self): - ctx = context.get_admin_context() - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - firewall_policy_id=fwp_id, - admin_state_up=test_db_firewall.ADMIN_STATE_UP, - ) as fwg: - fwg_id = fwg['firewall_group']['id'] - observed = self.callbacks.firewall_group_deleted( - ctx, fwg_id) - self.assertFalse(observed) - fwg_db = self.plugin._get_firewall_group(ctx, fwg_id) - self.assertEqual(nl_constants.ERROR, fwg_db['status']) - - -class TestFirewallPluginBasev2(TestFirewallRouterPortBase, - test_l3_plugin.L3NatTestCaseMixin): - - def setUp(self): - super(TestFirewallPluginBasev2, self).setUp(fw_plugin=FW_PLUGIN_KLASS) - fake_notifier.reset() - mock.patch.object(self.plugin, '_is_supported_by_fw_l2_driver', - return_value=True).start() - - @property - def _self_context(self): - return context.Context('', self._tenant_id) - - def test_create_firewall_group_ports_not_specified(self): - """neutron firewall-create test-policy """ - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - name='test', + name=attrs['name'], ingress_firewall_policy_id=fwp_id, egress_firewall_policy_id=fwp_id, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.INACTIVE, - fwg1['firewall_group']['status']) + admin_state_up=self.ADMIN_STATE_UP, + ports=attrs['ports'] if 'ports' in attrs else None, + ) as firewall_group: + for k, v in six.iteritems(attrs): + self.assertEqual(v, firewall_group['firewall_group'][k]) - def test_create_firewall_group_with_ports(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1, \ - self.subnet(cidr='20.0.0.0/24') as s2: - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] +class TestFirewallPluginBasev2(FirewallPluginV2TestCase): + def test_create_firewall_group_with_port_on_different_project(self): + with self.port(tenant_id='fake_project_id_1') as port: + admin_ctx = context.get_admin_context() + self._create_firewall_group( + self.fmt, + "firewall_group1", + self.DESCRIPTION, + context=admin_ctx, + ports=[port['port']['id']], + expected_res_status=webob.exc.HTTPConflict.code, + ) - body = self._router_interface_action( - 'add', - r['router']['id'], - s2['subnet']['id'], - None) - port_id2 = body['port_id'] - fwg_ports = [port_id1, port_id2] - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - name='test', - ingress_firewall_policy_id=fwp_id, - egress_firewall_policy_id=fwp_id, ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.PENDING_CREATE, - fwg1['firewall_group']['status']) - - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - self._router_interface_action( - 'remove', - r['router']['id'], - s2['subnet']['id'], - None) - - def test_create_firewall_group_with_ports_on_diff_routers(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1, \ - self.subnet(cidr='20.0.0.0/24') as s2: - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] - body = self._router_interface_action( - 'add', - r['router']['id'], - s2['subnet']['id'], - None) - port_id2 = body['port_id'] - - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r2, \ - self.subnet() as s3: - - body = self._router_interface_action( - 'add', - r2['router']['id'], - s3['subnet']['id'], - None) - port_id3 = body['port_id'] - - fwg_ports = [port_id1, port_id2, port_id3] - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - name='test', - ingress_firewall_policy_id=fwp_id, - egress_firewall_policy_id=fwp_id, - ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.PENDING_CREATE, - fwg1['firewall_group']['status']) - - self._router_interface_action('remove', - r2['router']['id'], - s3['subnet']['id'], - None) - - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - self._router_interface_action( - 'remove', - r['router']['id'], - s2['subnet']['id'], - None) - - def test_create_firewall_group_with_ports_no_policy(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1, \ - self.subnet(cidr='20.0.0.0/24') as s2: - - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] - - body = self._router_interface_action( - 'add', - r['router']['id'], - s2['subnet']['id'], - None) - port_id2 = body['port_id'] - fwg_ports = [port_id1, port_id2] - with self.firewall_group( - name='test', - default_policy=False, - ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.INACTIVE, - fwg1['firewall_group']['status']) - - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - self._router_interface_action( - 'remove', - r['router']['id'], - s2['subnet']['id'], - None) - - def test_update_firewall_group_with_new_ports_no_polcy(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1, \ - self.subnet(cidr='20.0.0.0/24') as s2, \ - self.subnet(cidr='30.0.0.0/24') as s3: - - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] - - body = self._router_interface_action( - 'add', - r['router']['id'], - s2['subnet']['id'], - None) - port_id2 = body['port_id'] - - body = self._router_interface_action( - 'add', - r['router']['id'], - s3['subnet']['id'], - None) - port_id3 = body['port_id'] - - fwg_ports = [port_id1, port_id2] - with self.firewall_group( - name='test', - default_policy=False, - ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.INACTIVE, - fwg1['firewall_group']['status']) - data = {'firewall_group': {'ports': [port_id2, port_id3]}} - req = self.new_update_request('firewall_groups', data, - fwg1['firewall_group']['id'], - context=self._self_context) - res = self.deserialize(self.fmt, - req.get_response(self.ext_api)) - - self.assertEqual(sorted([port_id2, port_id3]), - sorted(res['firewall_group']['ports'])) - - self.assertEqual(nl_constants.INACTIVE, - res['firewall_group']['status']) - - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - self._router_interface_action( - 'remove', - r['router']['id'], - s2['subnet']['id'], - None) - - def test_update_firewall_group_with_new_ports_status_pending(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1, \ - self.subnet(cidr='20.0.0.0/24') as s2, \ - self.subnet(cidr='30.0.0.0/24') as s3: - - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] - - body = self._router_interface_action( - 'add', - r['router']['id'], - s2['subnet']['id'], - None) - port_id2 = body['port_id'] - fwg_ports = [port_id1, port_id2] - - body = self._router_interface_action( - 'add', - r['router']['id'], - s3['subnet']['id'], - None) - port_id3 = body['port_id'] - - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - name='test', - ingress_firewall_policy_id=fwp_id, - egress_firewall_policy_id=fwp_id, ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.PENDING_CREATE, - fwg1['firewall_group']['status']) - data = {'firewall_group': {'ports': [port_id2, port_id3]}} - req = self.new_update_request('firewall_groups', data, - fwg1['firewall_group']['id']) - res = req.get_response(self.ext_api) - self.assertEqual(409, res.status_int) - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - self._router_interface_action( - 'remove', - r['router']['id'], - s2['subnet']['id'], - None) - - def test_update_firewall_group_with_new_ports_status_active(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1, \ - self.subnet(cidr='20.0.0.0/24') as s2, \ - self.subnet(cidr='30.0.0.0/24') as s3: - - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] - - body = self._router_interface_action( - 'add', - r['router']['id'], - s2['subnet']['id'], - None) - port_id2 = body['port_id'] - fwg_ports = [port_id1, port_id2] - - body = self._router_interface_action( - 'add', - r['router']['id'], - s3['subnet']['id'], - None) - port_id3 = body['port_id'] - - with self.firewall_policy() as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - name='test', - ingress_firewall_policy_id=fwp_id, - egress_firewall_policy_id=fwp_id, ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.PENDING_CREATE, - fwg1['firewall_group']['status']) - - ctx = context.get_admin_context() - self.callbacks.set_firewall_group_status(ctx, - fwg1['firewall_group']['id'], nl_constants.ACTIVE) - data = {'firewall_group': {'ports': [port_id2, port_id3]}} - req = self.new_update_request('firewall_groups', data, - fwg1['firewall_group']['id'], - context=self._self_context) - res = self.deserialize(self.fmt, - req.get_response(self.ext_api)) - self.assertEqual(sorted([port_id2, port_id3]), - sorted(res['firewall_group']['ports'])) - - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - self._router_interface_action( - 'remove', - r['router']['id'], - s2['subnet']['id'], - None) - - def test_update_firewall_rule_on_active_fwg(self): - name = "new_firewall_rule1" - attrs = self._get_test_firewall_rule_attrs(name) - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1: - - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] - with self.firewall_rule() as fwr: - with self.firewall_policy( - firewall_rules=[fwr['firewall_rule']['id']]) as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - name='test', - ingress_firewall_policy_id=fwp_id, - egress_firewall_policy_id=fwp_id, ports=[port_id1], - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.PENDING_CREATE, - fwg1['firewall_group']['status']) - - ctx = context.get_admin_context() - self.callbacks.set_firewall_group_status(ctx, - fwg1['firewall_group']['id'], nl_constants.ACTIVE) - data = {'firewall_rule': {'name': name}} - req = self.new_update_request('firewall_rules', data, - fwr['firewall_rule']['id']) - res = self.deserialize(self.fmt, - req.get_response(self.ext_api)) - for k, v in six.iteritems(attrs): - self.assertEqual(v, res['firewall_rule'][k]) - - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - - def test_update_firewall_rule_on_pending_create_fwg(self): - """update should fail""" - name = "new_firewall_rule1" - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet() as s1: - - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] - with self.firewall_rule() as fwr: - with self.firewall_policy( - firewall_rules=[fwr['firewall_rule']['id']]) as fwp: - fwp_id = fwp['firewall_policy']['id'] - with self.firewall_group( - name='test', - ingress_firewall_policy_id=fwp_id, - egress_firewall_policy_id=fwp_id, ports=[port_id1], - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.PENDING_CREATE, - fwg1['firewall_group']['status']) - - data = {'firewall_rule': {'name': name}} - req = self.new_update_request('firewall_rules', data, - fwr['firewall_rule']['id']) - res = req.get_response(self.ext_api) - self.assertEqual(409, res.status_int) - - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - - def test_update_firewall_group_with_non_exist_ports(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet(cidr='30.0.0.0/24') as s: - body = self._router_interface_action( - 'add', - r['router']['id'], - s['subnet']['id'], - None) - port_id1 = body['port_id'] - foo_port_id = 'caef152d-b118-4b9b-bc77-800661bf082d' - fwg_ports = [port_id1] - with self.firewall_group( - name='test', - default_policy=False, - ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.INACTIVE, - fwg1['firewall_group']['status']) - data = {'firewall_group': {'ports': [foo_port_id]}} - req = self.new_update_request('firewall_groups', data, - fwg1['firewall_group']['id']) - res = self.deserialize(self.fmt, - req.get_response(self.ext_api)) - self.assertEqual('PortNotFound', - res['NeutronError']['type']) - - self._router_interface_action('remove', - r['router']['id'], - s['subnet']['id'], - None) - - def _get_user_context(self, user_id="a_user", tenant_id="some_tenant", - is_admin=False): - return context.Context(user_id=user_id, tenant_id=tenant_id, - is_admin=is_admin) - - def test_update_firewall_group_with_invalid_project(self): - with self.router(name='router1', - admin_state_up=True, - tenant_id=self._tenant_id) as r, \ - self.subnet(cidr='30.0.0.0/24') as s: - body = self._router_interface_action('add', - r['router']['id'], - s['subnet']['id'], - None) - port_id = body['port_id'] - with self.firewall_group(name='test', - default_policy=False, - ports=[], - admin_state_up=True, - ctx=self._get_user_context()) as fwg1: - data = {'firewall_group': {'ports': [port_id]}} - # make sure that an exception is raised when admin tries to - # update ports of another tenant + def test_update_firewall_group_with_port_on_different_project(self): + ctx = context.Context('not_admin', 'fake_project_id_1') + with self.firewall_group(ctx=ctx) as firewall_group: + with self.port(tenant_id='fake_project_id_2') as port: + data = { + 'firewall_group': { + 'ports': [port['port']['id']], + }, + } req = self.new_update_request( - 'firewall_groups', data, fwg1['firewall_group']['id'], - context=context.get_admin_context()) - res = self.deserialize(self.fmt, - req.get_response(self.ext_api)) - self.assertEqual('FirewallGroupPortInvalidProject', - res['NeutronError']['type']) + 'firewall_groups', + data, + firewall_group['firewall_group']['id'], + ) + res = req.get_response(self.ext_api) + self.assertEqual(webob.exc.HTTPConflict.code, res.status_int) - self._router_interface_action('remove', - r['router']['id'], - s['subnet']['id'], - None) + def test_create_firewall_group_with_with_wrong_type_port(self): + with self.port(device_owner="wrong port type") as port: + self._create_firewall_group( + self.fmt, + "firewall_group1", + self.DESCRIPTION, + ports=[port['port']['id']], + expected_res_status=webob.exc.HTTPConflict.code, + ) - def test_update_firewall_group_with_ports_and_polcy(self): - """neutron firewall_group create test-policy """ - with self.router(name='router1', admin_state_up=True, - tenant_id=self._tenant_id) as r,\ - self.subnet() as s1,\ - self.subnet(cidr='20.0.0.0/24') as s2: + def test_update_firewall_group_with_with_wrong_type_port(self): + with self.firewall_group() as firewall_group: + with self.port(device_owner="wrong port type") as port: + data = { + 'firewall_group': { + 'ports': [port['port']['id']], + }, + } + req = self.new_update_request( + 'firewall_groups', + data, + firewall_group['firewall_group']['id'], + ) + res = req.get_response(self.ext_api) + self.assertEqual(webob.exc.HTTPConflict.code, res.status_int) - body = self._router_interface_action( - 'add', - r['router']['id'], - s1['subnet']['id'], - None) - port_id1 = body['port_id'] + def test_create_firewall_group_with_port_already_in_use(self): + with self.port( + device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF) as port: + with self.firewall_group(ports=[port['port']['id']]): + self._create_firewall_group( + self.fmt, + "firewall_group2", + self.DESCRIPTION, + ports=[port['port']['id']], + expected_res_status=webob.exc.HTTPConflict.code, + ) - body = self._router_interface_action( - 'add', - r['router']['id'], - s2['subnet']['id'], - None) - port_id2 = body['port_id'] + def test_update_firewall_group_with_port_already_in_use(self): + with self.port( + device_owner=nl_constants.DEVICE_OWNER_ROUTER_INTF) as port: + with self.firewall_group(ports=[port['port']['id']]): + with self.firewall_group() as firewall_group: + data = { + 'firewall_group': { + 'ports': [port['port']['id']], + }, + } + req = self.new_update_request( + 'firewall_groups', + data, + firewall_group['firewall_group']['id'], + ) + res = req.get_response(self.ext_api) + self.assertEqual(webob.exc.HTTPConflict.code, + res.status_int) - fwg_ports = [port_id1, port_id2] + def test_firewall_group_policy_rule_can_be_updated(self): + pending_status = [nl_constants.PENDING_CREATE, + nl_constants.PENDING_UPDATE, + nl_constants.PENDING_DELETE] + + for status in pending_status: with self.firewall_rule() as fwr: - with self.firewall_policy( - firewall_rules=[fwr['firewall_rule']['id']]) as fwp: + fwr_id = fwr['firewall_rule']['id'] + with self.firewall_policy(firewall_rules=[fwr_id]) as fwp: + fwp_id = fwp['firewall_policy']['id'] with self.firewall_group( - name='test', - default_policy=False, - ports=fwg_ports, - admin_state_up=True) as fwg1: - self.assertEqual(nl_constants.INACTIVE, - fwg1['firewall_group']['status']) - fwp_id = fwp["firewall_policy"]["id"] + ingress_firewall_policy_id=fwp_id) as fwg: + self.plugin.driver.firewall_db.\ + update_firewall_group_status( + context.get_admin_context(), + fwg['firewall_group']['id'], + status + ) + data = { + 'firewall_rule': { + 'name': 'new_name', + }, + } + req = self.new_update_request( + 'firewall_rules', + data, + fwr_id, + ) + res = req.get_response(self.ext_api) + self.assertEqual(webob.exc.HTTPConflict.code, + res.status_int) - data = {'firewall_group': {'ports': fwg_ports}} - req = (self. - new_update_request('firewall_groups', data, - fwg1['firewall_group']['id'], - context=self._self_context)) - res = self.deserialize(self.fmt, - req.get_response(self.ext_api)) - self.assertEqual(nl_constants.INACTIVE, - res['firewall_group']['status']) + def test_create_firewall_policy_with_other_project_not_shared_rule(self): + project1_context = self._get_nonadmin_context(tenant_id='project1') + project2_context = self._get_nonadmin_context(tenant_id='project2') + with self.firewall_rule(context=project1_context, shared=False) as fwr: + fwr_id = fwr['firewall_rule']['id'] + self.firewall_policy( + context=project2_context, + firewall_rules=[fwr_id], + expected_res_status=webob.exc.HTTPNotFound.code, + ) - data = {'firewall_group': { - 'ingress_firewall_policy_id': fwp_id}} - req = (self. - new_update_request('firewall_groups', data, - fwg1['firewall_group']['id'], - context=self._self_context)) - res = self.deserialize(self.fmt, - req.get_response(self.ext_api)) - self.assertEqual(nl_constants.PENDING_UPDATE, - res['firewall_group']['status']) + def test_update_firewall_policy_with_other_project_not_shared_rule(self): + project1_context = self._get_nonadmin_context(tenant_id='project1') + project2_context = self._get_nonadmin_context(tenant_id='project2') + with self.firewall_rule(context=project1_context, shared=False) as fwr: + with self.firewall_policy(context=project2_context, + shared=False) as fwp: + fwr_id = fwr['firewall_rule']['id'] + fwp_id = fwp['firewall_policy']['id'] + data = { + 'firewall_policy': { + 'firewall_rules': [fwr_id], + }, + } + req = self.new_update_request('firewall_policy', data, fwp_id) + res = req.get_response(self.ext_api) + self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int) - self._router_interface_action('remove', - r['router']['id'], - s1['subnet']['id'], - None) - self._router_interface_action( - 'remove', - r['router']['id'], - s2['subnet']['id'], - None) + def test_create_firewall_policy_with_other_project_shared_rule(self): + admin_context = self._get_admin_context() + project1_context = self._get_nonadmin_context(tenant_id='project1') + with self.firewall_rule(context=admin_context, shared=True) as fwr: + fwr_id = fwr['firewall_rule']['id'] + self.firewall_policy( + context=project1_context, + firewall_rules=[fwr_id], + expected_res_status=webob.exc.HTTPOk.code, + ) class TestAutomaticAssociation(TestFirewallPluginBasev2): - def setUp(self): # TODO(yushiro): Replace constant value for this test class # Set auto association fwg super(TestAutomaticAssociation, self).setUp() - self.agent_rpc = self.plugin.agent_rpc - self.plugin.set_port_for_default_firewall_group = mock.Mock() - self.plugin._get_fwg_port_details = mock.Mock() def test_vm_port(self): - self.plugin._get_fwg_port_details = mock.Mock() + port = { + "id": "fake_port", + "device_owner": "compute:nova", + "binding:vif_type": "ovs", + "binding:vif_details": {"ovs_hybrid_plug": False}, + "project_id": "fake_project", + "port_security_enabled": True, + } + self.plugin._core_plugin.get_port = mock.Mock(return_value=port) + fake_default_fwg = { + 'id': 'fake_id', + 'name': 'default', + 'ports': ['fake_port_id1'], + } + self.plugin.get_firewall_groups = \ + mock.Mock(return_value=[fake_default_fwg]) + self.plugin.update_firewall_group = mock.Mock() kwargs = { "context": mock.ANY, - "port": {"id": "fake_port", - "device_owner": "compute:nova", - "binding:vif_type": "ovs", - "project_id": "fake_project"}, + "port": port, "original_port": {"binding:vif_type": "unbound"} } self.plugin.handle_update_port( "PORT", "after_update", "test_plugin", **kwargs) - self.plugin.set_port_for_default_firewall_group.\ - assert_called_once_with(mock.ANY, - kwargs['port']['id'], - kwargs['port']['project_id']) + self.plugin.get_firewall_groups.assert_called_once_with( + mock.ANY, + filters={ + 'tenant_id': [kwargs['port']['project_id']], + 'name': [fake_default_fwg['name']], + }, + fields=['id', 'ports'], + ) + port_ids = fake_default_fwg['ports'] + [kwargs['port']['id']] + self.plugin.update_firewall_group.assert_called_once_with( + mock.ANY, + fake_default_fwg['id'], + {'firewall_group': {'ports': port_ids}}, + ) def test_vm_port_not_newly_created(self): + self.plugin.get_firewall_group = mock.Mock() + self.plugin.update_firewall_group = mock.Mock() # Just updated for VM port(name or description...etc.) kwargs = { "context": mock.ANY, @@ -822,9 +642,12 @@ class TestAutomaticAssociation(TestFirewallPluginBasev2): } self.plugin.handle_update_port( "PORT", "after_update", "test_plugin", **kwargs) - self.plugin.set_port_for_default_firewall_group.assert_not_called() + self.plugin.get_firewall_group.assert_not_called() + self.plugin.update_firewall_group.assert_not_called() def test_not_vm_port(self): + self.plugin.get_firewall_group = mock.Mock() + self.plugin.update_firewall_group = mock.Mock() for device_owner in ["network:router_interface", "network:router_gateway", "network:dhcp"]: @@ -839,4 +662,31 @@ class TestAutomaticAssociation(TestFirewallPluginBasev2): } self.plugin.handle_update_port( "PORT", "after_update", "test_plugin", **kwargs) - self.plugin.set_port_for_default_firewall_group.assert_not_called() + self.plugin.get_firewall_group.assert_not_called() + self.plugin.update_firewall_group.assert_not_called() + + def test_set_port_for_default_firewall_group_raised_port_in_use(self): + port_id = 'fake_port_id_already_associated_to_default_fw' + port = { + "id": port_id, + "device_owner": "compute:nova", + "binding:vif_type": "ovs", + "binding:vif_details": {"ovs_hybrid_plug": False}, + "project_id": "fake_project", + "port_security_enabled": True, + } + self.plugin._core_plugin.get_port = mock.Mock(return_value=port) + self.plugin.get_firewall_groups = mock.Mock(return_value=[]) + self.plugin.update_firewall_group = mock.Mock( + side_effect=f_exc.FirewallGroupPortInUse(port_ids=[port_id])) + kwargs = { + "context": mock.ANY, + "port": port, + "original_port": {"binding:vif_type": "unbound"} + } + try: + self.plugin.handle_update_port("PORT", "after_update", + "test_plugin", **kwargs) + except f_exc.FirewallGroupPortInUse: + self.fail("Associating port to default firewall group raises " + "'FirewallGroupPortInUse' while it should ignore it") diff --git a/setup.cfg b/setup.cfg index c1fa6ad94..fedd3c157 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,9 +34,9 @@ setup-hooks = firewall_drivers = # These are for backwards compat with Juno firewall service provider # configuration values - neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas:IptablesFwaasDriver - iptables = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas:IptablesFwaasDriver - iptables_v2 = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas_v2:IptablesFwaasDriver + neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.iptables_fwaas:IptablesFwaasDriver + iptables = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.iptables_fwaas:IptablesFwaasDriver + iptables_v2 = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.iptables_fwaas_v2:IptablesFwaasDriver neutron.service_plugins = firewall = neutron_fwaas.services.firewall.fwaas_plugin:FirewallPlugin firewall_v2 = neutron_fwaas.services.firewall.fwaas_plugin_v2:FirewallPluginV2 @@ -50,16 +50,16 @@ oslo.config.opts = neutron.fwaas = neutron_fwaas.opts:list_opts firewall.agent = neutron_fwaas.opts:list_agent_opts neutron.agent.l2.extensions = - fwaas_v2 = neutron_fwaas.services.firewall.agents.l2.fwaas_v2:FWaaSV2AgentExtension + fwaas_v2 = neutron_fwaas.services.firewall.service_drivers.agents.l2.fwaas_v2:FWaaSV2AgentExtension neutron.agent.l2.firewall_drivers = - noop = neutron_fwaas.services.firewall.drivers.linux.l2.noop.noop_driver:NoopFirewallL2Driver - ovs = neutron_fwaas.services.firewall.drivers.linux.l2.openvswitch_firewall.firewall:OVSFirewallDriver + noop = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.noop.noop_driver:NoopFirewallL2Driver + ovs = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.l2.openvswitch_firewall.firewall:OVSFirewallDriver neutron.agent.l3.extensions = - fwaas = neutron_fwaas.services.firewall.agents.l3reference.firewall_l3_agent:L3WithFWaaS - fwaas_v2 = neutron_fwaas.services.firewall.agents.l3reference.firewall_l3_agent_v2:L3WithFWaaS -neutron_fwaas.services.firewall.drivers.linux = - conntrack = neutron_fwaas.services.firewall.drivers.linux.legacy_conntrack:ConntrackLegacy - netlink_conntrack = neutron_fwaas.services.firewall.drivers.linux.netlink_conntrack:ConntrackNetlink + fwaas = neutron_fwaas.services.firewall.service_drivers.agents.l3reference.firewall_l3_agent:L3WithFWaaS + fwaas_v2 = neutron_fwaas.services.firewall.service_drivers.agents.l3reference.firewall_l3_agent_v2:L3WithFWaaS +neutron.agent.l3.firewall_drivers = + conntrack = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.legacy_conntrack:ConntrackLegacy + netlink_conntrack = neutron_fwaas.services.firewall.service_drivers.agents.drivers.linux.netlink_conntrack:ConntrackNetlink [extract_messages] keywords = _ gettext ngettext l_ lazy_gettext