diff --git a/neutron_fwaas/db/firewall/v2/__init__.py b/neutron_fwaas/db/firewall/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron_fwaas/db/firewall/v2/firewall_db_v2.py b/neutron_fwaas/db/firewall/v2/firewall_db_v2.py new file mode 100644 index 000000000..a5c061ca8 --- /dev/null +++ b/neutron_fwaas/db/firewall/v2/firewall_db_v2.py @@ -0,0 +1,633 @@ +# Copyright (c) 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. + +from neutron.db import common_db_mixin as base_db +from neutron.db import model_base +from neutron.db import models_v2 +from neutron.plugins.common import constants as p_const +import neutron_lib.constants as libconstants +from oslo_config import cfg +from oslo_log import log as logging +from oslo_utils import uuidutils +import sqlalchemy as sa +from sqlalchemy.ext.orderinglist import ordering_list +from sqlalchemy import orm +from sqlalchemy.orm import exc + +import netaddr + +from neutron_fwaas.extensions import firewall_v2 as fw_ext + +LOG = logging.getLogger(__name__) + + +class HasName(object): + name = sa.Column(sa.String(255)) + + +class HasDescription(object): + description = sa.Column(sa.String(1024)) + + +class FirewallRuleV2(model_base.BASEV2, models_v2.HasId, HasName, + HasDescription, model_base.HasProject): + __tablename__ = "firewall_rules_v2" + public = sa.Column(sa.Boolean) + protocol = sa.Column(sa.String(40)) + ip_version = sa.Column(sa.Integer) + source_ip_address = sa.Column(sa.String(46)) + destination_ip_address = sa.Column(sa.String(46)) + source_port_range_min = sa.Column(sa.Integer) + source_port_range_max = sa.Column(sa.Integer) + destination_port_range_min = sa.Column(sa.Integer) + destination_port_range_max = sa.Column(sa.Integer) + action = sa.Column(sa.Enum('allow', 'deny', 'reject', + name='firewallrules_action')) + enabled = sa.Column(sa.Boolean) + + +class FirewallGroup(model_base.BASEV2, models_v2.HasId, HasName, + HasDescription, model_base.HasProject): + __tablename__ = 'firewall_groups_v2' + ports = orm.relationship( + 'FirewallGroupPortAssociation', + backref=orm.backref('firewall_group_port_associations_v2', + cascade='all, delete')) + name = sa.Column(sa.String(255)) + description = sa.Column(sa.String(1024)) + public = sa.Column(sa.Boolean) + ingress_firewall_policy_id = sa.Column(sa.String(36), + sa.ForeignKey( + 'firewall_policies_v2.id')) + egress_firewall_policy_id = sa.Column(sa.String(36), + sa.ForeignKey( + 'firewall_policies_v2.id')) + admin_state_up = sa.Column(sa.Boolean) + status = sa.Column(sa.String(16)) + + +class FirewallGroupPortAssociation(model_base.BASEV2): + __tablename__ = 'firewall_group_port_associations_v2' + firewall_group_id = sa.Column(sa.String(36), + sa.ForeignKey('firewall_groups_v2.id'), + primary_key=True) + port_id = sa.Column(sa.String(36), + sa.ForeignKey('ports.id'), + primary_key=True) + + +class FirewallPolicyRuleAssociation(model_base.BASEV2): + + """Tracks FW Policy and Rule(s) Association""" + + __tablename__ = 'firewall_policy_rule_associations_v2' + + firewall_policy_id = sa.Column(sa.String(36), + sa.ForeignKey('firewall_policies_v2.id', ondelete="CASCADE"), + primary_key=True) + firewall_rule_id = sa.Column(sa.String(36), + sa.ForeignKey('firewall_rules_v2.id', ondelete="CASCADE"), + primary_key=True) + position = sa.Column(sa.Integer) + + +class FirewallPolicy(model_base.BASEV2, models_v2.HasId, HasName, + HasDescription, model_base.HasProject): + __tablename__ = 'firewall_policies_v2' + name = sa.Column(sa.String(255)) + description = sa.Column(sa.String(1024)) + public = sa.Column(sa.Boolean) + rule_count = sa.Column(sa.Integer) + audited = sa.Column(sa.Boolean) + firewall_rules = orm.relationship( + FirewallPolicyRuleAssociation, + backref=orm.backref('firewall_policies_v2', cascade='all, delete'), + order_by='FirewallPolicyRuleAssociation.position', + collection_class=ordering_list('position', count_from=1)) + + +class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): + + def _get_firewall_group(self, context, id): + try: + return self._get_by_id(context, FirewallGroup, id) + except exc.NoResultFound: + raise fw_ext.FirewallGroupNotFound(firewall_id=id) + + def _get_firewall_policy(self, context, id): + try: + return self._get_by_id(context, FirewallPolicy, id) + except exc.NoResultFound: + raise fw_ext.FirewallPolicyNotFound(firewall_policy_id=id) + + def _get_firewall_rule(self, context, id): + try: + return self._get_by_id(context, FirewallRuleV2, id) + except exc.NoResultFound: + raise fw_ext.FirewallRuleNotFound(firewall_rule_id=id) + + def _validate_fwr_protocol_parameters(self, fwr): + protocol = fwr['protocol'] + if protocol not in (libconstants.PROTO_NAME_TCP, + libconstants.PROTO_NAME_UDP): + if fwr['source_port'] or fwr['destination_port']: + raise fw_ext.FirewallRuleInvalidICMPParameter( + param="Source, destination port") + + def _validate_fwr_src_dst_ip_version(self, fwr): + src_version = dst_version = None + if fwr['source_ip_address']: + src_version = netaddr.IPNetwork(fwr['source_ip_address']).version + if fwr['destination_ip_address']: + dst_version = netaddr.IPNetwork( + fwr['destination_ip_address']).version + rule_ip_version = fwr['ip_version'] + if ((src_version and src_version != rule_ip_version) or + (dst_version and dst_version != rule_ip_version)): + raise fw_ext.FirewallIpAddressConflict() + + def _validate_fwr_port_range(self, min_port, max_port): + if int(min_port) > int(max_port): + port_range = '%s:%s' % (min_port, max_port) + raise fw_ext.FirewallRuleInvalidPortValue(port=port_range) + + def _get_min_max_ports_from_range(self, port_range): + if not port_range: + return [None, None] + min_port, sep, max_port = port_range.partition(":") + if not max_port: + max_port = min_port + self._validate_fwr_port_range(min_port, max_port) + return [int(min_port), int(max_port)] + + def _get_port_range_from_min_max_ports(self, min_port, max_port): + if not min_port: + return None + if min_port == max_port: + return str(min_port) + self._validate_fwr_port_range(min_port, max_port) + return '%s:%s' % (min_port, max_port) + + def _make_firewall_rule_dict(self, firewall_rule, fields=None): + src_port_range = self._get_port_range_from_min_max_ports( + firewall_rule['source_port_range_min'], + firewall_rule['source_port_range_max']) + dst_port_range = self._get_port_range_from_min_max_ports( + firewall_rule['destination_port_range_min'], + firewall_rule['destination_port_range_max']) + res = {'id': firewall_rule['id'], + 'tenant_id': firewall_rule['tenant_id'], + 'name': firewall_rule['name'], + 'description': firewall_rule['description'], + 'public': firewall_rule['public'], + 'protocol': firewall_rule['protocol'], + 'ip_version': firewall_rule['ip_version'], + 'source_ip_address': firewall_rule['source_ip_address'], + 'destination_ip_address': + firewall_rule['destination_ip_address'], + 'source_port': src_port_range, + 'destination_port': dst_port_range, + 'action': firewall_rule['action'], + 'enabled': firewall_rule['enabled']} + return self._fields(res, fields) + + def _make_firewall_policy_dict(self, firewall_policy, fields=None): + fw_rules = [rule.firewall_rule_id + for rule in firewall_policy['firewall_rules']] + res = {'id': firewall_policy['id'], + 'tenant_id': firewall_policy['tenant_id'], + 'name': firewall_policy['name'], + 'description': firewall_policy['description'], + 'public': firewall_policy['public'], + 'audited': firewall_policy['audited'], + 'firewall_rules': fw_rules} + return self._fields(res, fields) + + def _make_firewall_group_dict(self, firewall_group, fields=None): + res = {'id': firewall_group['id'], + 'tenant_id': firewall_group['tenant_id'], + 'name': firewall_group['name'], + 'description': firewall_group['description'], + 'public': firewall_group['public'], + 'ingress_firewall_policy_id': + firewall_group['ingress_firewall_policy_id'], + 'egress_firewall_policy_id': + firewall_group['egress_firewall_policy_id'], + 'admin_state_up': firewall_group['admin_state_up'], + 'status': firewall_group['status']} + return self._fields(res, fields) + + 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: + ingress_policy = self.get_firewall_policy( + context, ingress_policy_id) + ingress_rules_list = [self.get_firewall_rule( + context, rule_id) for rule_id + in ingress_policy['firewall_rules']] + firewall_group['ingress_rule_list'] = ingress_rules_list + else: + firewall_group['ingress_rule_list'] = [] + + egress_policy_id = firewall_group['egress_firewall_policy_id'] + if egress_policy_id: + egress_policy = self.get_firewall_policy( + context, egress_policy_id) + egress_rules_list = [self.get_firewall_rule( + context, rule_id) for rule_id + in egress_policy['firewall_rules']] + firewall_group['egress_rule_list'] = egress_rules_list + else: + firewall_group['egress_rule_list'] = [] + return firewall_group + + def create_firewall_rule(self, context, firewall_rule): + LOG.debug("create_firewall_rule() called") + fwr = firewall_rule['firewall_rule'] + self._validate_fwr_protocol_parameters(fwr) + self._validate_fwr_src_dst_ip_version(fwr) + if not fwr['protocol'] and (fwr['source_port'] or + fwr['destination_port']): + raise fw_ext.FirewallRuleWithPortWithoutProtocolInvalid() + src_port_min, src_port_max = self._get_min_max_ports_from_range( + fwr['source_port']) + dst_port_min, dst_port_max = self._get_min_max_ports_from_range( + fwr['destination_port']) + with context.session.begin(subtransactions=True): + fwr_db = FirewallRuleV2( + id=uuidutils.generate_uuid(), + tenant_id=fwr['tenant_id'], + name=fwr['name'], + description=fwr['description'], + public=fwr['public'], + protocol=fwr['protocol'], + ip_version=fwr['ip_version'], + source_ip_address=fwr['source_ip_address'], + destination_ip_address=fwr['destination_ip_address'], + source_port_range_min=src_port_min, + source_port_range_max=src_port_max, + destination_port_range_min=dst_port_min, + destination_port_range_max=dst_port_max, + action=fwr['action'], + enabled=fwr['enabled']) + context.session.add(fwr_db) + return self._make_firewall_rule_dict(fwr_db) + + def update_firewall_rule(self, context, id, firewall_rule): + LOG.debug("update_firewall_rule() called") + fwr = firewall_rule['firewall_rule'] + fwr_db = self._get_firewall_rule(context, id) + if 'source_port' in fwr: + src_port_min, src_port_max = self._get_min_max_ports_from_range( + fwr['source_port']) + fwr['source_port_range_min'] = src_port_min + fwr['source_port_range_max'] = src_port_max + del fwr['source_port'] + if 'destination_port' in fwr: + dst_port_min, dst_port_max = self._get_min_max_ports_from_range( + fwr['destination_port']) + fwr['destination_port_range_min'] = dst_port_min + fwr['destination_port_range_max'] = dst_port_max + del fwr['destination_port'] + with context.session.begin(subtransactions=True): + protocol = fwr.get('protocol', fwr_db['protocol']) + if not protocol: + sport = fwr.get('source_port_range_min', + fwr_db['source_port_range_min']) + dport = fwr.get('destination_port_range_min', + fwr_db['destination_port_range_min']) + if sport or dport: + raise fw_ext.FirewallRuleWithPortWithoutProtocolInvalid() + fwr_db.update(fwr) + # if the rule on a policy, fix audited flag + 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): + raise fw_ext.FirewallRuleInUse(firewall_rule_id=id) + context.session.delete(fwr) + + def insert_rule(self, context, id, rule_info): + # TODO(sridar) + pass + + def remove_rule(self, context, id, rule_info): + # TODO(sridar) + pass + + def get_firewall_rule(self, context, id, fields=None): + LOG.debug("get_firewall_rule() called") + fwr = self._get_firewall_rule(context, id) + return self._make_firewall_rule_dict(fwr, fields) + + def get_firewall_rules(self, context, filters=None, fields=None): + LOG.debug("get_firewall_rules() called") + return self._get_collection(context, FirewallRuleV2, + self._make_firewall_rule_dict, + filters=filters, fields=fields) + + def _delete_rules_in_policy(self, context, firewall_policy_id): + """Delete the rules in the firewall policy.""" + with context.session.begin(subtransactions=True): + fw_pol_rule_qry = context.session.query( + FirewallPolicyRuleAssociation) + fw_pol_rule_qry.filter_by( + firewall_policy_id=firewall_policy_id).delete() + return + + def _get_rules_in_policy(self, context, fwpid): + """Gets rules in a firewall policy""" + with context.session.begin(subtransactions=True): + fw_pol_rule_qry = context.session.query( + FirewallPolicyRuleAssociation).filter_by( + firewall_policy_id=fwpid) + fwp_rules = [entry.firewall_rule_id for entry in fw_pol_rule_qry] + return fwp_rules + + 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( + FirewallPolicyRuleAssociation).filter_by( + firewall_rule_id=fwrid) + fwps = [entry.firewall_policy_id for entry in fw_pol_rule_qry] + return fwps + + def _set_rules_in_policy_rule_assoc(self, context, fwp_db, fwp): + # Pull the rules and add it to policy - rule association table + # Set the position (this can be used in the making the dict) + # might be good to track the last position + rule_id_list = fwp['firewall_rules'] + if not rule_id_list: + return + position = 0 + with context.session.begin(subtransactions=True): + for rule_id in rule_id_list: + fw_pol_rul_db = FirewallPolicyRuleAssociation( + firewall_policy_id=fwp_db['id'], + firewall_rule_id=rule_id, + position=position) + context.session.add(fw_pol_rul_db) + position += 1 + + def _check_rules_for_policy_is_valid(self, context, fwp, fwp_db, + rule_id_list, filters): + rules_in_fwr_db = self._get_collection_query(context, FirewallRuleV2, + filters=filters) + rules_dict = dict((fwr_db['id'], fwr_db) for fwr_db in rules_in_fwr_db) + for fwrule_id in rule_id_list: + if fwrule_id not in rules_dict: + # Bail as soon as we find an invalid rule. + raise fw_ext.FirewallRuleNotFound( + firewall_rule_id=fwrule_id) + if 'public' in fwp: + if fwp['public'] and not rules_dict[fwrule_id]['public']: + raise fw_ext.FirewallRuleSharingConflict( + firewall_rule_id=fwrule_id, + firewall_policy_id=fwp_db['id']) + elif fwp_db['public'] and not rules_dict[fwrule_id]['public']: + raise fw_ext.FirewallRuleSharingConflict( + firewall_rule_id=fwrule_id, + firewall_policy_id=fwp_db['id']) + else: + # the policy is not public, the rule and policy should be in + # the same project if the rule is not public. + if not rules_dict[fwrule_id]['public']: + if (rules_dict[fwrule_id]['tenant_id'] != + fwp_db['tenant_id']): + raise fw_ext.FirewallRuleConflict( + firewall_rule_id=fwrule_id, + tenant_id=rules_dict[fwrule_id]['tenant_id']) + + def _check_if_rules_public_for_policy_public(self, context, fwp_db, fwp): + if fwp['public']: + rules_in_db = fwp_db['firewall_rules'] + for entry in rules_in_db: + fwr_db = self._get_firewall_rule(context, + entry.firewall_rule_id) + if not fwr_db['public']: + raise fw_ext.FirewallPolicySharingConflict( + firewall_rule_id=fwr_db['id'], + firewall_policy_id=fwp_db['id']) + + def _check_fwgs_associated_with_policy_in_same_project(self, context, + fwp_id, + fwp_tenant_id): + filters = {'ingress_firewall_rule_id': [fwp_id], + 'ingress_firewall_rule_id': [fwp_id]} + with context.session.begin(subtransactions=True): + fwg_with_fwp_id_db = self._get_collection_query( + context, + FirewallGroup, + filters=filters) + for entry in fwg_with_fwp_id_db: + if entry.tenant_id != fwp_tenant_id: + raise fw_ext.FirewallPolicyInUse( + firewall_policy_id=fwp_id) + + def _set_rules_for_policy(self, context, firewall_policy_db, fwp): + rule_id_list = fwp['firewall_rules'] + fwp_db = firewall_policy_db + with context.session.begin(subtransactions=True): + if not rule_id_list: + fwp_db.firewall_rules = [] + return + # We will first check if the new list of rules is valid + filters = {'firewall_rule_id': [r_id for r_id in rule_id_list]} + # Run a validation on the Firewall Rules table + self._check_rules_for_policy_is_valid(context, fwp, fwp_db, + rule_id_list, filters) + # new rules are valid, lets delete the old association + self._delete_rules_in_policy(context, fwp_db['id']) + # and add in the new association + self._set_rules_in_policy_rule_assoc(context, fwp_db, fwp) + rules_in_fpol_rul_db = self._get_collection_query( + context, + FirewallPolicyRuleAssociation, + filters=filters) + rules_dict = dict((fpol_rul_db['firewall_rule_id'], fpol_rul_db) + for fpol_rul_db in rules_in_fpol_rul_db) + fwp_db.firewall_rules = [] + for fwrule_id in rule_id_list: + fwp_db.firewall_rules.append(rules_dict[fwrule_id]) + fwp_db.firewall_rules.reorder() + + def create_firewall_policy(self, context, firewall_policy): + LOG.debug("create_firewall_policy() called") + fwp = firewall_policy['firewall_policy'] + with context.session.begin(subtransactions=True): + fwp_db = FirewallPolicy( + id=uuidutils.generate_uuid(), + tenant_id=fwp['tenant_id'], + name=fwp['name'], + description=fwp['description'], + public=fwp['public'], + audited=fwp['audited']) + context.session.add(fwp_db) + self._set_rules_for_policy(context, fwp_db, fwp) + return self._make_firewall_policy_dict(fwp_db) + + def update_firewall_policy(self, context, id, firewall_policy): + LOG.debug("update_firewall_policy() called") + fwp = firewall_policy['firewall_policy'] + with context.session.begin(subtransactions=True): + fwp_db = self._get_firewall_policy(context, id) + if not fwp.get('public', True): + # an update is setting public to False, make sure associated + # firewall groups are in the same project. + self._check_fwgs_associated_with_policy_in_same_project( + context, id, fwp_db['tenant_id']) + if 'public' in fwp and 'firewall_rules' not in fwp: + self._check_if_rules_public_for_policy_public( + context, fwp_db, fwp) + if 'firewall_rules' in fwp: + self._set_rules_for_policy(context, fwp_db, fwp) + del fwp['firewall_rules'] + if 'audited' not in fwp: + fwp['audited'] = False + fwp_db.update(fwp) + return self._make_firewall_policy_dict(fwp_db) + + def delete_firewall_policy(self, context, id): + LOG.debug("delete_firewall_policy() called") + with context.session.begin(subtransactions=True): + fwp_db = self._get_firewall_policy(context, id) + # check if policy in use + qry = context.session.query(FirewallGroup) + if qry.filter_by(ingress_firewall_policy_id=id).first(): + raise fw_ext.FirewallPolicyInUse(firewall_policy_id=id) + elif qry.filter_by(egress_firewall_policy_id=id).first(): + raise fw_ext.FirewallPolicyInUse(firewall_policy_id=id) + else: + # Policy is not being used, delete. + self._delete_rules_in_policy(context, id) + 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_fwg_parameters(self, context, fwg, fwg_tenant_id): + # On updates, all keys will not be present so check 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['public']: + raise fw_ext.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['public']: + raise fw_ext.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: + return + with context.session.begin(subtransactions=True): + for port_id in port_id_list: + fwg_port_db = FirewallGroupPortAssociation( + firewall_group_id=fwg_db['id'], + port=port_id) + context.session.add(fwg_port_db) + + def _delete_ports_in_firewall_group(self, context, firewall_group_id): + """Delete the Ports associated with the firewall group.""" + with context.session.begin(subtransactions=True): + fw_group_port_qry = context.session.query( + FirewallGroupPortAssociation) + fw_group_port_qry.filter_by( + firewall_group_id=firewall_group_id).delete() + return + + def create_firewall_group(self, context, firewall_group, status=None): + fwg = firewall_group['firewall_group'] + if not status: + status = (p_const.CREATED if cfg.CONF.router_distributed + else p_const.PENDING_CREATE) + with context.session.begin(subtransactions=True): + self._validate_fwg_parameters(context, fwg, fwg['tenant_id']) + fwg_db = FirewallGroup(id=uuidutils.generate_uuid(), + tenant_id=fwg['tenant_id'], + name=fwg['name'], + description=fwg['description'], + public=fwg['public'], + status=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']) + context.session.add(fwg_db) + self._set_ports_for_firewall_group(context, fwg_db, fwg) + return self._make_firewall_group_dict(fwg_db) + + def update_firewall_group(self, context, id, firewall_group): + LOG.debug("update_firewall() called") + fwg = firewall_group['firewall_group'] + with context.session.begin(subtransactions=True): + fwg_db = self.get_firewall_group(context, id) + self._validate_fwg_parameters(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) + self._set_ports_for_firewall_group(context, fwg_db, fwg) + del fwg['ports'] + count = context.session.query( + FirewallGroup).filter_by(id=id).update(fwg) + if not count: + raise fw_ext.FirewallNotFound(firewall_id=id) + return self.get_firewall_group(context, id) + + def delete_firewall_group(self, context, id): + LOG.debug("delete_firewall() called") + with context.session.begin(subtransactions=True): + # Note: Plugin should ensure that it's okay to delete if the + # firewall is active + count = context.session.query( + FirewallGroup).filter_by(id=id).delete() + if not count: + raise fw_ext.FirewallNotFound(firewall_id=id) + + 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") + return self._get_collection(context, FirewallGroup, + self._make_firewall_group_dict, + filters=filters, fields=fields) diff --git a/neutron_fwaas/db/migration/alembic_migrations/versions/d6a12e637e28_neutron_fwaas_v2_0.py b/neutron_fwaas/db/migration/alembic_migrations/versions/d6a12e637e28_neutron_fwaas_v2_0.py new file mode 100644 index 000000000..4dffadfab --- /dev/null +++ b/neutron_fwaas/db/migration/alembic_migrations/versions/d6a12e637e28_neutron_fwaas_v2_0.py @@ -0,0 +1,92 @@ +# Copyright 2016 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""neutron-fwaas v2.0 + +Revision ID: d6a12e637e28 +Revises: kilo +Create Date: 2016-06-08 19:57:13.848855 + +""" + +# revision identifiers, used by Alembic. +revision = 'd6a12e637e28' +down_revision = 'kilo' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + + op.create_table( + 'firewall_policies_v2', + sa.Column('id', sa.String(length=36), primary_key=True), + sa.Column('name', sa.String(length=255)), + sa.Column('description', sa.String(length=1024)), + sa.Column('project_id', sa.String(length=36), index=True), + sa.Column('audited', sa.Boolean), + sa.Column('public', sa.Boolean), + sa.Column('rule_count', sa.Integer)) + + op.create_table( + 'firewall_rules_v2', + sa.Column('id', sa.String(length=36), primary_key=True), + sa.Column('name', sa.String(length=255)), + sa.Column('description', sa.String(length=1024)), + sa.Column('project_id', sa.String(length=36), index=True), + sa.Column('protocol', sa.String(length=40)), + sa.Column('ip_version', sa.Integer, nullable=False), + sa.Column('source_ip_address', sa.String(length=46)), + sa.Column('destination_ip_address', sa.String(length=46)), + sa.Column('source_port_range_min', sa.Integer), + sa.Column('source_port_range_max', sa.Integer), + sa.Column('destination_port_range_min', sa.Integer), + sa.Column('destination_port_range_max', sa.Integer), + sa.Column('action', sa.Enum('allow', 'deny', 'reject', + name='firewallrules_action')), + sa.Column('public', sa.Boolean), + sa.Column('enabled', sa.Boolean)) + + op.create_table( + 'firewall_groups_v2', + sa.Column('id', sa.String(length=36), primary_key=True), + sa.Column('name', sa.String(length=255)), + sa.Column('description', sa.String(length=1024)), + sa.Column('project_id', sa.String(length=36), index=True), + sa.Column('status', sa.String(length=255)), + sa.Column('admin_state_up', sa.Boolean), + sa.Column('public', sa.Boolean), + sa.Column('egress_firewall_policy_id', sa.String(length=36)), + sa.Column('ingress_firewall_policy_id', sa.String(length=36))) + + op.create_table( + 'firewall_group_port_associations_v2', + sa.Column('firewall_group_id', sa.String(length=36), + sa.ForeignKey('firewall_groups_v2.id', ondelete='CASCADE'), + nullable=False, unique=True), + sa.Column('port_id', sa.String(length=36), + sa.ForeignKey('ports.id', ondelete='CASCADE'), + nullable=False, unique=True)) + + op.create_table( + 'firewall_policy_rule_associations_v2', + sa.Column('firewall_policy_id', sa.String(length=36), + sa.ForeignKey('firewall_policies_v2.id', ondelete='CASCADE'), + nullable=False, unique=True, primary_key=True), + sa.Column('firewall_rule_id', sa.String(length=36), + sa.ForeignKey('firewall_rules_v2.id', ondelete='CASCADE'), + nullable=False, unique=True, primary_key=True), + sa.Column('position', sa.Integer)) diff --git a/neutron_fwaas/extensions/firewall.py b/neutron_fwaas/extensions/firewall.py index 62aecf52c..0b38d136a 100644 --- a/neutron_fwaas/extensions/firewall.py +++ b/neutron_fwaas/extensions/firewall.py @@ -237,8 +237,9 @@ def _validate_ip_or_subnet_or_none(data, valid_values=None): 'msg_subnet': msg_subnet} -attr.validators['type:port_range'] = _validate_port_range -attr.validators['type:ip_or_subnet_or_none'] = _validate_ip_or_subnet_or_none +validators.validators['type:port_range'] = _validate_port_range +validators.validators['type:ip_or_subnet_or_none'] = \ + _validate_ip_or_subnet_or_none RESOURCE_ATTRIBUTE_MAP = { diff --git a/neutron_fwaas/tests/unit/db/firewall/v2/__init__.py b/neutron_fwaas/tests/unit/db/firewall/v2/__init__.py new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..2c09c021c --- /dev/null +++ b/neutron_fwaas/tests/unit/db/firewall/v2/test_firewall_db_v2.py @@ -0,0 +1,1225 @@ +# Copyright (c) 2016 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import contextlib + +import mock +from neutron.api import extensions as api_ext +from neutron.common import config +from neutron import context +import neutron.extensions as nextensions +from neutron import manager +from neutron.plugins.common import constants +from oslo_config import cfg +from oslo_utils import importutils +from oslo_utils import uuidutils +import six +import testtools +import webob.exc + +from neutron_fwaas.db.firewall.v2 import firewall_db_v2 as fdb +from neutron_fwaas import extensions +from neutron_fwaas.extensions import firewall_v2 as firewall +from neutron_fwaas.services.firewall import fwaas_plugin +from neutron_fwaas.tests import base + +DB_FW_PLUGIN_KLASS = ( + "neutron_fwaas.db.firewall.v2.firewall_db_v2.Firewall_db_mixin_v2" +) +FWAAS_PLUGIN = 'neutron_fwaas.services.firewall.fwaas_plugin' +DELETEFW_PATH = FWAAS_PLUGIN + '.FirewallAgentApi.delete_firewall' +extensions_path = ':'.join(extensions.__path__ + nextensions.__path__) +DESCRIPTION = 'default description' +PUBLIC = True +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 + + +class FakeAgentApi(fwaas_plugin.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(self, context, firewall, **kwargs): + self.plugin = manager.NeutronManager.get_service_plugins()['FIREWALL'] + self.firewall_deleted(context, firewall['id'], **kwargs) + + +class FirewallPluginV2DbTestCase(base.NeutronDbPluginV2TestCase): + resource_prefix_map = dict( + (k, firewall.FIREWALL_PREFIX) + for k in firewall.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) + 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.FIREWALL_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, + {constants.FIREWALL: self.plugin} + ) + app = config.load_paste_app('extensions_test_app') + self.ext_api = api_ext.ExtensionMiddleware(app, ext_mgr=ext_mgr) + + def _test_list_resources(self, resource, items, + neutron_context=None, + 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 _get_test_firewall_rule_attrs(self, name='firewall_rule1'): + attrs = {'name': name, + 'tenant_id': self._tenant_id, + 'public': PUBLIC, + '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} + return attrs + + def _get_test_firewall_policy_attrs(self, name='firewall_policy1', + audited=AUDITED): + attrs = {'name': name, + 'description': DESCRIPTION, + 'tenant_id': self._tenant_id, + 'public': PUBLIC, + 'firewall_rules': [], + 'audited': audited} + return attrs + + def _get_test_firewall_group_attrs(self, name='firewall_1', + status='PENDING_CREATE'): + attrs = {'name': name, + 'tenant_id': self._tenant_id, + 'admin_state_up': ADMIN_STATE_UP, + 'status': status} + + return attrs + + def _create_firewall_policy(self, fmt, name, description, public, + 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, + 'public': public, + 'firewall_rules': firewall_rules, + 'audited': audited}} + + 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, public=True, + 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, public, + 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, public, 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, + 'public': public, + '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}} + + 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', + public=PUBLIC, 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, public, 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, 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: + res = self._create_firewall_policy(fmt, 'fwp', + description=DESCRIPTION, + public=True, + firewall_rules=[], + tenant_id=tenant_id, + 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}) + + 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, + 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, + 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 test_create_firewall_policy(self): + name = "firewall_policy1" + attrs = self._get_test_firewall_policy_attrs(name) + + with self.firewall_policy(name=name, public=PUBLIC, + firewall_rules=None, + audited=AUDITED) as firewall_policy: + for k, v in six.iteritems(attrs): + self.assertEqual(v, firewall_policy['firewall_policy'][k]) + + def test_create_firewall_policy_with_rules(self): + name = "firewall_policy1" + attrs = self._get_test_firewall_policy_attrs(name) + + with self.firewall_rule(name='fwr1') as fwr1, \ + self.firewall_rule(name='fwr2') as fwr2, \ + self.firewall_rule(name='fwr3') as fwr3: + 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, public=PUBLIC, + firewall_rules=fw_rule_ids, + audited=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(public=False) as fr: + fw_rule_ids = [fr['firewall_rule']['id']] + res = self._create_firewall_policy(None, 'firewall_policy1', + description=DESCRIPTION, + public=PUBLIC, + firewall_rules=fw_rule_ids, + audited=AUDITED, + tenant_id='admin-tenant') + self.assertEqual(webob.exc.HTTPConflict.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(firewall_rules=fw_rule_ids, + public=PUBLIC) as fwp2: + self.assertEqual( + fwr['firewall_rule']['id'], + fwp2['firewall_policy']['firewall_rules'][0]) + + def test_create_public_firewall_policy_with_nonpublic_rule(self): + with self.firewall_rule(public=False) as fwr: + fw_rule_ids = [fwr['firewall_rule']['id']] + res = self._create_firewall_policy( + None, 'firewall_policy1', description=DESCRIPTION, public=True, + firewall_rules=fw_rule_ids, audited=AUDITED) + self.assertEqual(webob.exc.HTTPConflict.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, public=PUBLIC, + firewall_rules=None, + audited=AUDITED) as fwp: + req = self.new_show_request('firewall_policies', + fwp['firewall_policy']['id'], + fmt=self.fmt) + res = self.deserialize(self.fmt, req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_policy'][k]) + + def test_list_firewall_policies(self): + with self.firewall_policy(name='fwp1', description='fwp') as fwp1, \ + self.firewall_policy(name='fwp2', description='fwp') as fwp2, \ + self.firewall_policy(name='fwp3', description='fwp') as fwp3: + fw_policies = [fwp1, fwp2, fwp3] + self._test_list_resources('firewall_policy', + fw_policies, + query_params='description=fwp') + + def test_update_firewall_policy(self): + name = "new_firewall_policy1" + attrs = self._get_test_firewall_policy_attrs(name, audited=False) + + with self.firewall_policy(public=PUBLIC, + firewall_rules=None, + audited=AUDITED) as fwp: + data = {'firewall_policy': {'name': name}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + res = self.deserialize(self.fmt, req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_policy'][k]) + + def _test_update_firewall_policy(self, with_audited): + with self.firewall_policy(name='firewall_policy1', + description='fwp', + audited=AUDITED) as fwp: + attrs = self._get_test_firewall_policy_attrs(audited=with_audited) + data = {'firewall_policy': + {'description': 'fw_p1'}} + if with_audited: + data['firewall_policy']['audited'] = 'True' + + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + attrs['description'] = 'fw_p1' + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_policy'][k]) + + def test_update_firewall_policy_set_audited_false(self): + self._test_update_firewall_policy(with_audited=False) + + def test_update_firewall_policy_with_audited_set_true(self): + self._test_update_firewall_policy(with_audited=True) + + def test_update_firewall_policy_with_rules(self): + attrs = self._get_test_firewall_policy_attrs() + + with self.firewall_rule(name='fwr1') as fwr1, \ + self.firewall_rule(name='fwr2') as fwr2, \ + self.firewall_rule(name='fwr3') as fwr3: + with self.firewall_policy() as fwp: + fr = [fwr1, fwr2, fwr3] + fw_rule_ids = [r['firewall_rule']['id'] for r in fr] + attrs['firewall_rules'] = fw_rule_ids + data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + attrs['audited'] = False + attrs['firewall_rules'] = sorted(attrs['firewall_rules']) + # TODO(sridar): set it so that the ordering is maintained + res['firewall_policy']['firewall_rules'] = sorted( + res['firewall_policy']['firewall_rules']) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_policy'][k]) + + def test_update_firewall_policy_replace_rules(self): + attrs = self._get_test_firewall_policy_attrs() + + with self.firewall_rule(name='fwr1') as fwr1, \ + self.firewall_rule(name='fwr2') as fwr2, \ + self.firewall_rule(name='fwr3') as fwr3, \ + self.firewall_rule(name='fwr4') as fwr4: + frs = [fwr1, fwr2, fwr3, fwr4] + fr1 = frs[0:2] + fr2 = frs[2:4] + with self.firewall_policy() as fwp: + fw_rule_ids = [r['firewall_rule']['id'] for r in fr1] + data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + req.get_response(self.ext_api) + + fw_rule_ids = [r['firewall_rule']['id'] for r in fr2] + attrs['firewall_rules'] = fw_rule_ids + new_data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + req = self.new_update_request('firewall_policies', new_data, + fwp['firewall_policy']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + attrs['audited'] = False + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_policy'][k]) + + @testtools.skip('bug/1614673') + def test_update_firewall_policy_reorder_rules(self): + attrs = self._get_test_firewall_policy_attrs() + + with self.firewall_rule(name='fwr1') as fwr1, \ + self.firewall_rule(name='fwr2') as fwr2, \ + self.firewall_rule(name='fwr3') as fwr3, \ + self.firewall_rule(name='fwr4') as fwr4: + fr = [fwr1, fwr2, fwr3, fwr4] + with self.firewall_policy() as fwp: + fw_rule_ids = [fr[2]['firewall_rule']['id'], + fr[3]['firewall_rule']['id']] + data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + req.get_response(self.ext_api) + # shuffle the rules, add more rules + fw_rule_ids = [fr[1]['firewall_rule']['id'], + fr[3]['firewall_rule']['id'], + fr[2]['firewall_rule']['id'], + fr[0]['firewall_rule']['id']] + attrs['firewall_rules'] = fw_rule_ids + data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + rules = [] + for rule_id in fw_rule_ids: + req = self.new_show_request('firewall_rules', + rule_id, + fmt=self.fmt) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + rules.append(res['firewall_rule']) + self.assertEqual(1, rules[0]['position']) + self.assertEqual(fr[1]['firewall_rule']['id'], rules[0]['id']) + self.assertEqual(2, rules[1]['position']) + self.assertEqual(fr[3]['firewall_rule']['id'], rules[1]['id']) + self.assertEqual(3, rules[2]['position']) + self.assertEqual(fr[2]['firewall_rule']['id'], rules[2]['id']) + self.assertEqual(4, rules[3]['position']) + self.assertEqual(fr[0]['firewall_rule']['id'], rules[3]['id']) + + def test_update_firewall_policy_with_non_existing_rule(self): + attrs = self._get_test_firewall_policy_attrs() + + with self.firewall_rule(name='fwr1') as fwr1, \ + self.firewall_rule(name='fwr2') as fwr2: + fr = [fwr1, fwr2] + with self.firewall_policy() as fwp: + fw_rule_ids = [r['firewall_rule']['id'] for r in fr] + # appending non-existent rule + fw_rule_ids.append(uuidutils.generate_uuid()) + data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + res = req.get_response(self.ext_api) + # check that the firewall_rule was not found + self.assertEqual(404, res.status_int) + # check if none of the rules got added to the policy + req = self.new_show_request('firewall_policies', + fwp['firewall_policy']['id'], + fmt=self.fmt) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_policy'][k]) + + def test_update_public_firewall_policy_with_nonpublic_rule(self): + with self.firewall_rule(name='fwr1', public=False) as fr: + with self.firewall_policy() as fwp: + fw_rule_ids = [fr['firewall_rule']['id']] + # update public policy with nonpublic rule + data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + 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_with_public_attr_nonpublic_rule(self): + with self.firewall_rule(name='fwr1', public=False) as fr: + with self.firewall_policy(public=False) as fwp: + fw_rule_ids = [fr['firewall_rule']['id']] + # update public policy with public attr and nonpublic rule + data = {'firewall_policy': {'public': True, + 'firewall_rules': fw_rule_ids}} + 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_with_public_attr_exist_unshare_rule(self): + with self.firewall_rule(name='fwr1', public=False) as fr: + fw_rule_ids = [fr['firewall_rule']['id']] + with self.firewall_policy(public=False, + firewall_rules=fw_rule_ids) as fwp: + # update policy with public attr + data = {'firewall_policy': {'public': True}} + 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(public=True, 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): + data = {'firewall_policy': {'public': False}} + 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_delete_firewall_policy(self): + ctx = context.get_admin_context() + with self.firewall_policy(do_delete=False) as fwp: + fwp_id = fwp['firewall_policy']['id'] + req = self.new_delete_request('firewall_policies', fwp_id) + res = req.get_response(self.ext_api) + self.assertEqual(204, res.status_int) + self.assertRaises(firewall.FirewallPolicyNotFound, + self.plugin.get_firewall_policy, + ctx, fwp_id) + + @testtools.skip('bug/1614673') + def test_delete_firewall_policy_with_rule(self): + ctx = context.get_admin_context() + attrs = self._get_test_firewall_policy_attrs() + with self.firewall_policy(do_delete=False) as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_rule(name='fwr1') as fr: + fr_id = fr['firewall_rule']['id'] + fw_rule_ids = [fr_id] + attrs['firewall_rules'] = fw_rule_ids + data = {'firewall_policy': + {'firewall_rules': fw_rule_ids}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + req.get_response(self.ext_api) + fw_rule = self.plugin.get_firewall_rule(ctx, fr_id) + self.assertEqual(fwp_id, fw_rule['ingress_firewall_policy_id']) + req = self.new_delete_request('firewall_policies', fwp_id) + res = req.get_response(self.ext_api) + self.assertEqual(204, res.status_int) + self.assertRaises(firewall.FirewallPolicyNotFound, + self.plugin.get_firewall_policy, + ctx, fwp_id) + fw_rule = self.plugin.get_firewall_rule(ctx, fr_id) + 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): + req = self.new_delete_request('firewall_policies', fwp_id) + res = req.get_response(self.ext_api) + self.assertEqual(409, res.status_int) + + def test_create_firewall_rule(self): + attrs = self._get_test_firewall_rule_attrs() + + with self.firewall_rule() as firewall_rule: + for k, v in six.iteritems(attrs): + self.assertEqual(v, firewall_rule['firewall_rule'][k]) + + attrs['source_port'] = None + attrs['destination_port'] = None + with self.firewall_rule(source_port=None, + destination_port=None) as firewall_rule: + for k, v in six.iteritems(attrs): + self.assertEqual(v, firewall_rule['firewall_rule'][k]) + + attrs['source_port'] = '10000' + attrs['destination_port'] = '80' + with self.firewall_rule(source_port=10000, + destination_port=80) as firewall_rule: + for k, v in six.iteritems(attrs): + self.assertEqual(v, firewall_rule['firewall_rule'][k]) + + attrs['source_port'] = '10000' + attrs['destination_port'] = '80' + with self.firewall_rule(source_port='10000', + destination_port='80') as firewall_rule: + for k, v in six.iteritems(attrs): + self.assertEqual(v, firewall_rule['firewall_rule'][k]) + + 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) + + 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) + + 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) + + def test_create_firewall_rule_icmp_without_port(self): + attrs = self._get_test_firewall_rule_attrs() + + attrs['protocol'] = 'icmp' + attrs['source_port'] = None + attrs['destination_port'] = None + with self.firewall_rule(source_port=None, + destination_port=None, + protocol='icmp') as firewall_rule: + for k, v in six.iteritems(attrs): + self.assertEqual(v, firewall_rule['firewall_rule'][k]) + + 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) + + 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) + + 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) + + 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) + + def test_show_firewall_rule_with_fw_policy_not_associated(self): + attrs = self._get_test_firewall_rule_attrs() + with self.firewall_rule() as fw_rule: + req = self.new_show_request('firewall_rules', + fw_rule['firewall_rule']['id'], + fmt=self.fmt) + 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]) + + @testtools.skip('bug/1614673') + def test_show_firewall_rule_with_fw_policy_associated(self): + attrs = self._get_test_firewall_rule_attrs() + with self.firewall_rule() as fw_rule: + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + attrs['ingress_firewall_policy_id'] = fwp_id + data = {'firewall_policy': + {'firewall_rules': + [fw_rule['firewall_rule']['id']]}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + req.get_response(self.ext_api) + req = self.new_show_request('firewall_rules', + fw_rule['firewall_rule']['id'], + fmt=self.fmt) + 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_create_firewall_rule_with_ipv6_addrs_and_wrong_ip_version(self): + attrs = self._get_test_firewall_rule_attrs() + 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 = 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 = 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) + + def test_list_firewall_rules(self): + with self.firewall_rule(name='fwr1') as fwr1, \ + self.firewall_rule(name='fwr2') as fwr2, \ + self.firewall_rule(name='fwr3') as fwr3: + fr = [fwr1, fwr2, fwr3] + query_params = 'protocol=tcp' + self._test_list_resources('firewall_rule', fr, + query_params=query_params) + + def test_update_firewall_rule(self): + name = "new_firewall_rule1" + attrs = self._get_test_firewall_rule_attrs(name) + + attrs['source_port'] = '10:20' + attrs['destination_port'] = '30:40' + with self.firewall_rule() as fwr: + data = {'firewall_rule': {'name': name, + 'source_port': '10:20', + 'destination_port': '30:40'}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_rule'][k]) + + attrs['source_port'] = '10000' + attrs['destination_port'] = '80' + with self.firewall_rule() as fwr: + data = {'firewall_rule': {'name': name, + 'source_port': 10000, + 'destination_port': 80}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_rule'][k]) + + attrs['source_port'] = '10000' + attrs['destination_port'] = '80' + with self.firewall_rule() as fwr: + data = {'firewall_rule': {'name': name, + 'source_port': '10000', + 'destination_port': '80'}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_rule'][k]) + + attrs['source_port'] = None + attrs['destination_port'] = None + with self.firewall_rule() as fwr: + data = {'firewall_rule': {'name': name, + 'source_port': None, + 'destination_port': None}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_rule'][k]) + + def test_update_firewall_rule_with_port_and_no_proto(self): + with self.firewall_rule() as fwr: + data = {'firewall_rule': {'protocol': None, + 'destination_port': 80}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(400, res.status_int) + + def test_update_firewall_rule_without_ports_and_no_proto(self): + with self.firewall_rule() as fwr: + data = {'firewall_rule': {'protocol': None, + 'destination_port': None, + 'source_port': None}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(200, res.status_int) + + def test_update_firewall_rule_with_port(self): + with self.firewall_rule(source_port=None, + destination_port=None, + protocol=None) as fwr: + data = {'firewall_rule': {'destination_port': 80}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(400, res.status_int) + + def test_update_firewall_rule_with_port_illegal_range(self): + with self.firewall_rule() as fwr: + data = {'firewall_rule': {'destination_port': '65535:1024'}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(400, res.status_int) + + def test_update_firewall_rule_with_port_and_protocol(self): + with self.firewall_rule(source_port=None, + destination_port=None, + protocol=None) as fwr: + data = {'firewall_rule': {'destination_port': 80, + 'protocol': 'tcp'}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(200, res.status_int) + + def test_update_firewall_rule_with_policy_associated(self): + name = "new_firewall_rule1" + attrs = self._get_test_firewall_rule_attrs(name) + with self.firewall_rule() as fwr: + with self.firewall_policy() as fwp: + fwr_id = fwr['firewall_rule']['id'] + data = {'firewall_policy': {'firewall_rules': [fwr_id]}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + req.get_response(self.ext_api) + data = {'firewall_rule': {'name': name}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_rule'][k]) + req = self.new_show_request('firewall_policies', + fwp['firewall_policy']['id'], + fmt=self.fmt) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + self.assertEqual( + [fwr_id], + res['firewall_policy']['firewall_rules']) + self.assertFalse(res['firewall_policy']['audited']) + + @testtools.skip('bug/1614680') + def test_update_firewall_rule_associated_with_other_tenant_policy(self): + with self.firewall_rule(public=True, tenant_id='tenant1') as fwr: + fwr_id = [fwr['firewall_rule']['id']] + with self.firewall_policy(public=False, + firewall_rules=fwr_id): + data = {'firewall_rule': {'public': False}} + req = self.new_update_request('firewall_rules', data, + fwr['firewall_rule']['id']) + res = req.get_response(self.ext_api) + self.assertEqual(webob.exc.HTTPConflict.code, res.status_int) + + def test_delete_firewall_rule(self): + ctx = context.get_admin_context() + with self.firewall_rule(do_delete=False) as fwr: + fwr_id = fwr['firewall_rule']['id'] + req = self.new_delete_request('firewall_rules', fwr_id) + res = req.get_response(self.ext_api) + self.assertEqual(204, res.status_int) + self.assertRaises(firewall.FirewallRuleNotFound, + self.plugin.get_firewall_rule, + ctx, fwr_id) + + def test_delete_firewall_rule_with_policy_associated(self): + with self.firewall_rule() as fwr: + with self.firewall_policy() as fwp: + fwr_id = fwr['firewall_rule']['id'] + data = {'firewall_policy': {'firewall_rules': [fwr_id]}} + req = self.new_update_request('firewall_policies', data, + fwp['firewall_policy']['id']) + res = req.get_response(self.ext_api) + req = self.new_delete_request('firewall_rules', fwr_id) + 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 + ) 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) + + 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" + description = "my_firewall1" + not_found_fwp_id = uuidutils.generate_uuid() + self._create_firewall_group(fmt, fwg_name, + description, not_found_fwp_id, + not_found_fwp_id, ADMIN_STATE_UP, + expected_res_status=404) + + def test_create_firewall_group_with_fwp_on_different_tenant(self): + fmt = self.fmt + fwg_name = "firewall1" + description = "my_firewall1" + with self.firewall_policy(public=False, tenant_id='tenant2') as fwp: + fwp_id = fwp['firewall_policy']['id'] + ctx = context.Context('not_admin', 'tenant1') + self._create_firewall_group(fmt, fwg_name, + description, + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, + context=ctx, + expected_res_status=404) + + def test_create_firewall_group_with_admin_and_fwp_different_tenant(self): + fmt = self.fmt + fwg_name = "firewall1" + description = "my_firewall1" + with self.firewall_policy(public=False, tenant_id='tenant2') as fwp: + fwp_id = fwp['firewall_policy']['id'] + ctx = context.get_admin_context() + self._create_firewall_group(fmt, fwg_name, + description, fwp_id, fwp_id, + tenant_id="admin-tenant", + context=ctx, + expected_res_status=409) + + def test_create_firewall_group_with_admin_and_fwp_is_public(self): + fwg_name = "fw_with_public_fwp" + with self.firewall_policy(tenant_id="tenantX") as fwp: + fwp_id = fwp['firewall_policy']['id'] + ctx = context.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: + self.assertEqual(target_tenant, + fwg['firewall_group']['tenant_id']) + + def test_show_firewall_group(self): + name = "firewall1" + attrs = self._get_test_firewall_group_attrs(name) + + 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 + attrs['status'] = 'PENDING_CREATE' + with self.firewall_group( + name=name, + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, + admin_state_up=ADMIN_STATE_UP) as firewall_group: + req = self.new_show_request( + 'firewall_groups', + firewall_group['firewall_group']['id'], + fmt=self.fmt) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_group'][k]) + + def test_list_firewall_groups(self): + with self.firewall_policy() as fwp: + fwp_id = fwp['firewall_policy']['id'] + with self.firewall_group(name='fwg1', tenant_id='tenant1', + ingress_firewall_policy_id=fwp_id, + description='fwg') as fwg1, \ + self.firewall_group(name='fwg2', tenant_id='tenant2', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, + description='fwg') as fwg2, \ + self.firewall_group(name='fwg3', tenant_id='tenant3', + ingress_firewall_policy_id=fwp_id, + egress_firewall_policy_id=fwp_id, + description='fwg') as fwg3: + fwgrps = [fwg1, fwg2, fwg3] + self._test_list_resources('firewall_group', fwgrps, + query_params='description=fwg') + + def test_update_firewall_group(self): + name = "new_firewall1" + attrs = self._get_test_firewall_group_attrs(name) + + 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=ADMIN_STATE_UP) as firewall: + data = {'firewall_group': {'name': name}} + req = self.new_update_request('firewall_groups', data, + firewall['firewall_group']['id']) + res = self.deserialize(self.fmt, + req.get_response(self.ext_api)) + for k, v in six.iteritems(attrs): + self.assertEqual(v, res['firewall_group'][k]) + + def test_update_firewall_group_with_fwp(self): + ctx = context.Context('not_admin', 'tenant1') + with self.firewall_policy( + name='p1', tenant_id='tenant1', public=False) as fwp1, \ + self.firewall_policy( + name='p2', tenant_id='tenant1', public=False) as fwp2, \ + self.firewall_group( + ingress_firewall_policy_id=fwp1['firewall_policy']['id'], + egress_firewall_policy_id=fwp2['firewall_policy']['id'], + context=ctx) as fw: + fw_id = fw['firewall_group']['id'] + fwp2_id = fwp2['firewall_policy']['id'] + data = {'firewall_group': {'ingress_firewall_policy_id': fwp2_id}} + req = self.new_update_request('firewall_groups', data, fw_id, + context=ctx) + res = req.get_response(self.ext_api) + self.assertEqual(200, res.status_int) + + @testtools.skip('bug/1614680') + def test_update_firewall_group_with_public_fwp(self): + ctx = context.Context('not_admin', 'tenant1') + with self.firewall_policy(name='p1', tenant_id='tenant1', public=True) as fwp1, \ + self.firewall_policy(name='p2', tenant_id='tenant2', public=True) as fwp2, \ + self.firewall_group( + ingress_firewall_policy_id=fwp1['firewall_policy']['id'], + egress_firewall_policy_id=fwp1['firewall_policy']['id'], + context=ctx) as fw: + fw_id = fw['firewall_group']['id'] + fwp2_id = fwp2['firewall_policy']['id'] + data = {'firewall_group': {'ingress_firewall_policy_id': fwp2_id}} + req = self.new_update_request('firewall_groups', data, fw_id, + context=ctx) + res = req.get_response(self.ext_api) + self.assertEqual(200, res.status_int) + + def test_update_firewall_group_with_admin_and_fwp_different_tenant(self): + ctx = context.get_admin_context() + with self.firewall_policy() as fwp1, \ + self.firewall_policy( + tenant_id='tenant2', public=False) as fwp2, \ + self.firewall_group( + ingress_firewall_policy_id=fwp1['firewall_policy']['id'], + egress_firewall_policy_id=fwp1['firewall_policy']['id'], + context=ctx) as fw: + fw_id = fw['firewall_group']['id'] + fwp2_id = fwp2['firewall_policy']['id'] + data = {'firewall_group': {'egress_firewall_policy_id': fwp2_id}} + req = self.new_update_request('firewall_groups', data, fw_id, + context=ctx) + res = req.get_response(self.ext_api) + self.assertEqual(409, 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', public=False, + tenant_id='tenant2') as fwp2: + + 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 = context.Context('not_admin', 'tenant1') + 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'] = 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) + res = req.get_response(self.ext_api) + self.assertEqual(404, res.status_int) + + def test_delete_firewall(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, + do_delete=False) as fw: + fw_id = fw['firewall_group']['id'] + req = self.new_delete_request('firewall_groups', fw_id) + res = req.get_response(self.ext_api) + self.assertEqual(204, res.status_int) + self.assertRaises(firewall.FirewallGroupNotFound, + self.plugin.get_firewall_group, + ctx, fw_id) + + def test_show_firewall_rule_by_name(self): + with self.firewall_rule(name='firewall_Rule1') as fw_rule: + res = self._show('firewall_rules', + fw_rule['firewall_rule']['id']) + self.assertEqual('firewall_Rule1', res['firewall_rule']['name']) + + def test_show_firewall_policy_by_name(self): + with self.firewall_policy( + name='firewall_Policy1') as fw_policy: + res = self._show('firewall_policies', + fw_policy['firewall_policy']['id']) + self.assertEqual( + 'firewall_Policy1', res['firewall_policy']['name']) + + def test_show_firewall_group_by_name(self): + with self.firewall_group(name='fireWall1') as fw: + res = self._show('firewall_groups', fw['firewall_group']['id']) + self.assertEqual('fireWall1', res['firewall_group']['name']) diff --git a/tox.ini b/tox.ini index dbfa51cc0..55f9c4e76 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt -whitelist_externals = sh +whitelist_externals = sh find commands = find . -type f -name "*.py[c|o]" -delete find . -type d -name "__pycache__" -delete