FWaaS v2 Database
This change adds database objects for FireWall-as-a-Service v2. This creates a new set of tables to support v2 of FWaaS, and the methods to interact with this data. Co-Authored-By: Sean M. Collins <sean@coreitpro.com> Co-Authored-By: Margaret Frances <margaret_frances@cable.comcast.com> Co-Authored-By: Sridar Kandaswamy <skandasw@cisco.com> Partial-Implements: blueprint fwaas-api-2.0 Depends-On: I4a0cc154f83bbce748d06e25485931fa2bc91f2c Change-Id: Ibc2df1f26407b7482cd58978c11d9a2845972ba2
This commit is contained in:
parent
40a529dfcd
commit
39e4dd9a15
|
@ -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)
|
|
@ -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))
|
|
@ -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 = {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
2
tox.ini
2
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
|
||||
|
|
Loading…
Reference in New Issue