1080 lines
49 KiB
Python
1080 lines
49 KiB
Python
# 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.
|
|
|
|
import copy
|
|
|
|
import netaddr
|
|
|
|
from neutron.db import _model_query as model_query
|
|
from neutron.db import common_db_mixin
|
|
from neutron_lib.api.definitions import constants as fw_const
|
|
from neutron_lib import constants as nl_constants
|
|
from neutron_lib.db import api as db_api
|
|
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_db import exception as db_exc
|
|
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 or_
|
|
from sqlalchemy import orm
|
|
from sqlalchemy.orm import exc
|
|
|
|
from neutron_fwaas.common import fwaas_constants as const
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class FirewallDefaultParameterExists(exceptions.InUse):
|
|
"""Default Firewall Parameter conflict exception
|
|
|
|
Occurs when user creates/updates any existing firewall resource with
|
|
reserved parameter names.
|
|
"""
|
|
message = ("Operation cannot be performed since '%(name)s' "
|
|
"is a reserved name for %(resource_type)s.")
|
|
|
|
|
|
class FirewallDefaultObjectUpdateRestricted(FirewallDefaultParameterExists):
|
|
message = ("Operation cannot be performed on default object "
|
|
"'%(resource_id)s' of type %(resource_type)s.")
|
|
|
|
|
|
class HasName(object):
|
|
name = sa.Column(sa.String(db_constants.NAME_FIELD_SIZE))
|
|
|
|
|
|
class HasDescription(object):
|
|
description = sa.Column(
|
|
sa.String(db_constants.LONG_DESCRIPTION_FIELD_SIZE))
|
|
|
|
|
|
class FirewallRuleV2(model_base.BASEV2, model_base.HasId, HasName,
|
|
HasDescription, model_base.HasProject):
|
|
__tablename__ = "firewall_rules_v2"
|
|
shared = 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, model_base.HasId, HasName,
|
|
HasDescription, model_base.HasProject):
|
|
__tablename__ = 'firewall_groups_v2'
|
|
port_associations = orm.relationship(
|
|
'FirewallGroupPortAssociation',
|
|
backref=orm.backref('firewall_group_port_associations_v2',
|
|
cascade='all, delete'))
|
|
name = sa.Column(sa.String(db_constants.NAME_FIELD_SIZE))
|
|
description = sa.Column(
|
|
sa.String(db_constants.LONG_DESCRIPTION_FIELD_SIZE))
|
|
ingress_firewall_policy_id = sa.Column(
|
|
sa.String(db_constants.UUID_FIELD_SIZE),
|
|
sa.ForeignKey('firewall_policies_v2.id'))
|
|
egress_firewall_policy_id = sa.Column(
|
|
sa.String(db_constants.UUID_FIELD_SIZE),
|
|
sa.ForeignKey('firewall_policies_v2.id'))
|
|
admin_state_up = sa.Column(sa.Boolean)
|
|
status = sa.Column(sa.String(db_constants.STATUS_FIELD_SIZE))
|
|
shared = sa.Column(sa.Boolean)
|
|
|
|
|
|
class DefaultFirewallGroup(model_base.BASEV2, model_base.HasProjectPrimaryKey):
|
|
__tablename__ = "default_firewall_groups"
|
|
firewall_group_id = sa.Column(sa.String(db_constants.UUID_FIELD_SIZE),
|
|
sa.ForeignKey('firewall_groups_v2.id',
|
|
ondelete="CASCADE"),
|
|
nullable=False)
|
|
firewall_group = orm.relationship(
|
|
FirewallGroup, lazy='joined',
|
|
backref=orm.backref('default_firewall_group', cascade='all,delete'),
|
|
primaryjoin="FirewallGroup.id==DefaultFirewallGroup.firewall_group_id",
|
|
)
|
|
|
|
|
|
class FirewallGroupPortAssociation(model_base.BASEV2):
|
|
__tablename__ = 'firewall_group_port_associations_v2'
|
|
firewall_group_id = sa.Column(sa.String(db_constants.UUID_FIELD_SIZE),
|
|
sa.ForeignKey('firewall_groups_v2.id',
|
|
ondelete="CASCADE"),
|
|
primary_key=True)
|
|
port_id = sa.Column(sa.String(db_constants.UUID_FIELD_SIZE),
|
|
sa.ForeignKey('ports.id', ondelete="CASCADE"),
|
|
unique=True,
|
|
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(db_constants.UUID_FIELD_SIZE),
|
|
sa.ForeignKey('firewall_policies_v2.id',
|
|
ondelete="CASCADE"),
|
|
primary_key=True)
|
|
firewall_rule_id = sa.Column(sa.String(db_constants.UUID_FIELD_SIZE),
|
|
sa.ForeignKey('firewall_rules_v2.id',
|
|
ondelete="CASCADE"),
|
|
primary_key=True)
|
|
position = sa.Column(sa.Integer)
|
|
|
|
|
|
class FirewallPolicy(model_base.BASEV2, model_base.HasId, HasName,
|
|
HasDescription, model_base.HasProject):
|
|
__tablename__ = 'firewall_policies_v2'
|
|
name = sa.Column(sa.String(db_constants.NAME_FIELD_SIZE))
|
|
description = sa.Column(
|
|
sa.String(db_constants.LONG_DESCRIPTION_FIELD_SIZE))
|
|
rule_count = sa.Column(sa.Integer)
|
|
audited = sa.Column(sa.Boolean)
|
|
rule_associations = orm.relationship(
|
|
FirewallPolicyRuleAssociation,
|
|
backref=orm.backref('firewall_policies_v2', cascade='all, delete'),
|
|
order_by='FirewallPolicyRuleAssociation.position',
|
|
collection_class=ordering_list('position', count_from=1))
|
|
shared = sa.Column(sa.Boolean)
|
|
|
|
|
|
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:
|
|
return self._get_by_id(context, FirewallGroup, id)
|
|
except exc.NoResultFound:
|
|
raise f_exc.FirewallGroupNotFound(firewall_id=id)
|
|
|
|
def _get_firewall_policy(self, context, id):
|
|
try:
|
|
return self._get_by_id(context, FirewallPolicy, id)
|
|
except exc.NoResultFound:
|
|
raise f_exc.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 f_exc.FirewallRuleNotFound(firewall_rule_id=id)
|
|
|
|
def _validate_fwr_protocol_parameters(self, fwr, fwr_db=None):
|
|
protocol = fwr.get('protocol', None)
|
|
if fwr_db and not protocol:
|
|
protocol = fwr_db.protocol
|
|
if protocol not in (nl_constants.PROTO_NAME_TCP,
|
|
nl_constants.PROTO_NAME_UDP):
|
|
if (fwr.get('source_port', None) or
|
|
fwr.get('destination_port', None)):
|
|
raise f_exc.FirewallRuleInvalidICMPParameter(
|
|
param="Source, destination port")
|
|
|
|
def _validate_fwr_src_dst_ip_version(self, fwr, fwr_db=None):
|
|
src_version = dst_version = None
|
|
if fwr.get('source_ip_address', None):
|
|
src_version = netaddr.IPNetwork(fwr['source_ip_address']).version
|
|
if fwr.get('destination_ip_address', None):
|
|
dst_version = netaddr.IPNetwork(
|
|
fwr['destination_ip_address']).version
|
|
rule_ip_version = fwr.get('ip_version', None)
|
|
if not rule_ip_version and fwr_db:
|
|
rule_ip_version = fwr_db.ip_version
|
|
if ((src_version and src_version != rule_ip_version) or
|
|
(dst_version and dst_version != rule_ip_version)):
|
|
raise f_exc.FirewallIpAddressConflict()
|
|
|
|
def _validate_fwr_port_range(self, min_port, max_port):
|
|
if int(min_port) > int(max_port):
|
|
port_range = '%s:%s' % (min_port, max_port)
|
|
raise f_exc.FirewallRuleInvalidPortValue(port=port_range)
|
|
|
|
def _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,
|
|
policies=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'],
|
|
'protocol': firewall_rule['protocol'],
|
|
'firewall_policy_id': policies,
|
|
'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'],
|
|
'shared': firewall_rule['shared']}
|
|
return self._fields(res, fields)
|
|
|
|
def _make_firewall_policy_dict(self, firewall_policy, fields=None):
|
|
fw_rules = [
|
|
rule_association.firewall_rule_id
|
|
for rule_association in firewall_policy['rule_associations']]
|
|
res = {'id': firewall_policy['id'],
|
|
'tenant_id': firewall_policy['tenant_id'],
|
|
'name': firewall_policy['name'],
|
|
'description': firewall_policy['description'],
|
|
'audited': firewall_policy['audited'],
|
|
'firewall_rules': fw_rules,
|
|
'shared': firewall_policy['shared']}
|
|
return self._fields(res, fields)
|
|
|
|
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_db['ingress_firewall_policy_id'],
|
|
'egress_firewall_policy_id':
|
|
firewall_group_db['egress_firewall_policy_id'],
|
|
'admin_state_up': firewall_group_db['admin_state_up'],
|
|
'ports': fwg_ports,
|
|
'status': firewall_group_db['status'],
|
|
'shared': firewall_group_db['shared']}
|
|
return self._fields(res, fields)
|
|
|
|
def _get_policy_ordered_rules(self, context, policy_id):
|
|
query = (context.session.query(FirewallRuleV2)
|
|
.join(FirewallPolicyRuleAssociation)
|
|
.filter_by(firewall_policy_id=policy_id)
|
|
.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):
|
|
firewall_group = self.get_firewall_group(context, firewall_group_id)
|
|
ingress_policy_id = firewall_group['ingress_firewall_policy_id']
|
|
if ingress_policy_id:
|
|
firewall_group['ingress_rule_list'] = (
|
|
self._get_policy_ordered_rules(context, ingress_policy_id))
|
|
else:
|
|
firewall_group['ingress_rule_list'] = []
|
|
|
|
egress_policy_id = firewall_group['egress_firewall_policy_id']
|
|
if egress_policy_id:
|
|
firewall_group['egress_rule_list'] = (
|
|
self._get_policy_ordered_rules(context, egress_policy_id))
|
|
else:
|
|
firewall_group['egress_rule_list'] = []
|
|
return firewall_group
|
|
|
|
def _check_firewall_rule_conflict(self, fwr_db, fwp_db):
|
|
if not fwr_db['shared']:
|
|
if fwr_db['tenant_id'] != fwp_db['tenant_id']:
|
|
raise f_exc.FirewallRuleConflict(
|
|
firewall_rule_id=fwr_db['id'],
|
|
project_id=fwr_db['tenant_id'])
|
|
|
|
def _process_rule_for_policy(self, context, firewall_policy_id,
|
|
firewall_rule_id, position, association_db):
|
|
with context.session.begin(subtransactions=True):
|
|
fwp_query = context.session.query(
|
|
FirewallPolicy).with_lockmode('update')
|
|
fwp_db = fwp_query.filter_by(id=firewall_policy_id).one()
|
|
if position:
|
|
# Note that although position numbering starts at 1,
|
|
# internal ordering of the list starts at 0, so we compensate.
|
|
fwp_db.rule_associations.insert(
|
|
position - 1,
|
|
FirewallPolicyRuleAssociation(
|
|
firewall_rule_id=firewall_rule_id))
|
|
else:
|
|
fwp_db.rule_associations.remove(association_db)
|
|
context.session.delete(association_db)
|
|
fwp_db.rule_associations.reorder()
|
|
fwp_db.audited = False
|
|
return self._make_firewall_policy_dict(fwp_db)
|
|
|
|
def _get_policy_rule_association_query(self, context, firewall_policy_id,
|
|
firewall_rule_id):
|
|
fwpra_query = context.session.query(FirewallPolicyRuleAssociation)
|
|
return fwpra_query.filter_by(firewall_policy_id=firewall_policy_id,
|
|
firewall_rule_id=firewall_rule_id)
|
|
|
|
def _ensure_rule_not_already_associated(self, context, firewall_policy_id,
|
|
firewall_rule_id):
|
|
"""Checks that a rule is not already associated with a particular
|
|
policy. If it is the function will throw an exception.
|
|
"""
|
|
try:
|
|
self._get_policy_rule_association_query(
|
|
context, firewall_policy_id, firewall_rule_id).one()
|
|
raise f_exc.FirewallRuleAlreadyAssociated(
|
|
firewall_rule_id=firewall_rule_id,
|
|
firewall_policy_id=firewall_policy_id)
|
|
except exc.NoResultFound:
|
|
return
|
|
|
|
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 assocition does not exist.
|
|
"""
|
|
try:
|
|
return self._get_policy_rule_association_query(
|
|
context, firewall_policy_id, firewall_rule_id).one()
|
|
except exc.NoResultFound:
|
|
raise f_exc.FirewallRuleNotAssociatedWithPolicy(
|
|
firewall_rule_id=firewall_rule_id,
|
|
firewall_policy_id=firewall_policy_id)
|
|
|
|
def _create_default_firewall_rules(self, context, tenant_id):
|
|
# NOTE(xgerman) Maybe generating the final set of rules from a
|
|
# configuration file makes sense. Can be done some time later
|
|
|
|
# 1. Drop any IPv4 packets for ingress traffic
|
|
in_fwr_v4 = {
|
|
'description': 'default ingress rule for IPv4',
|
|
'name': 'default ingress ipv4 (deny all)',
|
|
'shared': False,
|
|
'protocol': None,
|
|
'tenant_id': tenant_id,
|
|
'ip_version': nl_constants.IP_VERSION_4,
|
|
'action': fw_const.FWAAS_DENY,
|
|
'enabled': True,
|
|
'source_port': None,
|
|
'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['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['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['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'],
|
|
'in_ipv6': self.create_firewall_rule(context, in_fwr_v6)['id'],
|
|
'eg_ipv4': self.create_firewall_rule(context, eg_fwr_v4)['id'],
|
|
'eg_ipv6': self.create_firewall_rule(context, eg_fwr_v6)['id'],
|
|
}
|
|
|
|
def create_firewall_rule(self, context, 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
|
|
fwr['destination_port']):
|
|
raise f_exc.FirewallRuleWithPortWithoutProtocolInvalid()
|
|
src_port_min, src_port_max = self._get_min_max_ports_from_range(
|
|
fwr['source_port'])
|
|
dst_port_min, dst_port_max = self._get_min_max_ports_from_range(
|
|
fwr['destination_port'])
|
|
with context.session.begin(subtransactions=True):
|
|
fwr_db = FirewallRuleV2(
|
|
id=uuidutils.generate_uuid(),
|
|
tenant_id=fwr['tenant_id'],
|
|
name=fwr['name'],
|
|
description=fwr['description'],
|
|
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'],
|
|
shared=fwr['shared'])
|
|
context.session.add(fwr_db)
|
|
return self._make_firewall_rule_dict(fwr_db)
|
|
|
|
def update_firewall_rule(self, context, id, 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)
|
|
if 'source_port' in fwr:
|
|
src_port_min, src_port_max = self._get_min_max_ports_from_range(
|
|
fwr['source_port'])
|
|
fwr['source_port_range_min'] = src_port_min
|
|
fwr['source_port_range_max'] = src_port_max
|
|
del fwr['source_port']
|
|
if 'destination_port' in fwr:
|
|
dst_port_min, dst_port_max = self._get_min_max_ports_from_range(
|
|
fwr['destination_port'])
|
|
fwr['destination_port_range_min'] = dst_port_min
|
|
fwr['destination_port_range_max'] = dst_port_max
|
|
del fwr['destination_port']
|
|
with context.session.begin(subtransactions=True):
|
|
protocol = fwr.get('protocol', fwr_db['protocol'])
|
|
if not protocol:
|
|
sport = fwr.get('source_port_range_min',
|
|
fwr_db['source_port_range_min'])
|
|
dport = fwr.get('destination_port_range_min',
|
|
fwr_db['destination_port_range_min'])
|
|
if sport or dport:
|
|
raise f_exc.FirewallRuleWithPortWithoutProtocolInvalid()
|
|
fwr_db.update(fwr)
|
|
# if 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):
|
|
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 f_exc.FirewallRuleInUse(firewall_rule_id=id)
|
|
context.session.delete(fwr)
|
|
|
|
def insert_rule(self, context, id, 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)
|
|
insert_before = True
|
|
ref_firewall_rule_id = None
|
|
if 'insert_before' in rule_info:
|
|
ref_firewall_rule_id = rule_info['insert_before']
|
|
if not ref_firewall_rule_id and 'insert_after' in rule_info:
|
|
# If insert_before is set, we will ignore insert_after.
|
|
ref_firewall_rule_id = rule_info['insert_after']
|
|
insert_before = False
|
|
with context.session.begin(subtransactions=True):
|
|
fwr_db = self._get_firewall_rule(context, firewall_rule_id)
|
|
fwp_db = self._get_firewall_policy(context, id)
|
|
self._check_firewall_rule_conflict(fwr_db, fwp_db)
|
|
if ref_firewall_rule_id:
|
|
# If reference_firewall_rule_id is set, the new rule
|
|
# is inserted depending on the value of insert_before.
|
|
# If insert_before is set, the new rule is inserted before
|
|
# reference_firewall_rule_id, and if it is not set the new
|
|
# rule is inserted after reference_firewall_rule_id.
|
|
fwpra_db = self._get_policy_rule_association(
|
|
context, id, ref_firewall_rule_id)
|
|
if insert_before:
|
|
position = fwpra_db.position
|
|
else:
|
|
position = fwpra_db.position + 1
|
|
else:
|
|
# If reference_firewall_rule_id is not set, it is assumed
|
|
# that the new rule needs to be inserted at the top.
|
|
# insert_before field is ignored.
|
|
# So default insertion is always at the top.
|
|
# Also note that position numbering starts at 1.
|
|
position = 1
|
|
return self._process_rule_for_policy(context, id, firewall_rule_id,
|
|
position, None)
|
|
|
|
def remove_rule(self, context, id, rule_info):
|
|
firewall_rule_id = rule_info['firewall_rule_id']
|
|
with context.session.begin(subtransactions=True):
|
|
self._get_firewall_rule(context, firewall_rule_id)
|
|
fwpra_db = self._get_policy_rule_association(context, id,
|
|
firewall_rule_id)
|
|
return self._process_rule_for_policy(context, id, firewall_rule_id,
|
|
None, fwpra_db)
|
|
|
|
def get_firewall_rule(self, context, id, fields=None):
|
|
fwr = self._get_firewall_rule(context, id)
|
|
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):
|
|
return self._get_collection(context, FirewallRuleV2,
|
|
self._make_firewall_rule_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
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 f_exc.FirewallRuleNotFound(
|
|
firewall_rule_id=fwrule_id)
|
|
if 'shared' in fwp:
|
|
if fwp['shared'] and not rules_dict[fwrule_id]['shared']:
|
|
raise f_exc.FirewallRuleSharingConflict(
|
|
firewall_rule_id=fwrule_id,
|
|
firewall_policy_id=fwp_db['id'])
|
|
elif fwp_db['shared'] and not rules_dict[fwrule_id]['shared']:
|
|
raise f_exc.FirewallRuleSharingConflict(
|
|
firewall_rule_id=fwrule_id,
|
|
firewall_policy_id=fwp_db['id'])
|
|
else:
|
|
# the policy is not shared, the rule and policy should be in
|
|
# the same project if the rule is not shared.
|
|
if not rules_dict[fwrule_id]['shared']:
|
|
if (rules_dict[fwrule_id]['tenant_id'] != fwp_db[
|
|
'tenant_id']):
|
|
raise f_exc.FirewallRuleConflict(
|
|
firewall_rule_id=fwrule_id,
|
|
project_id=rules_dict[fwrule_id]['tenant_id'])
|
|
|
|
def _check_if_rules_shared_for_policy_shared(self, context, fwp_db, fwp):
|
|
if fwp['shared']:
|
|
rules_in_db = fwp_db.rule_associations
|
|
for entry in rules_in_db:
|
|
fwr_db = self._get_firewall_rule(context,
|
|
entry.firewall_rule_id)
|
|
if not fwp_db['shared']:
|
|
raise f_exc.FirewallPolicySharingConflict(
|
|
firewall_rule_id=fwr_db['id'],
|
|
firewall_policy_id=fwp_db['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(
|
|
ingress_firewall_policy_id=fwp_id)
|
|
ing_fwg_ids = [entry.id for entry in fwg_ing_pol_qry]
|
|
fwg_eg_pol_qry = context.session.query(
|
|
FirewallGroup).filter_by(
|
|
egress_firewall_policy_id=fwp_id)
|
|
eg_fwg_ids = [entry.id for entry in fwg_eg_pol_qry]
|
|
return ing_fwg_ids, eg_fwg_ids
|
|
|
|
def _check_fwgs_associated_with_policy_in_same_project(self, context,
|
|
fwp_id,
|
|
fwp_tenant_id):
|
|
with context.session.begin(subtransactions=True):
|
|
fwg_with_fwp_id_db = context.session.query(FirewallGroup).filter(
|
|
or_(FirewallGroup.ingress_firewall_policy_id == fwp_id,
|
|
FirewallGroup.egress_firewall_policy_id == fwp_id))
|
|
for entry in fwg_with_fwp_id_db:
|
|
if entry.tenant_id != fwp_tenant_id:
|
|
raise f_exc.FirewallPolicyInUse(
|
|
firewall_policy_id=fwp_id)
|
|
|
|
def _delete_all_rules_from_policy(self, context, fwp_db):
|
|
"""Deletes all FirewallPolicyRuleAssociation objects
|
|
|
|
fwp_db is an DB dict representing firewall policy.
|
|
Returns a dictionary with updated rule_associations.
|
|
"""
|
|
for rule_id in [rule_assoc.firewall_rule_id
|
|
for rule_assoc in fwp_db['rule_associations']]:
|
|
fwpra_db = self._get_policy_rule_association(
|
|
context, fwp_db['id'], rule_id)
|
|
fwp_db.rule_associations.remove(fwpra_db)
|
|
context.session.delete(fwpra_db)
|
|
fwp_db.rule_associations = []
|
|
return fwp_db
|
|
|
|
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:
|
|
self._delete_all_rules_from_policy(context, fwp_db)
|
|
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_all_rules_from_policy(context, fwp_db)
|
|
# and add in the new association
|
|
self._set_rules_in_policy_rule_assoc(context, fwp_db, fwp)
|
|
# we need care about the associations related with this policy
|
|
# and its rules only.
|
|
filters['firewall_policy_id'] = [fwp_db['id']]
|
|
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.rule_associations = []
|
|
for fwrule_id in rule_id_list:
|
|
fwp_db.rule_associations.append(rules_dict[fwrule_id])
|
|
fwp_db.rule_associations.reorder()
|
|
|
|
def _create_default_firewall_policy(self, context, tenant_id, policy_type,
|
|
**kwargs):
|
|
fwrs = kwargs.get('firewall_rules', [])
|
|
description = kwargs.get('description', '')
|
|
name = (const.DEFAULT_FWP_INGRESS
|
|
if policy_type == 'ingress' else const.DEFAULT_FWP_EGRESS)
|
|
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
|
|
with context.session.begin(subtransactions=True):
|
|
fwp_db = FirewallPolicy(
|
|
id=uuidutils.generate_uuid(),
|
|
tenant_id=fwp['tenant_id'],
|
|
name=fwp['name'],
|
|
description=fwp['description'],
|
|
audited=fwp['audited'],
|
|
shared=fwp['shared'])
|
|
context.session.add(fwp_db)
|
|
self._set_rules_for_policy(context, fwp_db, fwp)
|
|
return self._make_firewall_policy_dict(fwp_db)
|
|
|
|
def create_firewall_policy(self, context, firewall_policy):
|
|
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):
|
|
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',
|
|
action="update")
|
|
if not fwp.get('shared', True):
|
|
# an update is setting shared 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 'shared' in fwp and 'firewall_rules' not in fwp:
|
|
self._check_if_rules_shared_for_policy_shared(
|
|
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):
|
|
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 f_exc.FirewallPolicyInUse(firewall_policy_id=id)
|
|
elif qry.filter_by(egress_firewall_policy_id=id).first():
|
|
raise f_exc.FirewallPolicyInUse(firewall_policy_id=id)
|
|
else:
|
|
fwp_db = self._delete_all_rules_from_policy(context, fwp_db)
|
|
context.session.delete(fwp_db)
|
|
|
|
def get_firewall_policy(self, context, id, fields=None):
|
|
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):
|
|
return self._get_collection(context, FirewallPolicy,
|
|
self._make_firewall_policy_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
def _set_ports_for_firewall_group(self, context, fwg_db, fwg):
|
|
port_id_list = fwg['ports']
|
|
if not port_id_list:
|
|
return
|
|
|
|
exc_ports = []
|
|
for port_id in port_id_list:
|
|
try:
|
|
with context.session.begin(subtransactions=True):
|
|
fwg_port_db = FirewallGroupPortAssociation(
|
|
firewall_group_id=fwg_db['id'],
|
|
port_id=port_id)
|
|
context.session.add(fwg_port_db)
|
|
except db_exc.DBDuplicateEntry:
|
|
exc_ports.append(port_id)
|
|
if exc_ports:
|
|
raise f_exc.FirewallGroupPortInUse(port_ids=exc_ports)
|
|
|
|
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(
|
|
FirewallGroupPortAssociation)
|
|
fw_group_port_rows = fw_group_port_qry.filter_by(
|
|
firewall_group_id=firewall_group_id)
|
|
fw_ports = [entry.port_id for entry in fw_group_port_rows]
|
|
return fw_ports
|
|
|
|
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 _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 get_fwg_attached_to_port(self, context, port_id):
|
|
"""Return a firewall group ID that is attached to a given port"""
|
|
fwg_port = self._model_query(context, FirewallGroupPortAssociation).\
|
|
filter_by(port_id=port_id).first()
|
|
if fwg_port:
|
|
return fwg_port.firewall_group_id
|
|
return None
|
|
|
|
def get_fwg_ports_in_tenant(self, context, tenant_id):
|
|
"""Return a list of ports under a given tenant"""
|
|
try:
|
|
fwg_id = FirewallGroupPortAssociation.firewall_group_id
|
|
with context.session.begin(subtransactions=True):
|
|
port_qry = context.session.query(
|
|
FirewallGroupPortAssociation.port_id).join(
|
|
FirewallGroup, FirewallGroup.id == fwg_id).filter(
|
|
FirewallGroup.tenant_id == tenant_id).all()
|
|
return list({port for (port,) in port_qry})
|
|
except exc.NoResultFound:
|
|
return []
|
|
|
|
def _ensure_default_firewall_group(self, context, tenant_id):
|
|
"""Create a default firewall group if one doesn't exist for a tenant
|
|
|
|
Returns the default firewall group id for a given tenant.
|
|
"""
|
|
exists = self._get_default_fwg_id(context, tenant_id)
|
|
if exists:
|
|
return exists
|
|
|
|
try:
|
|
# NOTE(cby): default fwg not created => we try to create it!
|
|
with db_api.autonested_transaction(context.session):
|
|
|
|
fwr_ids = self._create_default_firewall_rules(
|
|
context, tenant_id)
|
|
ingress_fwp = {
|
|
'description': 'Ingress firewall policy',
|
|
'firewall_rules': [fwr_ids['in_ipv4'],
|
|
fwr_ids['in_ipv6']],
|
|
}
|
|
egress_fwp = {
|
|
'description': 'Egress firewall policy',
|
|
'firewall_rules': [fwr_ids['eg_ipv4'],
|
|
fwr_ids['eg_ipv6']],
|
|
}
|
|
ingress_fwp_db = self._create_default_firewall_policy(
|
|
context, tenant_id, 'ingress', **ingress_fwp)
|
|
egress_fwp_db = self._create_default_firewall_policy(
|
|
context, tenant_id, 'egress', **egress_fwp)
|
|
|
|
fwg = {
|
|
'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, default_fwg=True)
|
|
context.session.add(DefaultFirewallGroup(
|
|
firewall_group_id=fwg_db['id'],
|
|
project_id=tenant_id))
|
|
return fwg_db['id']
|
|
|
|
except db_exc.DBDuplicateEntry:
|
|
# NOTE(cby): default fwg created concurrently
|
|
LOG.debug("Default FWG was concurrently created")
|
|
return self._get_default_fwg_id(context, tenant_id)
|
|
|
|
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
|
|
tenant_id = fwg['tenant_id']
|
|
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(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)
|
|
|
|
with context.session.begin(subtransactions=True):
|
|
fwg_db = FirewallGroup(
|
|
id=uuidutils.generate_uuid(),
|
|
tenant_id=tenant_id,
|
|
name=fwg['name'],
|
|
description=fwg['description'],
|
|
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'],
|
|
shared=fwg['shared'])
|
|
context.session.add(fwg_db)
|
|
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):
|
|
self._ensure_not_default_resource(firewall_group, 'firewall_group')
|
|
return self._create_firewall_group(context, firewall_group)
|
|
|
|
def update_firewall_group(self, context, id, firewall_group):
|
|
fwg = firewall_group
|
|
# make sure that no group can be updated to have name=default
|
|
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):
|
|
attrs = [
|
|
'name', 'description', 'admin_state_up',
|
|
'ingress_firewall_policy_id', 'egress_firewall_policy_id'
|
|
]
|
|
if context.is_admin:
|
|
attrs = ['name']
|
|
for attr in attrs:
|
|
if attr in fwg:
|
|
raise FirewallDefaultObjectUpdateRestricted(
|
|
resource_type='Firewall Group',
|
|
resource_id=fwg_db['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']
|
|
# If fwg is empty, skip updating
|
|
if fwg:
|
|
count = context.session.query(
|
|
FirewallGroup).filter_by(id=id).update(fwg)
|
|
if not count:
|
|
raise f_exc.FirewallGroupNotFound(firewall_id=id)
|
|
return self.get_firewall_group(context, id)
|
|
|
|
def update_firewall_group_status(self, context, id, status, not_in=None):
|
|
"""Conditionally update firewall_group status.
|
|
Status transition is performed only if firewall is not in the specified
|
|
states as defined by 'not_in' list.
|
|
"""
|
|
# filter in_ wants iterable objects, None isn't.
|
|
not_in = not_in or []
|
|
with context.session.begin(subtransactions=True):
|
|
return (context.session.query(FirewallGroup).
|
|
filter(FirewallGroup.id == id).
|
|
filter(~FirewallGroup.status.in_(not_in)).
|
|
update({'status': status}, synchronize_session=False))
|
|
|
|
def delete_firewall_group(self, context, id):
|
|
# Note: Plugin should ensure that it's okay to delete if the
|
|
# firewall is active
|
|
|
|
with context.session.begin(subtransactions=True):
|
|
# if no such group exists -> don't raise an exception according to
|
|
# 80fe2ba1, return None
|
|
try:
|
|
fwg_db = self._get_firewall_group(context, id)
|
|
except f_exc.FirewallGroupNotFound:
|
|
return
|
|
|
|
if _is_default(fwg_db):
|
|
if context.is_admin:
|
|
# Like Rules in Default SG, when the Default FWG is deleted
|
|
# its associated Rules and policies would also be deleted.
|
|
# Delete fwg first and then associated policies
|
|
context.session.query(
|
|
FirewallGroup).filter_by(id=id).delete()
|
|
fwp = [fwg_db['ingress_firewall_policy_id'],
|
|
fwg_db['egress_firewall_policy_id']]
|
|
for fwp_id in fwp:
|
|
self.delete_firewall_policy(context, fwp_id)
|
|
else:
|
|
# only admin can delete default fwg
|
|
raise f_exc.FirewallGroupCannotRemoveDefault()
|
|
else:
|
|
context.session.query(
|
|
FirewallGroup).filter_by(id=id).delete()
|
|
|
|
def _ensure_not_default_resource(self, resource_dict, r_type, action=None):
|
|
"""Checks that a resource is not default by checking its name
|
|
|
|
A resource_dict can be either a dictionary in form {r_type : {}} or a
|
|
serialized object from db.
|
|
|
|
Action is used to determine type of exception to be raised.
|
|
"""
|
|
resource = resource_dict.get(r_type) or resource_dict
|
|
if r_type == 'firewall_group':
|
|
if resource.get('name', '') == const.DEFAULT_FWG:
|
|
if action == "update":
|
|
raise FirewallDefaultObjectUpdateRestricted(
|
|
resource_type='Firewall Group',
|
|
resource_id=resource['id'])
|
|
raise FirewallDefaultParameterExists(
|
|
resource_type='Firewall Group', name=resource['name'])
|
|
elif r_type == 'firewall_policy':
|
|
if resource.get('name', '') in [const.DEFAULT_FWP_INGRESS,
|
|
const.DEFAULT_FWP_EGRESS]:
|
|
if action == "update":
|
|
raise FirewallDefaultObjectUpdateRestricted(
|
|
resource_type='Firewall Group',
|
|
resource_id=resource['id'])
|
|
raise FirewallDefaultParameterExists(
|
|
resource_type='Firewall Policy', name=resource['name'])
|
|
|
|
def get_firewall_group(self, context, id, fields=None):
|
|
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):
|
|
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
|
|
self._ensure_default_firewall_group(context, tenant_id)
|
|
return self._get_collection(context, FirewallGroup,
|
|
self._make_firewall_group_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
|
|
def _is_default(fwg_db):
|
|
return fwg_db['name'] == const.DEFAULT_FWG
|