Merge "Firewall as a Service (FWaaS) APIs and DB Model"
This commit is contained in:
commit
d82bcb8c6b
@ -58,6 +58,26 @@
|
|||||||
"create_router:external_gateway_info:enable_snat": "rule:admin_only",
|
"create_router:external_gateway_info:enable_snat": "rule:admin_only",
|
||||||
"update_router:external_gateway_info:enable_snat": "rule:admin_only",
|
"update_router:external_gateway_info:enable_snat": "rule:admin_only",
|
||||||
|
|
||||||
|
"create_firewall": "",
|
||||||
|
"get_firewall": "rule:admin_or_owner",
|
||||||
|
"create_firewall:shared": "rule:admin_only",
|
||||||
|
"get_firewall:shared": "rule:admin_only",
|
||||||
|
"update_firewall": "rule:admin_or_owner",
|
||||||
|
"delete_firewall": "rule:admin_or_owner",
|
||||||
|
|
||||||
|
"create_firewall_policy": "",
|
||||||
|
"get_firewall_policy": "rule:admin_or_owner",
|
||||||
|
"create_firewall_policy:shared": "rule:admin_or_owner",
|
||||||
|
"update_firewall_policy": "rule:admin_or_owner",
|
||||||
|
"delete_firewall_policy": "rule:admin_or_owner",
|
||||||
|
|
||||||
|
"create_firewall_rule": "",
|
||||||
|
"get_firewall_rule": "rule:admin_or_owner",
|
||||||
|
"create_firewall_rule:shared": "rule:admin_or_owner",
|
||||||
|
"get_firewall_rule:shared": "rule:admin_or_owner",
|
||||||
|
"update_firewall_rule": "rule:admin_or_owner",
|
||||||
|
"delete_firewall_rule": "rule:admin_or_owner",
|
||||||
|
|
||||||
"create_qos_queue": "rule:admin_only",
|
"create_qos_queue": "rule:admin_only",
|
||||||
"get_qos_queue": "rule:admin_only",
|
"get_qos_queue": "rule:admin_only",
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ UPDATE = 'update'
|
|||||||
AGENT = 'q-agent-notifier'
|
AGENT = 'q-agent-notifier'
|
||||||
PLUGIN = 'q-plugin'
|
PLUGIN = 'q-plugin'
|
||||||
DHCP = 'q-dhcp-notifer'
|
DHCP = 'q-dhcp-notifer'
|
||||||
|
FIREWALL_PLUGIN = 'q-firewall-plugin'
|
||||||
|
|
||||||
L3_AGENT = 'l3_agent'
|
L3_AGENT = 'l3_agent'
|
||||||
DHCP_AGENT = 'dhcp_agent'
|
DHCP_AGENT = 'dhcp_agent'
|
||||||
|
16
neutron/db/firewall/__init__.py
Normal file
16
neutron/db/firewall/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 OpenStack Foundation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
470
neutron/db/firewall/firewall_db.py
Normal file
470
neutron/db/firewall/firewall_db.py
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 Big Switch Networks, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.ext.orderinglist import ordering_list
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from sqlalchemy.orm import exc
|
||||||
|
|
||||||
|
from neutron.db import db_base_plugin_v2 as base_db
|
||||||
|
from neutron.db import model_base
|
||||||
|
from neutron.db import models_v2
|
||||||
|
from neutron.extensions import firewall
|
||||||
|
from neutron import manager
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.openstack.common import uuidutils
|
||||||
|
from neutron.plugins.common import constants as const
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallRule(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
||||||
|
"""Represents a Firewall rule."""
|
||||||
|
__tablename__ = 'firewall_rules'
|
||||||
|
name = sa.Column(sa.String(255))
|
||||||
|
description = sa.Column(sa.String(1024))
|
||||||
|
firewall_policy_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('firewall_policies.id'),
|
||||||
|
nullable=True)
|
||||||
|
shared = sa.Column(sa.Boolean)
|
||||||
|
protocol = sa.Column(sa.String(40))
|
||||||
|
ip_version = sa.Column(sa.Integer, nullable=False)
|
||||||
|
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', name='firewallrules_action'))
|
||||||
|
enabled = sa.Column(sa.Boolean)
|
||||||
|
position = sa.Column(sa.Integer)
|
||||||
|
|
||||||
|
|
||||||
|
class Firewall(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
||||||
|
"""Represents a Firewall resource."""
|
||||||
|
__tablename__ = 'firewalls'
|
||||||
|
name = sa.Column(sa.String(255))
|
||||||
|
description = sa.Column(sa.String(1024))
|
||||||
|
shared = sa.Column(sa.Boolean)
|
||||||
|
admin_state_up = sa.Column(sa.Boolean)
|
||||||
|
status = sa.Column(sa.String(16))
|
||||||
|
firewall_policy_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('firewall_policies.id'),
|
||||||
|
nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallPolicy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
||||||
|
"""Represents a Firewall Policy resource."""
|
||||||
|
__tablename__ = 'firewall_policies'
|
||||||
|
name = sa.Column(sa.String(255))
|
||||||
|
description = sa.Column(sa.String(1024))
|
||||||
|
shared = sa.Column(sa.Boolean)
|
||||||
|
firewall_rules = orm.relationship(
|
||||||
|
FirewallRule,
|
||||||
|
backref=orm.backref('firewall_policies', cascade='all, delete'),
|
||||||
|
order_by='FirewallRule.position',
|
||||||
|
collection_class=ordering_list('position', count_from=1))
|
||||||
|
audited = sa.Column(sa.Boolean)
|
||||||
|
firewalls = orm.relationship(Firewall, backref='firewall_policies')
|
||||||
|
|
||||||
|
|
||||||
|
class Firewall_db_mixin(firewall.FirewallPluginBase, base_db.CommonDbMixin):
|
||||||
|
"""Mixin class for Firewall DB implementation."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _core_plugin(self):
|
||||||
|
return manager.NeutronManager.get_plugin()
|
||||||
|
|
||||||
|
def _get_firewall(self, context, id):
|
||||||
|
try:
|
||||||
|
return self._get_by_id(context, Firewall, id)
|
||||||
|
except exc.NoResultFound:
|
||||||
|
raise firewall.FirewallNotFound(firewall_id=id)
|
||||||
|
|
||||||
|
def _get_firewall_policy(self, context, id):
|
||||||
|
try:
|
||||||
|
return self._get_by_id(context, FirewallPolicy, id)
|
||||||
|
except exc.NoResultFound:
|
||||||
|
raise firewall.FirewallPolicyNotFound(firewall_policy_id=id)
|
||||||
|
|
||||||
|
def _get_firewall_rule(self, context, id):
|
||||||
|
try:
|
||||||
|
return self._get_by_id(context, FirewallRule, id)
|
||||||
|
except exc.NoResultFound:
|
||||||
|
raise firewall.FirewallRuleNotFound(firewall_rule_id=id)
|
||||||
|
|
||||||
|
def _make_firewall_dict(self, fw, fields=None):
|
||||||
|
res = {'id': fw['id'],
|
||||||
|
'tenant_id': fw['tenant_id'],
|
||||||
|
'name': fw['name'],
|
||||||
|
'description': fw['description'],
|
||||||
|
'shared': fw['shared'],
|
||||||
|
'admin_state_up': fw['admin_state_up'],
|
||||||
|
'status': fw['status'],
|
||||||
|
'firewall_policy_id': fw['firewall_policy_id']}
|
||||||
|
return self._fields(res, fields)
|
||||||
|
|
||||||
|
def _make_firewall_policy_dict(self, firewall_policy, fields=None):
|
||||||
|
fw_rules = [rule['id'] for rule in firewall_policy['firewall_rules']]
|
||||||
|
firewalls = [fw['id'] for fw in firewall_policy['firewalls']]
|
||||||
|
res = {'id': firewall_policy['id'],
|
||||||
|
'tenant_id': firewall_policy['tenant_id'],
|
||||||
|
'name': firewall_policy['name'],
|
||||||
|
'description': firewall_policy['description'],
|
||||||
|
'shared': firewall_policy['shared'],
|
||||||
|
'audited': firewall_policy['audited'],
|
||||||
|
'firewall_rules': fw_rules,
|
||||||
|
'firewall_list': firewalls}
|
||||||
|
return self._fields(res, fields)
|
||||||
|
|
||||||
|
def _make_firewall_rule_dict(self, firewall_rule, fields=None):
|
||||||
|
position = None
|
||||||
|
# We return the position only if the firewall_rule is bound to a
|
||||||
|
# firewall_policy.
|
||||||
|
if firewall_rule['firewall_policy_id']:
|
||||||
|
position = firewall_rule['position']
|
||||||
|
src_port_range = self._get_port_range_from_min_max_ports(
|
||||||
|
firewall_rule['source_port_range_min'],
|
||||||
|
firewall_rule['source_port_range_max'])
|
||||||
|
dst_port_range = self._get_port_range_from_min_max_ports(
|
||||||
|
firewall_rule['destination_port_range_min'],
|
||||||
|
firewall_rule['destination_port_range_max'])
|
||||||
|
res = {'id': firewall_rule['id'],
|
||||||
|
'tenant_id': firewall_rule['tenant_id'],
|
||||||
|
'name': firewall_rule['name'],
|
||||||
|
'description': firewall_rule['description'],
|
||||||
|
'firewall_policy_id': firewall_rule['firewall_policy_id'],
|
||||||
|
'shared': firewall_rule['shared'],
|
||||||
|
'protocol': firewall_rule['protocol'],
|
||||||
|
'ip_version': firewall_rule['ip_version'],
|
||||||
|
'source_ip_address': firewall_rule['source_ip_address'],
|
||||||
|
'destination_ip_address':
|
||||||
|
firewall_rule['destination_ip_address'],
|
||||||
|
'source_port': src_port_range,
|
||||||
|
'destination_port': dst_port_range,
|
||||||
|
'action': firewall_rule['action'],
|
||||||
|
'position': position,
|
||||||
|
'enabled': firewall_rule['enabled']}
|
||||||
|
return self._fields(res, fields)
|
||||||
|
|
||||||
|
def _set_rules_for_policy(self, context, firewall_policy_db, rule_id_list):
|
||||||
|
fwp_db = firewall_policy_db
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
if not rule_id_list:
|
||||||
|
fwp_db.firewall_rules = []
|
||||||
|
fwp_db.audited = False
|
||||||
|
return
|
||||||
|
# We will first check if the new list of rules is valid
|
||||||
|
filters = {'id': [r_id for r_id in rule_id_list]}
|
||||||
|
rules_in_db = self._get_collection_query(context, FirewallRule,
|
||||||
|
filters=filters)
|
||||||
|
rules_dict = dict((fwr_db['id'], fwr_db) for fwr_db in rules_in_db)
|
||||||
|
for fwrule_id in rule_id_list:
|
||||||
|
if fwrule_id not in rules_dict:
|
||||||
|
# If we find an invalid rule in the list we
|
||||||
|
# do not perform the update since this breaks
|
||||||
|
# the integrity of this list.
|
||||||
|
raise firewall.FirewallRuleNotFound(firewall_rule_id=
|
||||||
|
fwrule_id)
|
||||||
|
# New list of rules is valid so we will first reset the existing
|
||||||
|
# list and then add each rule in order.
|
||||||
|
# Note that the list could be empty in which case we interpret
|
||||||
|
# it as clearing existing rules.
|
||||||
|
fwp_db.firewall_rules = []
|
||||||
|
for fwrule_id in rule_id_list:
|
||||||
|
fwp_db.firewall_rules.append(rules_dict[fwrule_id])
|
||||||
|
fwp_db.audited = False
|
||||||
|
|
||||||
|
def _process_rule_for_policy(self, context, firewall_policy_id,
|
||||||
|
firewall_rule_db, position):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwp_query = context.session.query(
|
||||||
|
FirewallPolicy).with_lockmode('update')
|
||||||
|
fwp_db = fwp_query.filter_by(id=firewall_policy_id).one()
|
||||||
|
if position:
|
||||||
|
# Note that although position numbering starts at 1,
|
||||||
|
# internal ordering of the list starts at 0, so we compensate.
|
||||||
|
fwp_db.firewall_rules.insert(position - 1, firewall_rule_db)
|
||||||
|
else:
|
||||||
|
fwp_db.firewall_rules.remove(firewall_rule_db)
|
||||||
|
fwp_db.firewall_rules.reorder()
|
||||||
|
fwp_db.audited = False
|
||||||
|
return self._make_firewall_policy_dict(fwp_db)
|
||||||
|
|
||||||
|
def _get_min_max_ports_from_range(self, port_range):
|
||||||
|
if not port_range:
|
||||||
|
return [None, None]
|
||||||
|
ports = port_range.split(':')
|
||||||
|
ports[0] = int(ports[0])
|
||||||
|
if len(ports) < 2:
|
||||||
|
ports.append(ports[0])
|
||||||
|
else:
|
||||||
|
ports[1] = int(ports[1])
|
||||||
|
return ports
|
||||||
|
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
return str(min_port) + ':' + str(max_port)
|
||||||
|
|
||||||
|
def create_firewall(self, context, firewall):
|
||||||
|
LOG.debug(_("create_firewall() called"))
|
||||||
|
fw = firewall['firewall']
|
||||||
|
tenant_id = self._get_tenant_id_for_create(context, fw)
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
firewall_db = Firewall(id=uuidutils.generate_uuid(),
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
name=fw['name'],
|
||||||
|
description=fw['description'],
|
||||||
|
firewall_policy_id=
|
||||||
|
fw['firewall_policy_id'],
|
||||||
|
admin_state_up=fw['admin_state_up'],
|
||||||
|
status=const.PENDING_CREATE)
|
||||||
|
context.session.add(firewall_db)
|
||||||
|
return self._make_firewall_dict(firewall_db)
|
||||||
|
|
||||||
|
def update_firewall(self, context, id, firewall):
|
||||||
|
LOG.debug(_("update_firewall() called"))
|
||||||
|
fw = firewall['firewall']
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fw_query = context.session.query(
|
||||||
|
Firewall).with_lockmode('update')
|
||||||
|
firewall_db = fw_query.filter_by(id=id).one()
|
||||||
|
firewall_db.update(fw)
|
||||||
|
return self._make_firewall_dict(firewall_db)
|
||||||
|
|
||||||
|
def delete_firewall(self, context, id):
|
||||||
|
LOG.debug(_("delete_firewall() called"))
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fw_query = context.session.query(
|
||||||
|
Firewall).with_lockmode('update')
|
||||||
|
firewall_db = fw_query.filter_by(id=id).one()
|
||||||
|
# Note: Plugin should ensure that it's okay to delete if the
|
||||||
|
# firewall is active
|
||||||
|
context.session.delete(firewall_db)
|
||||||
|
|
||||||
|
def get_firewall(self, context, id, fields=None):
|
||||||
|
LOG.debug(_("get_firewall() called"))
|
||||||
|
fw = self._get_firewall(context, id)
|
||||||
|
return self._make_firewall_dict(fw, fields)
|
||||||
|
|
||||||
|
def get_firewalls(self, context, filters=None, fields=None):
|
||||||
|
LOG.debug(_("get_firewalls() called"))
|
||||||
|
return self._get_collection(context, Firewall,
|
||||||
|
self._make_firewall_dict,
|
||||||
|
filters=filters, fields=fields)
|
||||||
|
|
||||||
|
def get_firewalls_count(self, context, filters=None):
|
||||||
|
LOG.debug(_("get_firewalls_count() called"))
|
||||||
|
return self._get_collection_count(context, Firewall,
|
||||||
|
filters=filters)
|
||||||
|
|
||||||
|
def create_firewall_policy(self, context, firewall_policy):
|
||||||
|
LOG.debug(_("create_firewall_policy() called"))
|
||||||
|
fwp = firewall_policy['firewall_policy']
|
||||||
|
tenant_id = self._get_tenant_id_for_create(context, fwp)
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwp_db = FirewallPolicy(id=uuidutils.generate_uuid(),
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
name=fwp['name'],
|
||||||
|
description=fwp['description'],
|
||||||
|
shared=fwp['shared'])
|
||||||
|
context.session.add(fwp_db)
|
||||||
|
self._set_rules_for_policy(context, fwp_db,
|
||||||
|
fwp['firewall_rules'])
|
||||||
|
fwp_db.audited = fwp['audited']
|
||||||
|
return self._make_firewall_policy_dict(fwp_db)
|
||||||
|
|
||||||
|
def update_firewall_policy(self, context, id, firewall_policy):
|
||||||
|
LOG.debug(_("update_firewall_policy() called"))
|
||||||
|
fwp = firewall_policy['firewall_policy']
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwp_db = self._get_firewall_policy(context, id)
|
||||||
|
if 'firewall_rules' in fwp:
|
||||||
|
self._set_rules_for_policy(context, fwp_db,
|
||||||
|
fwp['firewall_rules'])
|
||||||
|
del fwp['firewall_rules']
|
||||||
|
fwp_db.update(fwp)
|
||||||
|
return self._make_firewall_policy_dict(fwp_db)
|
||||||
|
|
||||||
|
def delete_firewall_policy(self, context, id):
|
||||||
|
LOG.debug(_("delete_firewall_policy() called"))
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwp = self._get_firewall_policy(context, id)
|
||||||
|
# Ensure that the firewall_policy is not
|
||||||
|
# being used
|
||||||
|
qry = context.session.query(Firewall)
|
||||||
|
if qry.filter_by(firewall_policy_id=id).first():
|
||||||
|
raise firewall.FirewallPolicyInUse(firewall_policy_id=id)
|
||||||
|
else:
|
||||||
|
context.session.delete(fwp)
|
||||||
|
|
||||||
|
def get_firewall_policy(self, context, id, fields=None):
|
||||||
|
LOG.debug(_("get_firewall_policy() called"))
|
||||||
|
fwp = self._get_firewall_policy(context, id)
|
||||||
|
return self._make_firewall_policy_dict(fwp, fields)
|
||||||
|
|
||||||
|
def get_firewall_policies(self, context, filters=None, fields=None):
|
||||||
|
LOG.debug(_("get_firewall_policies() called"))
|
||||||
|
return self._get_collection(context, FirewallPolicy,
|
||||||
|
self._make_firewall_policy_dict,
|
||||||
|
filters=filters, fields=fields)
|
||||||
|
|
||||||
|
def get_firewalls_policies_count(self, context, filters=None):
|
||||||
|
LOG.debug(_("get_firewall_policies_count() called"))
|
||||||
|
return self._get_collection_count(context, FirewallPolicy,
|
||||||
|
filters=filters)
|
||||||
|
|
||||||
|
def create_firewall_rule(self, context, firewall_rule):
|
||||||
|
LOG.debug(_("create_firewall_rule() called"))
|
||||||
|
fwr = firewall_rule['firewall_rule']
|
||||||
|
tenant_id = self._get_tenant_id_for_create(context, fwr)
|
||||||
|
src_port_min, src_port_max = self._get_min_max_ports_from_range(
|
||||||
|
fwr['source_port'])
|
||||||
|
dst_port_min, dst_port_max = self._get_min_max_ports_from_range(
|
||||||
|
fwr['destination_port'])
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwr_db = FirewallRule(id=uuidutils.generate_uuid(),
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
name=fwr['name'],
|
||||||
|
description=fwr['description'],
|
||||||
|
shared=fwr['shared'],
|
||||||
|
protocol=fwr['protocol'],
|
||||||
|
ip_version=fwr['ip_version'],
|
||||||
|
source_ip_address=fwr['source_ip_address'],
|
||||||
|
destination_ip_address=
|
||||||
|
fwr['destination_ip_address'],
|
||||||
|
source_port_range_min=src_port_min,
|
||||||
|
source_port_range_max=src_port_max,
|
||||||
|
destination_port_range_min=dst_port_min,
|
||||||
|
destination_port_range_max=dst_port_max,
|
||||||
|
action=fwr['action'],
|
||||||
|
enabled=fwr['enabled'])
|
||||||
|
context.session.add(fwr_db)
|
||||||
|
return self._make_firewall_rule_dict(fwr_db)
|
||||||
|
|
||||||
|
def update_firewall_rule(self, context, id, firewall_rule):
|
||||||
|
LOG.debug(_("update_firewall_rule() called"))
|
||||||
|
fwr = firewall_rule['firewall_rule']
|
||||||
|
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):
|
||||||
|
fwr_db = self._get_firewall_rule(context, id)
|
||||||
|
fwr_db.update(fwr)
|
||||||
|
if fwr_db.firewall_policy_id:
|
||||||
|
fwp_db = self._get_firewall_policy(context,
|
||||||
|
fwr_db.firewall_policy_id)
|
||||||
|
fwp_db.audited = False
|
||||||
|
return self._make_firewall_rule_dict(fwr_db)
|
||||||
|
|
||||||
|
def delete_firewall_rule(self, context, id):
|
||||||
|
LOG.debug(_("delete_firewall_rule() called"))
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwr = self._get_firewall_rule(context, id)
|
||||||
|
if fwr.firewall_policy_id:
|
||||||
|
raise firewall.FirewallRuleInUse(firewall_rule_id=id)
|
||||||
|
context.session.delete(fwr)
|
||||||
|
|
||||||
|
def get_firewall_rule(self, context, id, fields=None):
|
||||||
|
LOG.debug(_("get_firewall_rule() called"))
|
||||||
|
fwr = self._get_firewall_rule(context, id)
|
||||||
|
return self._make_firewall_rule_dict(fwr, fields)
|
||||||
|
|
||||||
|
def get_firewall_rules(self, context, filters=None, fields=None):
|
||||||
|
LOG.debug(_("get_firewall_rules() called"))
|
||||||
|
return self._get_collection(context, FirewallRule,
|
||||||
|
self._make_firewall_rule_dict,
|
||||||
|
filters=filters, fields=fields)
|
||||||
|
|
||||||
|
def get_firewalls_rules_count(self, context, filters=None):
|
||||||
|
LOG.debug(_("get_firewall_rules_count() called"))
|
||||||
|
return self._get_collection_count(context, FirewallRule,
|
||||||
|
filters=filters)
|
||||||
|
|
||||||
|
def _validate_insert_remove_rule_request(self, id, rule_info):
|
||||||
|
if not rule_info or 'firewall_rule_id' not in rule_info:
|
||||||
|
raise firewall.FirewallRuleInfoMissing()
|
||||||
|
|
||||||
|
def insert_rule(self, context, id, rule_info):
|
||||||
|
LOG.debug(_("insert_rule() called"))
|
||||||
|
self._validate_insert_remove_rule_request(id, rule_info)
|
||||||
|
firewall_rule_id = rule_info['firewall_rule_id']
|
||||||
|
insert_before = True
|
||||||
|
ref_firewall_rule_id = None
|
||||||
|
if not firewall_rule_id:
|
||||||
|
raise firewall.FirewallRuleNotFound(firewall_rule_id=None)
|
||||||
|
if 'insert_before' in rule_info:
|
||||||
|
ref_firewall_rule_id = rule_info['insert_before']
|
||||||
|
if not ref_firewall_rule_id and 'insert_after' in rule_info:
|
||||||
|
# If insert_before is set, we will ignore insert_after.
|
||||||
|
ref_firewall_rule_id = rule_info['insert_after']
|
||||||
|
insert_before = False
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwr_db = self._get_firewall_rule(context, firewall_rule_id)
|
||||||
|
if fwr_db.firewall_policy_id:
|
||||||
|
raise firewall.FirewallRuleInUse(firewall_rule_id=fwr_db['id'])
|
||||||
|
if ref_firewall_rule_id:
|
||||||
|
# If reference_firewall_rule_id is set, the new rule
|
||||||
|
# is inserted depending on the value of insert_before.
|
||||||
|
# If insert_before is set, the new rule is inserted before
|
||||||
|
# reference_firewall_rule_id, and if it is not set the new
|
||||||
|
# rule is inserted after reference_firewall_rule_id.
|
||||||
|
ref_fwr_db = self._get_firewall_rule(
|
||||||
|
context, ref_firewall_rule_id)
|
||||||
|
if insert_before:
|
||||||
|
position = ref_fwr_db.position
|
||||||
|
else:
|
||||||
|
position = ref_fwr_db.position + 1
|
||||||
|
else:
|
||||||
|
# If reference_firewall_rule_id is not set, it is assumed
|
||||||
|
# that the new rule needs to be inserted at the top.
|
||||||
|
# insert_before field is ignored.
|
||||||
|
# So default insertion is always at the top.
|
||||||
|
# Also note that position numbering starts at 1.
|
||||||
|
position = 1
|
||||||
|
return self._process_rule_for_policy(context, id, fwr_db,
|
||||||
|
position)
|
||||||
|
|
||||||
|
def remove_rule(self, context, id, rule_info):
|
||||||
|
LOG.debug(_("remove_rule() called"))
|
||||||
|
self._validate_insert_remove_rule_request(id, rule_info)
|
||||||
|
firewall_rule_id = rule_info['firewall_rule_id']
|
||||||
|
if not firewall_rule_id:
|
||||||
|
raise firewall.FirewallRuleNotFound(firewall_rule_id=None)
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fwr_db = self._get_firewall_rule(context, firewall_rule_id)
|
||||||
|
if fwr_db.firewall_policy_id != id:
|
||||||
|
raise firewall.FirewallRuleNotAssociatedWithPolicy(
|
||||||
|
firewall_rule_id=fwr_db['id'],
|
||||||
|
firewall_policy_id=id)
|
||||||
|
return self._process_rule_for_policy(context, id, fwr_db, None)
|
@ -0,0 +1,105 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""FWaaS Havana-2 model
|
||||||
|
|
||||||
|
Revision ID: 39cf3f799352
|
||||||
|
Revises: e6b16a30d97
|
||||||
|
Create Date: 2013-07-10 16:16:51.302943
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '39cf3f799352'
|
||||||
|
down_revision = 'e6b16a30d97'
|
||||||
|
|
||||||
|
# Change to ['*'] if this migration applies to all plugins
|
||||||
|
|
||||||
|
migration_for_plugins = ['*']
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from neutron.db import migration
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(active_plugin=None, options=None):
|
||||||
|
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.drop_table('firewall_rules')
|
||||||
|
op.drop_table('firewalls')
|
||||||
|
op.drop_table('firewall_policies')
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(active_plugin=None, options=None):
|
||||||
|
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'firewall_policies',
|
||||||
|
sa.Column('tenant_id', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('id', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('description', sa.String(length=1024), nullable=True),
|
||||||
|
sa.Column('shared', sa.Boolean(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('audited', sa.Boolean(), autoincrement=False,
|
||||||
|
nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id'))
|
||||||
|
op.create_table(
|
||||||
|
'firewalls', sa.Column('tenant_id', sa.String(length=255),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('description', sa.String(length=1024), nullable=True),
|
||||||
|
sa.Column('shared', sa.Boolean(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('admin_state_up', sa.Boolean(), autoincrement=False,
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('status', sa.String(length=16), nullable=True),
|
||||||
|
sa.Column('firewall_policy_id', sa.String(length=36), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['firewall_policy_id'],
|
||||||
|
['firewall_policies.id'],
|
||||||
|
name='firewalls_ibfk_1'),
|
||||||
|
sa.PrimaryKeyConstraint('id'))
|
||||||
|
op.create_table(
|
||||||
|
'firewall_rules',
|
||||||
|
sa.Column('tenant_id', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('id', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('description', sa.String(length=1024), nullable=True),
|
||||||
|
sa.Column('firewall_policy_id', sa.String(length=36), nullable=True),
|
||||||
|
sa.Column('shared', sa.Boolean(), autoincrement=False,
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('protocol', sa.String(length=24), nullable=True),
|
||||||
|
sa.Column('ip_version', sa.Integer(), autoincrement=False,
|
||||||
|
nullable=False),
|
||||||
|
sa.Column('source_ip_address', sa.String(length=46), nullable=True),
|
||||||
|
sa.Column('destination_ip_address', sa.String(length=46),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('source_port_range_min', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('source_port_range_max', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('destination_port_range_min', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('destination_port_range_max', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('action', sa.Enum(), nullable=True),
|
||||||
|
sa.Column('enabled', sa.Boolean(), autoincrement=False,
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('position', sa.Integer(), autoincrement=False,
|
||||||
|
nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['firewall_policy_id'],
|
||||||
|
['firewall_policies.id'],
|
||||||
|
name='firewall_rules_ibfk_1'),
|
||||||
|
sa.PrimaryKeyConstraint('id'))
|
448
neutron/extensions/firewall.py
Normal file
448
neutron/extensions/firewall.py
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 Big Switch Networks, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron.api import extensions
|
||||||
|
from neutron.api.v2 import attributes as attr
|
||||||
|
from neutron.api.v2 import base
|
||||||
|
from neutron.common import exceptions as qexception
|
||||||
|
from neutron import manager
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.plugins.common import constants
|
||||||
|
from neutron.services.service_base import ServicePluginBase
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# Firewall Exceptions
|
||||||
|
class FirewallNotFound(qexception.NotFound):
|
||||||
|
message = _("Firewall %(firewall_id)s could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallInUse(qexception.InUse):
|
||||||
|
message = _("Firewall %(firewall_id)s is still active.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallInPendingState(qexception.Conflict):
|
||||||
|
message = _("Operation cannot be performed since associated Firewall "
|
||||||
|
"%(firewall_id)s is in %(pending_state)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallPolicyNotFound(qexception.NotFound):
|
||||||
|
message = _("Firewall Policy %(firewall_policy_id)s could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallPolicyInUse(qexception.InUse):
|
||||||
|
message = _("Firewall Policy %(firewall_policy_id)s is being used.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallRuleNotFound(qexception.NotFound):
|
||||||
|
message = _("Firewall Rule %(firewall_rule_id)s could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallRuleInUse(qexception.InUse):
|
||||||
|
message = _("Firewall Rule %(firewall_rule_id)s is being used.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallRuleNotAssociatedWithPolicy(qexception.InvalidInput):
|
||||||
|
message = _("Firewall Rule %(firewall_rule_id)s is not associated "
|
||||||
|
" with Firewall Policy %(firewall_policy_id)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallRuleInvalidProtocol(qexception.InvalidInput):
|
||||||
|
message = _("Firewall Rule protocol %(protocol)s is not supported. "
|
||||||
|
"Only protocol values %(values)s and their integer "
|
||||||
|
"representation (0 to 255) are supported.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallRuleInvalidAction(qexception.InvalidInput):
|
||||||
|
message = _("Firewall rule action %(action)s is not supported. "
|
||||||
|
"Only action values %(values)s are supported.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallInvalidPortValue(qexception.InvalidInput):
|
||||||
|
message = _("Invalid value for port %(port)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallRuleInfoMissing(qexception.InvalidInput):
|
||||||
|
message = _("Missing rule info argument for insert/remove "
|
||||||
|
"rule opertaion.")
|
||||||
|
|
||||||
|
|
||||||
|
fw_valid_protocol_values = [None, constants.TCP, constants.UDP, constants.ICMP]
|
||||||
|
fw_valid_action_values = [constants.FWAAS_ALLOW, constants.FWAAS_DENY]
|
||||||
|
|
||||||
|
|
||||||
|
def convert_protocol(value):
|
||||||
|
if value is None:
|
||||||
|
return
|
||||||
|
if value.isdigit():
|
||||||
|
val = int(value)
|
||||||
|
if 0 <= val <= 255:
|
||||||
|
return val
|
||||||
|
else:
|
||||||
|
raise FirewallRuleInvalidProtocol(protocol=value,
|
||||||
|
values=
|
||||||
|
fw_valid_protocol_values)
|
||||||
|
elif value.lower() in fw_valid_protocol_values:
|
||||||
|
return value.lower()
|
||||||
|
else:
|
||||||
|
raise FirewallRuleInvalidProtocol(protocol=value,
|
||||||
|
values=
|
||||||
|
fw_valid_protocol_values)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_action_to_case_insensitive(value):
|
||||||
|
if value is None:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
return value.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def convert_port_to_string(value):
|
||||||
|
if value is None:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_port_range(data, key_specs=None):
|
||||||
|
if data is None:
|
||||||
|
return
|
||||||
|
data = str(data)
|
||||||
|
ports = data.split(':')
|
||||||
|
for p in ports:
|
||||||
|
try:
|
||||||
|
val = int(p)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
msg = _("Port '%s' is not a valid number") % p
|
||||||
|
LOG.debug(msg)
|
||||||
|
return msg
|
||||||
|
if val <= 0 or val > 65535:
|
||||||
|
msg = _("Invalid port '%s'") % p
|
||||||
|
LOG.debug(msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_ip_or_subnet_or_none(data, valid_values=None):
|
||||||
|
if data is None:
|
||||||
|
return None
|
||||||
|
msg_ip = attr._validate_ip_address(data, valid_values)
|
||||||
|
if not msg_ip:
|
||||||
|
return
|
||||||
|
msg_subnet = attr._validate_subnet(data, valid_values)
|
||||||
|
if not msg_subnet:
|
||||||
|
return
|
||||||
|
return _("%(msg_ip)s and %(msg_subnet)s") % {'msg_ip': msg_ip,
|
||||||
|
'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
|
||||||
|
|
||||||
|
|
||||||
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
|
'firewall_rules': {
|
||||||
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
|
'validate': {'type:uuid': None},
|
||||||
|
'is_visible': True, 'primary_key': True},
|
||||||
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||||
|
'required_by_policy': True,
|
||||||
|
'is_visible': True},
|
||||||
|
'name': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True, 'default': ''},
|
||||||
|
'description': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True, 'default': ''},
|
||||||
|
'firewall_policy_id': {'allow_post': False, 'allow_put': False,
|
||||||
|
'validate': {'type:uuid_or_none': None},
|
||||||
|
'is_visible': True},
|
||||||
|
'shared': {'allow_post': True, 'allow_put': True,
|
||||||
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||||
|
'is_visible': True, 'required_by_policy': True,
|
||||||
|
'enforce_policy': True},
|
||||||
|
'protocol': {'allow_post': True, 'allow_put': True,
|
||||||
|
'is_visible': True, 'default': None,
|
||||||
|
'convert_to': convert_protocol,
|
||||||
|
'validate': {'type:values': fw_valid_protocol_values}},
|
||||||
|
'ip_version': {'allow_post': True, 'allow_put': True,
|
||||||
|
'default': 4, 'convert_to': attr.convert_to_int,
|
||||||
|
'validate': {'type:values': [4, 6]},
|
||||||
|
'is_visible': True},
|
||||||
|
'source_ip_address': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:ip_or_subnet_or_none': None},
|
||||||
|
'is_visible': True, 'default': None},
|
||||||
|
'destination_ip_address': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:ip_or_subnet_or_none':
|
||||||
|
None},
|
||||||
|
'is_visible': True, 'default': None},
|
||||||
|
'source_port': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:port_range': None},
|
||||||
|
'convert_to': convert_port_to_string,
|
||||||
|
'default': None, 'is_visible': True},
|
||||||
|
'destination_port': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:port_range': None},
|
||||||
|
'convert_to': convert_port_to_string,
|
||||||
|
'default': None, 'is_visible': True},
|
||||||
|
'position': {'allow_post': False, 'allow_put': False,
|
||||||
|
'default': None, 'is_visible': True},
|
||||||
|
'action': {'allow_post': True, 'allow_put': True,
|
||||||
|
'convert_to': convert_action_to_case_insensitive,
|
||||||
|
'validate': {'type:values': fw_valid_action_values},
|
||||||
|
'is_visible': True, 'default': 'deny'},
|
||||||
|
'enabled': {'allow_post': True, 'allow_put': True,
|
||||||
|
'default': True, 'convert_to': attr.convert_to_boolean,
|
||||||
|
'is_visible': True},
|
||||||
|
},
|
||||||
|
'firewall_policies': {
|
||||||
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
|
'validate': {'type:uuid': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'primary_key': True},
|
||||||
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||||
|
'required_by_policy': True,
|
||||||
|
'is_visible': True},
|
||||||
|
'name': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True, 'default': ''},
|
||||||
|
'description': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True, 'default': ''},
|
||||||
|
'shared': {'allow_post': True, 'allow_put': True,
|
||||||
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||||
|
'is_visible': True, 'required_by_policy': True,
|
||||||
|
'enforce_policy': True},
|
||||||
|
'firewall_rules': {'allow_post': True, 'allow_put': True,
|
||||||
|
'convert_to': attr.convert_none_to_empty_list,
|
||||||
|
'default': None, 'is_visible': True},
|
||||||
|
'audited': {'allow_post': True, 'allow_put': True,
|
||||||
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||||
|
'is_visible': True},
|
||||||
|
},
|
||||||
|
'firewalls': {
|
||||||
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
|
'validate': {'type:uuid': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'primary_key': True},
|
||||||
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||||
|
'required_by_policy': True,
|
||||||
|
'is_visible': True},
|
||||||
|
'name': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True, 'default': ''},
|
||||||
|
'description': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True, 'default': ''},
|
||||||
|
'admin_state_up': {'allow_post': True, 'allow_put': True,
|
||||||
|
'default': True,
|
||||||
|
'convert_to': attr.convert_to_boolean,
|
||||||
|
'is_visible': True},
|
||||||
|
'status': {'allow_post': False, 'allow_put': False,
|
||||||
|
'is_visible': True},
|
||||||
|
'shared': {'allow_post': True, 'allow_put': True,
|
||||||
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||||
|
'is_visible': False, 'required_by_policy': True,
|
||||||
|
'enforce_policy': True},
|
||||||
|
'firewall_policy_id': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:uuid_or_none': None},
|
||||||
|
'is_visible': True},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
firewall_quota_opts = [
|
||||||
|
cfg.IntOpt('quota_firewall',
|
||||||
|
default=1,
|
||||||
|
help=_('Number of firewalls allowed per tenant, -1 for '
|
||||||
|
'unlimited')),
|
||||||
|
cfg.IntOpt('quota_firewall_policy',
|
||||||
|
default=1,
|
||||||
|
help=_('Number of firewall policies allowed per tenant, -1 '
|
||||||
|
'for unlimited')),
|
||||||
|
cfg.IntOpt('quota_firewall_rule',
|
||||||
|
default=-1,
|
||||||
|
help=_('Number of firewall rules allowed per tenant, -1 '
|
||||||
|
'for unlimited')),
|
||||||
|
]
|
||||||
|
cfg.CONF.register_opts(firewall_quota_opts, 'QUOTAS')
|
||||||
|
|
||||||
|
|
||||||
|
class Firewall(extensions.ExtensionDescriptor):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_name(cls):
|
||||||
|
return "Firewall service"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_alias(cls):
|
||||||
|
return "fwaas"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_description(cls):
|
||||||
|
return "Extension for Firewall service"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_namespace(cls):
|
||||||
|
return "http://wiki.openstack.org/Neutron/FWaaS/API_1.0"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return "2013-02-25T10:00:00-00:00"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_resources(cls):
|
||||||
|
my_plurals = []
|
||||||
|
for plural in RESOURCE_ATTRIBUTE_MAP:
|
||||||
|
if plural == 'firewall_policies':
|
||||||
|
singular = 'firewall_policy'
|
||||||
|
else:
|
||||||
|
singular = plural[:-1]
|
||||||
|
my_plurals.append((plural, singular))
|
||||||
|
attr.PLURALS.update(dict(my_plurals))
|
||||||
|
resources = []
|
||||||
|
plugin = manager.NeutronManager.get_service_plugins()[
|
||||||
|
constants.FIREWALL]
|
||||||
|
for collection_name in RESOURCE_ATTRIBUTE_MAP:
|
||||||
|
# Special handling needed for resources with 'y' ending
|
||||||
|
if collection_name == 'firewall_policies':
|
||||||
|
resource_name = 'firewall_policy'
|
||||||
|
else:
|
||||||
|
resource_name = collection_name[:-1]
|
||||||
|
|
||||||
|
params = RESOURCE_ATTRIBUTE_MAP[collection_name]
|
||||||
|
|
||||||
|
member_actions = {}
|
||||||
|
if resource_name == 'firewall_policy':
|
||||||
|
member_actions = {'insert_rule': 'PUT',
|
||||||
|
'remove_rule': 'PUT'}
|
||||||
|
|
||||||
|
controller = base.create_resource(
|
||||||
|
collection_name, resource_name, plugin, params,
|
||||||
|
member_actions=member_actions,
|
||||||
|
allow_pagination=cfg.CONF.allow_pagination,
|
||||||
|
allow_sorting=cfg.CONF.allow_sorting)
|
||||||
|
|
||||||
|
resource = extensions.ResourceExtension(
|
||||||
|
collection_name,
|
||||||
|
controller,
|
||||||
|
path_prefix=constants.COMMON_PREFIXES[constants.FIREWALL],
|
||||||
|
member_actions=member_actions,
|
||||||
|
attr_map=params)
|
||||||
|
resources.append(resource)
|
||||||
|
|
||||||
|
return resources
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_plugin_interface(cls):
|
||||||
|
return FirewallPluginBase
|
||||||
|
|
||||||
|
def update_attributes_map(self, attributes):
|
||||||
|
super(Firewall, self).update_attributes_map(
|
||||||
|
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
if version == "2.0":
|
||||||
|
return RESOURCE_ATTRIBUTE_MAP
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallPluginBase(ServicePluginBase):
|
||||||
|
__metaclass__ = abc.ABCMeta
|
||||||
|
|
||||||
|
def get_plugin_name(self):
|
||||||
|
return constants.FIREWALL
|
||||||
|
|
||||||
|
def get_plugin_type(self):
|
||||||
|
return constants.FIREWALL
|
||||||
|
|
||||||
|
def get_plugin_description(self):
|
||||||
|
return 'Firewall service plugin'
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_firewalls(self, context, filters=None, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_firewall(self, context, id, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_firewall(self, context, firewall):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def update_firewall(self, context, id, firewall):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def delete_firewall(self, context, id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_firewall_rules(self, context, filters=None, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_firewall_rule(self, context, id, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_firewall_rule(self, context, firewall_rule):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def update_firewall_rule(self, context, id, firewall_rule):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def delete_firewall_rule(self, context, id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_firewall_policy(self, context, id, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_firewall_policies(self, context, filters=None, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_firewall_policy(self, context, firewall_policy):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def update_firewall_policy(self, context, id, firewall_policy):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def delete_firewall_policy(self, context, id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def insert_rule(self, context, id, rule_info):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def remove_rule(self, context, id, rule_info):
|
||||||
|
pass
|
@ -19,20 +19,23 @@
|
|||||||
CORE = "CORE"
|
CORE = "CORE"
|
||||||
DUMMY = "DUMMY"
|
DUMMY = "DUMMY"
|
||||||
LOADBALANCER = "LOADBALANCER"
|
LOADBALANCER = "LOADBALANCER"
|
||||||
|
FIREWALL = "FIREWALL"
|
||||||
|
|
||||||
#maps extension alias to service type
|
#maps extension alias to service type
|
||||||
EXT_TO_SERVICE_MAPPING = {
|
EXT_TO_SERVICE_MAPPING = {
|
||||||
'dummy': DUMMY,
|
'dummy': DUMMY,
|
||||||
'lbaas': LOADBALANCER
|
'lbaas': LOADBALANCER,
|
||||||
|
'fwaas': FIREWALL
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO(salvatore-orlando): Move these (or derive them) from conf file
|
# TODO(salvatore-orlando): Move these (or derive them) from conf file
|
||||||
ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER]
|
ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL]
|
||||||
|
|
||||||
COMMON_PREFIXES = {
|
COMMON_PREFIXES = {
|
||||||
CORE: "",
|
CORE: "",
|
||||||
DUMMY: "/dummy_svc",
|
DUMMY: "/dummy_svc",
|
||||||
LOADBALANCER: "/lb",
|
LOADBALANCER: "/lb",
|
||||||
|
FIREWALL: "/fw",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Service operation status constants
|
# Service operation status constants
|
||||||
@ -42,3 +45,12 @@ PENDING_UPDATE = "PENDING_UPDATE"
|
|||||||
PENDING_DELETE = "PENDING_DELETE"
|
PENDING_DELETE = "PENDING_DELETE"
|
||||||
INACTIVE = "INACTIVE"
|
INACTIVE = "INACTIVE"
|
||||||
ERROR = "ERROR"
|
ERROR = "ERROR"
|
||||||
|
|
||||||
|
# FWaaS firewall rule action
|
||||||
|
FWAAS_ALLOW = "allow"
|
||||||
|
FWAAS_DENY = "deny"
|
||||||
|
|
||||||
|
# L3 Protocol name constants
|
||||||
|
TCP = "tcp"
|
||||||
|
UDP = "udp"
|
||||||
|
ICMP = "icmp"
|
||||||
|
16
neutron/services/firewall/__init__.py
Normal file
16
neutron/services/firewall/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 OpenStack Foundation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
285
neutron/services/firewall/fwaas_plugin.py
Normal file
285
neutron/services/firewall/fwaas_plugin.py
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 Big Switch Networks, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron.common import rpc as q_rpc
|
||||||
|
from neutron.common import topics
|
||||||
|
from neutron.db import api as qdbapi
|
||||||
|
from neutron.db.firewall import firewall_db
|
||||||
|
from neutron.extensions import firewall as fw_ext
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.openstack.common import rpc
|
||||||
|
from neutron.openstack.common.rpc import proxy
|
||||||
|
from neutron.plugins.common import constants as const
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallCallbacks(object):
|
||||||
|
RPC_API_VERSION = '1.0'
|
||||||
|
|
||||||
|
def __init__(self, plugin):
|
||||||
|
self.plugin = plugin
|
||||||
|
|
||||||
|
def create_rpc_dispatcher(self):
|
||||||
|
return q_rpc.PluginRpcDispatcher([self])
|
||||||
|
|
||||||
|
def set_firewall_status(self, context, firewall_id, status, **kwargs):
|
||||||
|
"""Agent uses this to set a firewall's status."""
|
||||||
|
LOG.debug(_("set_firewall_status() called"))
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fw_db = self.plugin._get_firewall(context, firewall_id)
|
||||||
|
if status in (const.ACTIVE, const.INACTIVE):
|
||||||
|
fw_db.status = status
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
fw_db.status = const.ERROR
|
||||||
|
return False
|
||||||
|
|
||||||
|
def firewall_deleted(self, context, firewall_id, **kwargs):
|
||||||
|
"""Agent uses this to indicate firewall is deleted."""
|
||||||
|
LOG.debug(_("firewall_deleted() called"))
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
fw_db = self.plugin._get_firewall(context, firewall_id)
|
||||||
|
if fw_db.status == const.PENDING_DELETE:
|
||||||
|
self.plugin.delete_db_firewall_object(context, firewall_id)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
fw_db.status = const.ERROR
|
||||||
|
LOG.warn(_('Firewall %s unexpectedly deleted by agent.'),
|
||||||
|
firewall_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_firewalls_for_tenant(self, context, **kwargs):
|
||||||
|
"""Agent uses this to get all firewalls and rules for a tenant."""
|
||||||
|
LOG.debug(_("get_firewalls_for_tenant() called"))
|
||||||
|
fw_list = [
|
||||||
|
self.plugin._make_firewall_dict_with_rules(context, fw['id'])
|
||||||
|
for fw in self.plugin.get_firewalls(context)
|
||||||
|
]
|
||||||
|
return fw_list
|
||||||
|
|
||||||
|
def get_firewalls_for_tenant_without_rules(self, context, **kwargs):
|
||||||
|
"""Agent uses this to get all firewalls for a tenant."""
|
||||||
|
LOG.debug(_("get_firewalls_for_tenant_without_rules() called"))
|
||||||
|
fw_list = [fw for fw in self.plugin.get_firewalls(context)]
|
||||||
|
return fw_list
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallAgentApi(proxy.RpcProxy):
|
||||||
|
"""Plugin side of plugin to agent RPC API."""
|
||||||
|
|
||||||
|
API_VERSION = '1.0'
|
||||||
|
|
||||||
|
def __init__(self, topic, host):
|
||||||
|
super(FirewallAgentApi, self).__init__(topic, self.API_VERSION)
|
||||||
|
self.host = host
|
||||||
|
|
||||||
|
def create_firewall(self, context, firewall):
|
||||||
|
return self.fanout_cast(
|
||||||
|
context,
|
||||||
|
self.make_msg('create_firewall', firewall=firewall,
|
||||||
|
host=self.host),
|
||||||
|
topic=self.topic
|
||||||
|
)
|
||||||
|
|
||||||
|
def update_firewall(self, context, firewall):
|
||||||
|
return self.fanout_cast(
|
||||||
|
context,
|
||||||
|
self.make_msg('update_firewall', firewall=firewall,
|
||||||
|
host=self.host),
|
||||||
|
topic=self.topic
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete_firewall(self, context, firewall):
|
||||||
|
return self.fanout_cast(
|
||||||
|
context,
|
||||||
|
self.make_msg('delete_firewall', firewall=firewall,
|
||||||
|
host=self.host),
|
||||||
|
topic=self.topic
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallPlugin(firewall_db.Firewall_db_mixin):
|
||||||
|
|
||||||
|
"""Implementation of the Neutron Firewall Service Plugin.
|
||||||
|
|
||||||
|
This class manages the workflow of FWaaS request/response.
|
||||||
|
Most DB related works are implemented in class
|
||||||
|
firewall_db.Firewall_db_mixin.
|
||||||
|
"""
|
||||||
|
supported_extension_aliases = ["fwaas"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Do the initialization for the firewall service plugin here."""
|
||||||
|
qdbapi.register_models()
|
||||||
|
|
||||||
|
self.callbacks = FirewallCallbacks(self)
|
||||||
|
|
||||||
|
self.conn = rpc.create_connection(new=True)
|
||||||
|
self.conn.create_consumer(
|
||||||
|
topics.FIREWALL_PLUGIN,
|
||||||
|
self.callbacks.create_rpc_dispatcher(),
|
||||||
|
fanout=False)
|
||||||
|
self.conn.consume_in_thread()
|
||||||
|
|
||||||
|
self.agent_rpc = FirewallAgentApi(
|
||||||
|
topics.L3_AGENT,
|
||||||
|
cfg.CONF.host
|
||||||
|
)
|
||||||
|
|
||||||
|
def _make_firewall_dict_with_rules(self, context, firewall_id):
|
||||||
|
firewall = self.get_firewall(context, firewall_id)
|
||||||
|
fw_policy_id = firewall['firewall_policy_id']
|
||||||
|
if fw_policy_id:
|
||||||
|
fw_policy = self.get_firewall_policy(context, fw_policy_id)
|
||||||
|
fw_rules_list = [self.get_firewall_rule(
|
||||||
|
context, rule_id) for rule_id in fw_policy['firewall_rules']]
|
||||||
|
firewall['firewall_rule_list'] = fw_rules_list
|
||||||
|
else:
|
||||||
|
firewall['firewall_rule_list'] = []
|
||||||
|
# FIXME(Sumit): If the size of the firewall object we are creating
|
||||||
|
# here exceeds the largest message size supported by rabbit/qpid
|
||||||
|
# then we will have a problem.
|
||||||
|
return firewall
|
||||||
|
|
||||||
|
def _rpc_update_firewall(self, context, firewall_id):
|
||||||
|
status_update = {"firewall": {"status": const.PENDING_UPDATE}}
|
||||||
|
fw = super(FirewallPlugin, self).update_firewall(context, firewall_id,
|
||||||
|
status_update)
|
||||||
|
if fw:
|
||||||
|
fw_with_rules = (
|
||||||
|
self._make_firewall_dict_with_rules(context,
|
||||||
|
firewall_id))
|
||||||
|
self.agent_rpc.update_firewall(context, fw_with_rules)
|
||||||
|
|
||||||
|
def _rpc_update_firewall_policy(self, context, firewall_policy_id):
|
||||||
|
firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
|
||||||
|
if firewall_policy:
|
||||||
|
for firewall_id in firewall_policy['firewall_list']:
|
||||||
|
self._rpc_update_firewall(context, firewall_id)
|
||||||
|
|
||||||
|
def _ensure_update_firewall(self, context, firewall_id):
|
||||||
|
fwall = self.get_firewall(context, firewall_id)
|
||||||
|
if fwall['status'] in [const.PENDING_CREATE,
|
||||||
|
const.PENDING_UPDATE,
|
||||||
|
const.PENDING_DELETE]:
|
||||||
|
raise fw_ext.FirewallInPendingState(firewall_id=firewall_id,
|
||||||
|
pending_state=fwall['status'])
|
||||||
|
|
||||||
|
def _ensure_update_firewall_policy(self, context, firewall_policy_id):
|
||||||
|
firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
|
||||||
|
if firewall_policy and 'firewall_list' in firewall_policy:
|
||||||
|
for firewall_id in firewall_policy['firewall_list']:
|
||||||
|
self._ensure_update_firewall(context, firewall_id)
|
||||||
|
|
||||||
|
def _ensure_update_or_delete_firewall_rule(self, context,
|
||||||
|
firewall_rule_id):
|
||||||
|
fw_rule = self.get_firewall_rule(context, firewall_rule_id)
|
||||||
|
if 'firewall_policy_id' in fw_rule and fw_rule['firewall_policy_id']:
|
||||||
|
self._ensure_update_firewall_policy(context,
|
||||||
|
fw_rule['firewall_policy_id'])
|
||||||
|
|
||||||
|
def create_firewall(self, context, firewall):
|
||||||
|
LOG.debug(_("create_firewall() called"))
|
||||||
|
firewall['firewall']['status'] = const.PENDING_CREATE
|
||||||
|
fw = super(FirewallPlugin, self).create_firewall(context, firewall)
|
||||||
|
fw_with_rules = (
|
||||||
|
self._make_firewall_dict_with_rules(context, fw['id']))
|
||||||
|
self.agent_rpc.create_firewall(context, fw_with_rules)
|
||||||
|
return fw
|
||||||
|
|
||||||
|
def update_firewall(self, context, id, firewall):
|
||||||
|
LOG.debug(_("update_firewall() called"))
|
||||||
|
self._ensure_update_firewall(context, id)
|
||||||
|
firewall['firewall']['status'] = const.PENDING_UPDATE
|
||||||
|
fw = super(FirewallPlugin, self).update_firewall(context, id, firewall)
|
||||||
|
fw_with_rules = (
|
||||||
|
self._make_firewall_dict_with_rules(context, fw['id']))
|
||||||
|
self.agent_rpc.update_firewall(context, fw_with_rules)
|
||||||
|
return fw
|
||||||
|
|
||||||
|
def delete_db_firewall_object(self, context, id):
|
||||||
|
firewall = self.get_firewall(context, id)
|
||||||
|
if firewall['status'] in [const.PENDING_DELETE]:
|
||||||
|
super(FirewallPlugin, self).delete_firewall(context, id)
|
||||||
|
|
||||||
|
def delete_firewall(self, context, id):
|
||||||
|
LOG.debug(_("delete_firewall() called"))
|
||||||
|
status_update = {"firewall": {"status": const.PENDING_DELETE}}
|
||||||
|
fw = super(FirewallPlugin, self).update_firewall(context, id,
|
||||||
|
status_update)
|
||||||
|
fw_with_rules = (
|
||||||
|
self._make_firewall_dict_with_rules(context, fw['id']))
|
||||||
|
self.agent_rpc.delete_firewall(context, fw_with_rules)
|
||||||
|
|
||||||
|
def update_firewall_policy(self, context, id, firewall_policy):
|
||||||
|
LOG.debug(_("update_firewall_policy() called"))
|
||||||
|
self._ensure_update_firewall_policy(context, id)
|
||||||
|
fwp = super(FirewallPlugin,
|
||||||
|
self).update_firewall_policy(context, id, firewall_policy)
|
||||||
|
self._rpc_update_firewall_policy(context, id)
|
||||||
|
return fwp
|
||||||
|
|
||||||
|
def update_firewall_rule(self, context, id, firewall_rule):
|
||||||
|
LOG.debug(_("update_firewall_rule() called"))
|
||||||
|
self._ensure_update_or_delete_firewall_rule(context, id)
|
||||||
|
fwr = super(FirewallPlugin,
|
||||||
|
self).update_firewall_rule(context, id, firewall_rule)
|
||||||
|
firewall_policy_id = fwr['firewall_policy_id']
|
||||||
|
if firewall_policy_id:
|
||||||
|
self._rpc_update_firewall_policy(context, firewall_policy_id)
|
||||||
|
return fwr
|
||||||
|
|
||||||
|
def delete_firewall_rule(self, context, id):
|
||||||
|
LOG.debug(_("delete_firewall_rule() called"))
|
||||||
|
self._ensure_update_or_delete_firewall_rule(context, id)
|
||||||
|
fwr = self.get_firewall_rule(context, id)
|
||||||
|
firewall_policy_id = fwr['firewall_policy_id']
|
||||||
|
super(FirewallPlugin, self).delete_firewall_rule(context, id)
|
||||||
|
# At this point we have already deleted the rule in the DB,
|
||||||
|
# however it's still not deleted on the backend firewall.
|
||||||
|
# Until it gets deleted on the backend we will be setting
|
||||||
|
# the firewall in PENDING_UPDATE state. The backend firewall
|
||||||
|
# implementation is responsible for setting the appropriate
|
||||||
|
# configuration (e.g. do not allow any traffic) until the rule
|
||||||
|
# is deleted. Once the rule is deleted, the backend should put
|
||||||
|
# the firewall back in ACTIVE state. While the firewall is in
|
||||||
|
# PENDING_UPDATE state, the firewall behavior might differ based
|
||||||
|
# on the backend implementation.
|
||||||
|
if firewall_policy_id:
|
||||||
|
self._rpc_update_firewall_policy(context, firewall_policy_id)
|
||||||
|
|
||||||
|
def insert_rule(self, context, id, rule_info):
|
||||||
|
LOG.debug(_("insert_rule() called"))
|
||||||
|
self._ensure_update_firewall_policy(context, id)
|
||||||
|
fwp = super(FirewallPlugin,
|
||||||
|
self).insert_rule(context, id, rule_info)
|
||||||
|
self._rpc_update_firewall_policy(context, id)
|
||||||
|
return fwp
|
||||||
|
|
||||||
|
def remove_rule(self, context, id, rule_info):
|
||||||
|
LOG.debug(_("remove_rule() called"))
|
||||||
|
self._ensure_update_firewall_policy(context, id)
|
||||||
|
fwp = super(FirewallPlugin,
|
||||||
|
self).remove_rule(context, id, rule_info)
|
||||||
|
self._rpc_update_firewall_policy(context, id)
|
||||||
|
return fwp
|
15
neutron/tests/unit/db/firewall/__init__.py
Normal file
15
neutron/tests/unit/db/firewall/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 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.
|
965
neutron/tests/unit/db/firewall/test_db_firewall.py
Normal file
965
neutron/tests/unit/db/firewall/test_db_firewall.py
Normal file
@ -0,0 +1,965 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 Big Switch Networks, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the spec
|
||||||
|
#
|
||||||
|
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import webob.exc
|
||||||
|
|
||||||
|
from neutron.api import extensions as api_ext
|
||||||
|
from neutron.common import config
|
||||||
|
from neutron import context
|
||||||
|
from neutron.db.firewall import firewall_db as fdb
|
||||||
|
import neutron.extensions
|
||||||
|
from neutron.extensions import firewall
|
||||||
|
from neutron.openstack.common import importutils
|
||||||
|
from neutron.plugins.common import constants
|
||||||
|
from neutron.tests.unit import test_db_plugin
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
DB_FW_PLUGIN_KLASS = (
|
||||||
|
"neutron.db.firewall.firewall_db.Firewall_db_mixin"
|
||||||
|
)
|
||||||
|
extensions_path = ':'.join(neutron.extensions.__path__)
|
||||||
|
DESCRIPTION = 'default description'
|
||||||
|
SHARED = 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 FirewallPluginDbTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
||||||
|
resource_prefix_map = dict(
|
||||||
|
(k, constants.COMMON_PREFIXES[constants.FIREWALL])
|
||||||
|
for k in firewall.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||||
|
)
|
||||||
|
|
||||||
|
def setUp(self, core_plugin=None, fw_plugin=None):
|
||||||
|
if not fw_plugin:
|
||||||
|
fw_plugin = DB_FW_PLUGIN_KLASS
|
||||||
|
service_plugins = {'fw_plugin_name': fw_plugin}
|
||||||
|
|
||||||
|
fdb.Firewall_db_mixin.supported_extension_aliases = ["fwaas"]
|
||||||
|
super(FirewallPluginDbTestCase, self).setUp(
|
||||||
|
service_plugins=service_plugins
|
||||||
|
)
|
||||||
|
|
||||||
|
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['id'] for i in res[resource_plural]]),
|
||||||
|
sorted([i[resource]['id'] for i in items]))
|
||||||
|
|
||||||
|
def _get_test_firewall_rule_attrs(self, name='firewall_rule1'):
|
||||||
|
attrs = {'name': name,
|
||||||
|
'tenant_id': self._tenant_id,
|
||||||
|
'shared': SHARED,
|
||||||
|
'protocol': PROTOCOL,
|
||||||
|
'ip_version': IP_VERSION,
|
||||||
|
'source_ip_address': SOURCE_IP_ADDRESS_RAW,
|
||||||
|
'destination_ip_address': DESTINATION_IP_ADDRESS_RAW,
|
||||||
|
'source_port': SOURCE_PORT,
|
||||||
|
'destination_port': DESTINATION_PORT,
|
||||||
|
'action': ACTION,
|
||||||
|
'enabled': ENABLED}
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def _get_test_firewall_policy_attrs(self, name='firewall_policy1'):
|
||||||
|
attrs = {'name': name,
|
||||||
|
'description': DESCRIPTION,
|
||||||
|
'tenant_id': self._tenant_id,
|
||||||
|
'shared': SHARED,
|
||||||
|
'firewall_rules': [],
|
||||||
|
'audited': AUDITED}
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def _get_test_firewall_attrs(self, name='firewall_1'):
|
||||||
|
attrs = {'name': name,
|
||||||
|
'tenant_id': self._tenant_id,
|
||||||
|
'admin_state_up': ADMIN_STATE_UP,
|
||||||
|
'status': 'PENDING_CREATE'}
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def _create_firewall_policy(self, fmt, name, description, shared,
|
||||||
|
firewall_rules, audited,
|
||||||
|
expected_res_status=None, **kwargs):
|
||||||
|
data = {'firewall_policy': {'name': name,
|
||||||
|
'description': description,
|
||||||
|
'tenant_id': self._tenant_id,
|
||||||
|
'shared': shared,
|
||||||
|
'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(fw_policy_res.status_int, expected_res_status)
|
||||||
|
|
||||||
|
return fw_policy_res
|
||||||
|
|
||||||
|
def _replace_firewall_status(self, attrs, old_status, new_status):
|
||||||
|
if attrs['status'] is old_status:
|
||||||
|
attrs['status'] = new_status
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def firewall_policy(self, fmt=None, name='firewall_policy1',
|
||||||
|
description=DESCRIPTION, shared=True,
|
||||||
|
firewall_rules=None, audited=True,
|
||||||
|
no_delete=False, **kwargs):
|
||||||
|
if firewall_rules is None:
|
||||||
|
firewall_rules = []
|
||||||
|
if not fmt:
|
||||||
|
fmt = self.fmt
|
||||||
|
res = self._create_firewall_policy(fmt, name, description, shared,
|
||||||
|
firewall_rules, audited,
|
||||||
|
**kwargs)
|
||||||
|
if res.status_int >= 400:
|
||||||
|
raise webob.exc.HTTPClientError(code=res.status_int)
|
||||||
|
firewall_policy = self.deserialize(fmt or self.fmt, res)
|
||||||
|
try:
|
||||||
|
yield firewall_policy
|
||||||
|
finally:
|
||||||
|
if not no_delete:
|
||||||
|
self._delete('firewall_policies',
|
||||||
|
firewall_policy['firewall_policy']['id'])
|
||||||
|
|
||||||
|
def _create_firewall_rule(self, fmt, name, shared, protocol,
|
||||||
|
ip_version, source_ip_address,
|
||||||
|
destination_ip_address, source_port,
|
||||||
|
destination_port, action, enabled,
|
||||||
|
expected_res_status=None, **kwargs):
|
||||||
|
data = {'firewall_rule': {'name': name,
|
||||||
|
'tenant_id': self._tenant_id,
|
||||||
|
'shared': shared,
|
||||||
|
'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(fw_rule_res.status_int, expected_res_status)
|
||||||
|
|
||||||
|
return fw_rule_res
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def firewall_rule(self, fmt=None, name='firewall_rule1',
|
||||||
|
shared=SHARED, protocol=PROTOCOL, ip_version=IP_VERSION,
|
||||||
|
source_ip_address=SOURCE_IP_ADDRESS_RAW,
|
||||||
|
destination_ip_address=DESTINATION_IP_ADDRESS_RAW,
|
||||||
|
source_port=SOURCE_PORT,
|
||||||
|
destination_port=DESTINATION_PORT,
|
||||||
|
action=ACTION, enabled=ENABLED,
|
||||||
|
no_delete=False, **kwargs):
|
||||||
|
if not fmt:
|
||||||
|
fmt = self.fmt
|
||||||
|
res = self._create_firewall_rule(fmt, name, shared, protocol,
|
||||||
|
ip_version, source_ip_address,
|
||||||
|
destination_ip_address,
|
||||||
|
source_port, destination_port,
|
||||||
|
action, enabled, **kwargs)
|
||||||
|
if res.status_int >= 400:
|
||||||
|
raise webob.exc.HTTPClientError(code=res.status_int)
|
||||||
|
firewall_rule = self.deserialize(fmt or self.fmt, res)
|
||||||
|
try:
|
||||||
|
yield firewall_rule
|
||||||
|
finally:
|
||||||
|
if not no_delete:
|
||||||
|
self._delete('firewall_rules',
|
||||||
|
firewall_rule['firewall_rule']['id'])
|
||||||
|
|
||||||
|
def _create_firewall(self, fmt, name, description, firewall_policy_id,
|
||||||
|
admin_state_up=True, expected_res_status=None,
|
||||||
|
**kwargs):
|
||||||
|
data = {'firewall': {'name': name,
|
||||||
|
'description': description,
|
||||||
|
'firewall_policy_id': firewall_policy_id,
|
||||||
|
'admin_state_up': admin_state_up,
|
||||||
|
'tenant_id': self._tenant_id}}
|
||||||
|
|
||||||
|
firewall_req = self.new_create_request('firewalls', data, fmt)
|
||||||
|
firewall_res = firewall_req.get_response(self.ext_api)
|
||||||
|
if expected_res_status:
|
||||||
|
self.assertEqual(firewall_res.status_int, expected_res_status)
|
||||||
|
|
||||||
|
return firewall_res
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def firewall(self, fmt=None, name='firewall_1', description=DESCRIPTION,
|
||||||
|
firewall_policy_id=None, admin_state_up=True,
|
||||||
|
no_delete=False, **kwargs):
|
||||||
|
if not fmt:
|
||||||
|
fmt = self.fmt
|
||||||
|
res = self._create_firewall(fmt, name, description, firewall_policy_id,
|
||||||
|
admin_state_up, **kwargs)
|
||||||
|
if res.status_int >= 400:
|
||||||
|
raise webob.exc.HTTPClientError(code=res.status_int)
|
||||||
|
firewall = self.deserialize(fmt or self.fmt, res)
|
||||||
|
try:
|
||||||
|
yield firewall
|
||||||
|
finally:
|
||||||
|
if not no_delete:
|
||||||
|
self._delete('firewalls', firewall['firewall']['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(res.status_int, expected_code)
|
||||||
|
response = self.deserialize(self.fmt, res)
|
||||||
|
if expected_body:
|
||||||
|
self.assertEqual(response, expected_body)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def _compare_firewall_rule_lists(self, firewall_policy_id,
|
||||||
|
list1, list2):
|
||||||
|
position = 0
|
||||||
|
for r1, r2 in zip(list1, list2):
|
||||||
|
rule = r1['firewall_rule']
|
||||||
|
rule['firewall_policy_id'] = firewall_policy_id
|
||||||
|
position += 1
|
||||||
|
rule['position'] = position
|
||||||
|
for k in rule:
|
||||||
|
self.assertEqual(rule[k], r2[k])
|
||||||
|
|
||||||
|
|
||||||
|
class TestFirewallDBPlugin(FirewallPluginDbTestCase):
|
||||||
|
|
||||||
|
def test_create_firewall_policy(self):
|
||||||
|
name = "firewall_policy1"
|
||||||
|
attrs = self._get_test_firewall_policy_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy(name=name, shared=SHARED,
|
||||||
|
firewall_rules=None,
|
||||||
|
audited=AUDITED) as firewall_policy:
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(firewall_policy['firewall_policy'][k], v)
|
||||||
|
|
||||||
|
def test_create_firewall_policy_with_rules(self):
|
||||||
|
name = "firewall_policy1"
|
||||||
|
attrs = self._get_test_firewall_policy_attrs(name)
|
||||||
|
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr3',
|
||||||
|
no_delete=True)) as fr:
|
||||||
|
fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
|
||||||
|
attrs['firewall_rules'] = fw_rule_ids
|
||||||
|
with self.firewall_policy(name=name, shared=SHARED,
|
||||||
|
firewall_rules=fw_rule_ids,
|
||||||
|
audited=AUDITED,
|
||||||
|
no_delete=True) as fwp:
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(fwp['firewall_policy'][k], v)
|
||||||
|
|
||||||
|
def test_show_firewall_policy(self):
|
||||||
|
name = "firewall_policy1"
|
||||||
|
attrs = self._get_test_firewall_policy_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy(name=name, shared=SHARED,
|
||||||
|
firewall_rules=None,
|
||||||
|
audited=AUDITED) as fwp:
|
||||||
|
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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_policy'][k], v)
|
||||||
|
|
||||||
|
def test_list_firewall_policies(self):
|
||||||
|
with contextlib.nested(self.firewall_policy(name='fwp1',
|
||||||
|
description='fwp'),
|
||||||
|
self.firewall_policy(name='fwp2',
|
||||||
|
description='fwp'),
|
||||||
|
self.firewall_policy(name='fwp3',
|
||||||
|
description='fwp')
|
||||||
|
) as fw_policies:
|
||||||
|
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)
|
||||||
|
|
||||||
|
with self.firewall_policy(shared=SHARED,
|
||||||
|
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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_policy'][k], v)
|
||||||
|
|
||||||
|
def test_update_firewall_policy_with_rules(self):
|
||||||
|
attrs = self._get_test_firewall_policy_attrs()
|
||||||
|
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr3',
|
||||||
|
no_delete=True)) as fr:
|
||||||
|
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
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_policy'][k], v)
|
||||||
|
|
||||||
|
def test_update_firewall_policy_replace_rules(self):
|
||||||
|
attrs = self._get_test_firewall_policy_attrs()
|
||||||
|
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True)) as fr1:
|
||||||
|
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)
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr3',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr4',
|
||||||
|
no_delete=True)) as fr2:
|
||||||
|
fw_rule_ids = [r['firewall_rule']['id'] for r in fr2]
|
||||||
|
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
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_policy'][k], v)
|
||||||
|
|
||||||
|
def test_update_firewall_policy_with_non_existing_rule(self):
|
||||||
|
attrs = self._get_test_firewall_policy_attrs()
|
||||||
|
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True)) as fr:
|
||||||
|
fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
|
||||||
|
fw_rule_ids.append('12345') # non-existent 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)
|
||||||
|
#check that the firewall_rule was not found
|
||||||
|
self.assertEqual(res.status_int, 404)
|
||||||
|
#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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_policy'][k], v)
|
||||||
|
|
||||||
|
def test_delete_firewall_policy(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_policy(no_delete=True) 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(res.status_int, 204)
|
||||||
|
self.assertRaises(firewall.FirewallPolicyNotFound,
|
||||||
|
self.plugin.get_firewall_policy,
|
||||||
|
ctx, fwp_id)
|
||||||
|
|
||||||
|
def test_delete_firewall_policy_with_rule(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
attrs = self._get_test_firewall_policy_attrs()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall_rule(name='fwr1', no_delete=True) 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(fw_rule['firewall_policy_id'], fwp_id)
|
||||||
|
req = self.new_delete_request('firewall_policies', fwp_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 204)
|
||||||
|
self.assertRaises(firewall.FirewallPolicyNotFound,
|
||||||
|
self.plugin.get_firewall_policy,
|
||||||
|
ctx, fwp_id)
|
||||||
|
fw_rule = self.plugin.get_firewall_rule(ctx, fr_id)
|
||||||
|
self.assertEqual(fw_rule['firewall_policy_id'], None)
|
||||||
|
|
||||||
|
def test_delete_firewall_policy_with_firewall_association(self):
|
||||||
|
attrs = self._get_test_firewall_attrs()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
ADMIN_STATE_UP):
|
||||||
|
req = self.new_delete_request('firewall_policies', fwp_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 409)
|
||||||
|
|
||||||
|
def test_create_firewall_rule(self):
|
||||||
|
attrs = self._get_test_firewall_rule_attrs()
|
||||||
|
|
||||||
|
with self.firewall_rule() as firewall_rule:
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(firewall_rule['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
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 attrs.iteritems():
|
||||||
|
self.assertEqual(firewall_rule['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
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 attrs.iteritems():
|
||||||
|
self.assertEqual(firewall_rule['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
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 attrs.iteritems():
|
||||||
|
self.assertEqual(firewall_rule['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
def test_show_firewall_rule_with_fw_policy_associated(self):
|
||||||
|
attrs = self._get_test_firewall_rule_attrs()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall_rule(no_delete=True) as fw_rule:
|
||||||
|
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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
def test_list_firewall_rules(self):
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr3',
|
||||||
|
no_delete=True)) as fr:
|
||||||
|
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(no_delete=True) 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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
attrs['source_port'] = '10000'
|
||||||
|
attrs['destination_port'] = '80'
|
||||||
|
with self.firewall_rule(no_delete=True) 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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
attrs['source_port'] = '10000'
|
||||||
|
attrs['destination_port'] = '80'
|
||||||
|
with self.firewall_rule(no_delete=True) 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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
attrs['source_port'] = None
|
||||||
|
attrs['destination_port'] = None
|
||||||
|
with self.firewall_rule(no_delete=True) 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 attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_rule'][k], v)
|
||||||
|
|
||||||
|
def test_update_firewall_rule_with_policy_associated(self):
|
||||||
|
name = "new_firewall_rule1"
|
||||||
|
attrs = self._get_test_firewall_rule_attrs(name)
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall_rule(no_delete=True) as fwr:
|
||||||
|
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))
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall_rule'][k], v)
|
||||||
|
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(res['firewall_policy']['firewall_rules'],
|
||||||
|
[fwr_id])
|
||||||
|
self.assertEqual(res['firewall_policy']['audited'], False)
|
||||||
|
|
||||||
|
def test_delete_firewall_rule(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_rule(no_delete=True) 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(res.status_int, 204)
|
||||||
|
self.assertRaises(firewall.FirewallRuleNotFound,
|
||||||
|
self.plugin.get_firewall_rule,
|
||||||
|
ctx, fwr_id)
|
||||||
|
|
||||||
|
def test_delete_firewall_rule_with_policy_associated(self):
|
||||||
|
attrs = self._get_test_firewall_rule_attrs()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall_rule(no_delete=True) as fwr:
|
||||||
|
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)
|
||||||
|
req = self.new_delete_request('firewall_rules', fwr_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 409)
|
||||||
|
|
||||||
|
def test_create_firewall(self):
|
||||||
|
name = "firewall1"
|
||||||
|
attrs = self._get_test_firewall_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(name=name,
|
||||||
|
firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
ADMIN_STATE_UP) as firewall:
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(firewall['firewall'][k], v)
|
||||||
|
|
||||||
|
def test_show_firewall(self):
|
||||||
|
name = "firewall1"
|
||||||
|
attrs = self._get_test_firewall_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(name=name,
|
||||||
|
firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
ADMIN_STATE_UP) as firewall:
|
||||||
|
req = self.new_show_request('firewalls',
|
||||||
|
firewall['firewall']['id'],
|
||||||
|
fmt=self.fmt)
|
||||||
|
res = self.deserialize(self.fmt,
|
||||||
|
req.get_response(self.ext_api))
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall'][k], v)
|
||||||
|
|
||||||
|
def test_list_firewalls(self):
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with contextlib.nested(self.firewall(name='fw1',
|
||||||
|
firewall_policy_id=fwp_id,
|
||||||
|
description='fw'),
|
||||||
|
self.firewall(name='fw2',
|
||||||
|
firewall_policy_id=fwp_id,
|
||||||
|
description='fw'),
|
||||||
|
self.firewall(name='fw3',
|
||||||
|
firewall_policy_id=fwp_id,
|
||||||
|
description='fw')) as fwalls:
|
||||||
|
self._test_list_resources('firewall', fwalls,
|
||||||
|
query_params='description=fw')
|
||||||
|
|
||||||
|
def test_update_firewall(self):
|
||||||
|
name = "new_firewall1"
|
||||||
|
attrs = self._get_test_firewall_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
ADMIN_STATE_UP) as firewall:
|
||||||
|
data = {'firewall': {'name': name}}
|
||||||
|
req = self.new_update_request('firewalls', data,
|
||||||
|
firewall['firewall']['id'])
|
||||||
|
res = self.deserialize(self.fmt,
|
||||||
|
req.get_response(self.ext_api))
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall'][k], v)
|
||||||
|
|
||||||
|
def test_delete_firewall(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
no_delete=True) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
req = self.new_delete_request('firewalls', fw_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 204)
|
||||||
|
self.assertRaises(firewall.FirewallNotFound,
|
||||||
|
self.plugin.get_firewall,
|
||||||
|
ctx, fw_id)
|
||||||
|
|
||||||
|
def test_insert_rule_in_policy_with_prior_rules_added_via_update(self):
|
||||||
|
attrs = self._get_test_firewall_policy_attrs()
|
||||||
|
attrs['audited'] = False
|
||||||
|
attrs['firewall_list'] = []
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['id'] = fwp_id
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True)) as fr1:
|
||||||
|
fw_rule_ids = [r['firewall_rule']['id'] for r in fr1]
|
||||||
|
attrs['firewall_rules'] = fw_rule_ids[:]
|
||||||
|
data = {'firewall_policy':
|
||||||
|
{'firewall_rules': fw_rule_ids}}
|
||||||
|
req = self.new_update_request('firewall_policies', data,
|
||||||
|
fwp_id)
|
||||||
|
req.get_response(self.ext_api)
|
||||||
|
self._rule_action('insert', fwp_id, fw_rule_ids[0],
|
||||||
|
insert_before=fw_rule_ids[0],
|
||||||
|
insert_after=None,
|
||||||
|
expected_code=webob.exc.HTTPConflict.code,
|
||||||
|
expected_body=None)
|
||||||
|
with self.firewall_rule(name='fwr3', no_delete=True) as fwr3:
|
||||||
|
fwr3_id = fwr3['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].insert(0, fwr3_id)
|
||||||
|
self._rule_action('insert', fwp_id, fwr3_id,
|
||||||
|
insert_before=fw_rule_ids[0],
|
||||||
|
insert_after=None,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs)
|
||||||
|
|
||||||
|
def test_insert_rule_in_policy_failures(self):
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall_rule(name='fwr1', no_delete=True) as fr1:
|
||||||
|
fr1_id = fr1['firewall_rule']['id']
|
||||||
|
fw_rule_ids = [fr1_id]
|
||||||
|
data = {'firewall_policy':
|
||||||
|
{'firewall_rules': fw_rule_ids}}
|
||||||
|
req = self.new_update_request('firewall_policies', data,
|
||||||
|
fwp_id)
|
||||||
|
req.get_response(self.ext_api)
|
||||||
|
# test inserting with empty request body
|
||||||
|
self._rule_action('insert', fwp_id, '123',
|
||||||
|
expected_code=webob.exc.HTTPBadRequest.code,
|
||||||
|
expected_body=None, body_data={})
|
||||||
|
# test inserting when firewall_rule_id is missing in
|
||||||
|
# request body
|
||||||
|
insert_data = {'insert_before': '123',
|
||||||
|
'insert_after': '456'}
|
||||||
|
self._rule_action('insert', fwp_id, '123',
|
||||||
|
expected_code=webob.exc.HTTPBadRequest.code,
|
||||||
|
expected_body=None,
|
||||||
|
body_data=insert_data)
|
||||||
|
# test inserting when firewall_rule_id is None
|
||||||
|
insert_data = {'firewall_rule_id': None,
|
||||||
|
'insert_before': '123',
|
||||||
|
'insert_after': '456'}
|
||||||
|
self._rule_action('insert', fwp_id, '123',
|
||||||
|
expected_code=webob.exc.HTTPNotFound.code,
|
||||||
|
expected_body=None,
|
||||||
|
body_data=insert_data)
|
||||||
|
# test inserting when firewall_policy_id is incorrect
|
||||||
|
self._rule_action('insert', '123', fr1_id,
|
||||||
|
expected_code=webob.exc.HTTPNotFound.code,
|
||||||
|
expected_body=None)
|
||||||
|
# test inserting when firewall_policy_id is None
|
||||||
|
self._rule_action('insert', None, fr1_id,
|
||||||
|
expected_code=webob.exc.HTTPBadRequest.code,
|
||||||
|
expected_body=None)
|
||||||
|
|
||||||
|
def test_insert_rule_in_policy(self):
|
||||||
|
attrs = self._get_test_firewall_policy_attrs()
|
||||||
|
attrs['audited'] = False
|
||||||
|
attrs['firewall_list'] = []
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['id'] = fwp_id
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr0',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr3',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr4',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr5',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr6',
|
||||||
|
no_delete=True)) as fwr:
|
||||||
|
# test insert when rule list is empty
|
||||||
|
fwr0_id = fwr[0]['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].insert(0, fwr0_id)
|
||||||
|
self._rule_action('insert', fwp_id, fwr0_id,
|
||||||
|
insert_before=None,
|
||||||
|
insert_after=None,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs)
|
||||||
|
# test insert at top of rule list, insert_before and
|
||||||
|
# insert_after not provided
|
||||||
|
fwr1_id = fwr[1]['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].insert(0, fwr1_id)
|
||||||
|
insert_data = {'firewall_rule_id': fwr1_id}
|
||||||
|
self._rule_action('insert', fwp_id, fwr0_id,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs, body_data=insert_data)
|
||||||
|
# test insert at top of list above existing rule
|
||||||
|
fwr2_id = fwr[2]['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].insert(0, fwr2_id)
|
||||||
|
self._rule_action('insert', fwp_id, fwr2_id,
|
||||||
|
insert_before=fwr1_id,
|
||||||
|
insert_after=None,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs)
|
||||||
|
# test insert at bottom of list
|
||||||
|
fwr3_id = fwr[3]['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].append(fwr3_id)
|
||||||
|
self._rule_action('insert', fwp_id, fwr3_id,
|
||||||
|
insert_before=None,
|
||||||
|
insert_after=fwr0_id,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs)
|
||||||
|
# test insert in the middle of the list using
|
||||||
|
# insert_before
|
||||||
|
fwr4_id = fwr[4]['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].insert(1, fwr4_id)
|
||||||
|
self._rule_action('insert', fwp_id, fwr4_id,
|
||||||
|
insert_before=fwr1_id,
|
||||||
|
insert_after=None,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs)
|
||||||
|
# test insert in the middle of the list using
|
||||||
|
# insert_after
|
||||||
|
fwr5_id = fwr[5]['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].insert(1, fwr5_id)
|
||||||
|
self._rule_action('insert', fwp_id, fwr5_id,
|
||||||
|
insert_before=None,
|
||||||
|
insert_after=fwr2_id,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs)
|
||||||
|
# test insert when both insert_before and
|
||||||
|
# insert_after are set
|
||||||
|
fwr6_id = fwr[6]['firewall_rule']['id']
|
||||||
|
attrs['firewall_rules'].insert(1, fwr6_id)
|
||||||
|
self._rule_action('insert', fwp_id, fwr6_id,
|
||||||
|
insert_before=fwr5_id,
|
||||||
|
insert_after=fwr5_id,
|
||||||
|
expected_code=webob.exc.HTTPOk.code,
|
||||||
|
expected_body=attrs)
|
||||||
|
|
||||||
|
def test_remove_rule_from_policy(self):
|
||||||
|
attrs = self._get_test_firewall_policy_attrs()
|
||||||
|
attrs['audited'] = False
|
||||||
|
attrs['firewall_list'] = []
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['id'] = fwp_id
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr3',
|
||||||
|
no_delete=True)) as fr1:
|
||||||
|
fw_rule_ids = [r['firewall_rule']['id'] for r in fr1]
|
||||||
|
attrs['firewall_rules'] = fw_rule_ids[:]
|
||||||
|
data = {'firewall_policy':
|
||||||
|
{'firewall_rules': fw_rule_ids}}
|
||||||
|
req = self.new_update_request('firewall_policies', data,
|
||||||
|
fwp_id)
|
||||||
|
req.get_response(self.ext_api)
|
||||||
|
# test removing a rule from a policy that does not exist
|
||||||
|
self._rule_action('remove', '123', fw_rule_ids[1],
|
||||||
|
expected_code=webob.exc.HTTPNotFound.code,
|
||||||
|
expected_body=None)
|
||||||
|
# test removing a rule in the middle of the list
|
||||||
|
attrs['firewall_rules'].remove(fw_rule_ids[1])
|
||||||
|
self._rule_action('remove', fwp_id, fw_rule_ids[1],
|
||||||
|
expected_body=attrs)
|
||||||
|
# test removing a rule at the top of the list
|
||||||
|
attrs['firewall_rules'].remove(fw_rule_ids[0])
|
||||||
|
self._rule_action('remove', fwp_id, fw_rule_ids[0],
|
||||||
|
expected_body=attrs)
|
||||||
|
# test removing remaining rule in the list
|
||||||
|
attrs['firewall_rules'].remove(fw_rule_ids[2])
|
||||||
|
self._rule_action('remove', fwp_id, fw_rule_ids[2],
|
||||||
|
expected_body=attrs)
|
||||||
|
# test removing rule that is not associated with the policy
|
||||||
|
self._rule_action('remove', fwp_id, fw_rule_ids[2],
|
||||||
|
expected_code=webob.exc.HTTPBadRequest.code,
|
||||||
|
expected_body=None)
|
||||||
|
|
||||||
|
def test_remove_rule_from_policy_failures(self):
|
||||||
|
with self.firewall_policy() as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall_rule(name='fwr1', no_delete=True) as fr1:
|
||||||
|
fw_rule_ids = [fr1['firewall_rule']['id']]
|
||||||
|
data = {'firewall_policy':
|
||||||
|
{'firewall_rules': fw_rule_ids}}
|
||||||
|
req = self.new_update_request('firewall_policies', data,
|
||||||
|
fwp_id)
|
||||||
|
req.get_response(self.ext_api)
|
||||||
|
# test removing rule that does not exist
|
||||||
|
self._rule_action('remove', fwp_id, '123',
|
||||||
|
expected_code=webob.exc.HTTPNotFound.code,
|
||||||
|
expected_body=None)
|
||||||
|
# test removing rule with bad request
|
||||||
|
self._rule_action('remove', fwp_id, '123',
|
||||||
|
expected_code=webob.exc.HTTPBadRequest.code,
|
||||||
|
expected_body=None, body_data={})
|
||||||
|
# test removing rule with firewall_rule_id set to None
|
||||||
|
self._rule_action('remove', fwp_id, '123',
|
||||||
|
expected_code=webob.exc.HTTPNotFound.code,
|
||||||
|
expected_body=None,
|
||||||
|
body_data={'firewall_rule_id': None})
|
||||||
|
|
||||||
|
|
||||||
|
class TestFirewallDBPluginXML(TestFirewallDBPlugin):
|
||||||
|
fmt = 'xml'
|
15
neutron/tests/unit/services/firewall/__init__.py
Normal file
15
neutron/tests/unit/services/firewall/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 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.
|
353
neutron/tests/unit/services/firewall/test_fwaas_plugin.py
Normal file
353
neutron/tests/unit/services/firewall/test_fwaas_plugin.py
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 Big Switch Networks, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the spec
|
||||||
|
#
|
||||||
|
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
|
||||||
|
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from neutron import context
|
||||||
|
from neutron.extensions import firewall
|
||||||
|
from neutron.plugins.common import constants as const
|
||||||
|
from neutron.services.firewall import fwaas_plugin
|
||||||
|
from neutron.tests import base
|
||||||
|
from neutron.tests.unit.db.firewall import test_db_firewall
|
||||||
|
|
||||||
|
|
||||||
|
FW_PLUGIN_KLASS = (
|
||||||
|
"neutron.services.firewall.fwaas_plugin.FirewallPlugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFirewallCallbacks(test_db_firewall.FirewallPluginDbTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestFirewallCallbacks,
|
||||||
|
self).setUp(fw_plugin=FW_PLUGIN_KLASS)
|
||||||
|
self.callbacks = self.plugin.callbacks
|
||||||
|
|
||||||
|
def test_set_firewall_status(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
res = self.callbacks.set_firewall_status(ctx, fw_id,
|
||||||
|
const.ACTIVE,
|
||||||
|
host='dummy')
|
||||||
|
fw_db = self.plugin.get_firewall(ctx, fw_id)
|
||||||
|
self.assertEqual(fw_db['status'], const.ACTIVE)
|
||||||
|
self.assertTrue(res)
|
||||||
|
res = self.callbacks.set_firewall_status(ctx, fw_id,
|
||||||
|
const.ERROR)
|
||||||
|
fw_db = self.plugin.get_firewall(ctx, fw_id)
|
||||||
|
self.assertEqual(fw_db['status'], const.ERROR)
|
||||||
|
self.assertFalse(res)
|
||||||
|
|
||||||
|
def test_firewall_deleted(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
||||||
|
no_delete=True) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
with ctx.session.begin(subtransactions=True):
|
||||||
|
fw_db = self.plugin._get_firewall(ctx, fw_id)
|
||||||
|
fw_db['status'] = const.PENDING_DELETE
|
||||||
|
ctx.session.flush()
|
||||||
|
res = self.callbacks.firewall_deleted(ctx, fw_id,
|
||||||
|
host='dummy')
|
||||||
|
self.assertTrue(res)
|
||||||
|
self.assertRaises(firewall.FirewallNotFound,
|
||||||
|
self.plugin.get_firewall,
|
||||||
|
ctx, fw_id)
|
||||||
|
|
||||||
|
def test_firewall_deleted_error(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
||||||
|
no_delete=True) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
res = self.callbacks.firewall_deleted(ctx, fw_id,
|
||||||
|
host='dummy')
|
||||||
|
self.assertFalse(res)
|
||||||
|
fw_db = self.plugin._get_firewall(ctx, fw_id)
|
||||||
|
self.assertEqual(fw_db['status'], const.ERROR)
|
||||||
|
|
||||||
|
def test_get_firewall_for_tenant(self):
|
||||||
|
tenant_id = 'test-tenant'
|
||||||
|
ctx = context.Context('', tenant_id)
|
||||||
|
with self.firewall_policy(tenant_id=tenant_id, no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr3',
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
no_delete=True)) as fr:
|
||||||
|
fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
|
||||||
|
data = {'firewall_policy':
|
||||||
|
{'firewall_rules': fw_rule_ids}}
|
||||||
|
req = self.new_update_request('firewall_policies', data,
|
||||||
|
fwp_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
attrs = self._get_test_firewall_attrs()
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP,
|
||||||
|
no_delete=True) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
res = self.callbacks.get_firewalls_for_tenant(ctx,
|
||||||
|
host='dummy')
|
||||||
|
fw_rules = (
|
||||||
|
self.plugin._make_firewall_dict_with_rules(ctx,
|
||||||
|
fw_id)
|
||||||
|
)
|
||||||
|
self.assertEqual(res[0], fw_rules)
|
||||||
|
self._compare_firewall_rule_lists(
|
||||||
|
fwp_id, fr, res[0]['firewall_rule_list'])
|
||||||
|
|
||||||
|
def test_get_firewall_for_tenant_without_rules(self):
|
||||||
|
tenant_id = 'test-tenant'
|
||||||
|
ctx = context.Context('', tenant_id)
|
||||||
|
with self.firewall_policy(tenant_id=tenant_id, no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs = self._get_test_firewall_attrs()
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with contextlib.nested(self.firewall(
|
||||||
|
firewall_policy_id=fwp_id,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
||||||
|
no_delete=True), self.firewall(
|
||||||
|
firewall_policy_id=fwp_id,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
admin_state_up=test_db_firewall.ADMIN_STATE_UP,
|
||||||
|
no_delete=True)) as fws:
|
||||||
|
fw_list = [fw['firewall'] for fw in fws]
|
||||||
|
f = self.callbacks.get_firewalls_for_tenant_without_rules
|
||||||
|
res = f(ctx, host='dummy')
|
||||||
|
for fw in res:
|
||||||
|
del fw['shared']
|
||||||
|
self.assertEqual(res, fw_list)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFirewallAgentApi(base.BaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestFirewallAgentApi, self).setUp()
|
||||||
|
self.addCleanup(mock.patch.stopall)
|
||||||
|
|
||||||
|
self.api = fwaas_plugin.FirewallAgentApi('topic', 'host')
|
||||||
|
self.mock_fanoutcast = mock.patch.object(self.api,
|
||||||
|
'fanout_cast').start()
|
||||||
|
self.mock_msg = mock.patch.object(self.api, 'make_msg').start()
|
||||||
|
|
||||||
|
def test_init(self):
|
||||||
|
self.assertEqual(self.api.topic, 'topic')
|
||||||
|
self.assertEqual(self.api.host, 'host')
|
||||||
|
|
||||||
|
def _call_test_helper(self, method_name):
|
||||||
|
rv = getattr(self.api, method_name)(mock.sentinel.context, 'test')
|
||||||
|
self.assertEqual(rv, self.mock_fanoutcast.return_value)
|
||||||
|
self.mock_fanoutcast.assert_called_once_with(
|
||||||
|
mock.sentinel.context,
|
||||||
|
self.mock_msg.return_value,
|
||||||
|
topic='topic'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mock_msg.assert_called_once_with(
|
||||||
|
method_name,
|
||||||
|
firewall='test',
|
||||||
|
host='host'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_create_firewall(self):
|
||||||
|
self._call_test_helper('create_firewall')
|
||||||
|
|
||||||
|
def test_update_firewall(self):
|
||||||
|
self._call_test_helper('update_firewall')
|
||||||
|
|
||||||
|
def test_delete_firewall(self):
|
||||||
|
self._call_test_helper('delete_firewall')
|
||||||
|
|
||||||
|
|
||||||
|
class TestFirewallPluginBase(test_db_firewall.TestFirewallDBPlugin):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestFirewallPluginBase, self).setUp(fw_plugin=FW_PLUGIN_KLASS)
|
||||||
|
self.callbacks = self.plugin.callbacks
|
||||||
|
|
||||||
|
def test_update_firewall(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
name = "new_firewall1"
|
||||||
|
attrs = self._get_test_firewall_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP) as firewall:
|
||||||
|
fw_id = firewall['firewall']['id']
|
||||||
|
res = self.callbacks.set_firewall_status(ctx, fw_id,
|
||||||
|
const.ACTIVE)
|
||||||
|
data = {'firewall': {'name': name}}
|
||||||
|
req = self.new_update_request('firewalls', data, fw_id)
|
||||||
|
res = self.deserialize(self.fmt,
|
||||||
|
req.get_response(self.ext_api))
|
||||||
|
attrs = self._replace_firewall_status(attrs,
|
||||||
|
const.PENDING_CREATE,
|
||||||
|
const.PENDING_UPDATE)
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(res['firewall'][k], v)
|
||||||
|
|
||||||
|
def test_update_firewall_fails_when_firewall_pending(self):
|
||||||
|
name = "new_firewall1"
|
||||||
|
attrs = self._get_test_firewall_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP) as firewall:
|
||||||
|
fw_id = firewall['firewall']['id']
|
||||||
|
data = {'firewall': {'name': name}}
|
||||||
|
req = self.new_update_request('firewalls', data, fw_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 409)
|
||||||
|
|
||||||
|
def test_update_firewall_policy_fails_when_firewall_pending(self):
|
||||||
|
name = "new_firewall1"
|
||||||
|
attrs = self._get_test_firewall_attrs(name)
|
||||||
|
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP):
|
||||||
|
data = {'firewall_policy': {'name': name}}
|
||||||
|
req = self.new_update_request('firewall_policies',
|
||||||
|
data, fwp_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 409)
|
||||||
|
|
||||||
|
def test_update_firewall_rule_fails_when_firewall_pending(self):
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall_rule(name='fwr1', no_delete=True) as fr:
|
||||||
|
fr_id = fr['firewall_rule']['id']
|
||||||
|
fw_rule_ids = [fr_id]
|
||||||
|
data = {'firewall_policy':
|
||||||
|
{'firewall_rules': fw_rule_ids}}
|
||||||
|
req = self.new_update_request('firewall_policies', data,
|
||||||
|
fwp_id)
|
||||||
|
req.get_response(self.ext_api)
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP,
|
||||||
|
no_delete=True):
|
||||||
|
data = {'firewall_rule': {'protocol': 'udp'}}
|
||||||
|
req = self.new_update_request('firewall_rules',
|
||||||
|
data, fr_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 409)
|
||||||
|
|
||||||
|
def test_delete_firewall(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
attrs = self._get_test_firewall_attrs()
|
||||||
|
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP) as firewall:
|
||||||
|
fw_id = firewall['firewall']['id']
|
||||||
|
attrs = self._replace_firewall_status(attrs,
|
||||||
|
const.PENDING_CREATE,
|
||||||
|
const.PENDING_DELETE)
|
||||||
|
req = self.new_delete_request('firewalls', fw_id)
|
||||||
|
req.get_response(self.ext_api)
|
||||||
|
fw_db = self.plugin._get_firewall(ctx, fw_id)
|
||||||
|
for k, v in attrs.iteritems():
|
||||||
|
self.assertEqual(fw_db[k], v)
|
||||||
|
|
||||||
|
def test_delete_firewall_after_agent_delete(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
no_delete=True) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
with ctx.session.begin(subtransactions=True):
|
||||||
|
req = self.new_delete_request('firewalls', fw_id)
|
||||||
|
res = req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(res.status_int, 204)
|
||||||
|
self.plugin.callbacks.firewall_deleted(ctx, fw_id)
|
||||||
|
self.assertRaises(firewall.FirewallNotFound,
|
||||||
|
self.plugin.get_firewall,
|
||||||
|
ctx, fw_id)
|
||||||
|
|
||||||
|
def test_make_firewall_dict_with_in_place_rules(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall_policy(no_delete=True) as fwp:
|
||||||
|
fwp_id = fwp['firewall_policy']['id']
|
||||||
|
with contextlib.nested(self.firewall_rule(name='fwr1',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr2',
|
||||||
|
no_delete=True),
|
||||||
|
self.firewall_rule(name='fwr3',
|
||||||
|
no_delete=True)) as fr:
|
||||||
|
fw_rule_ids = [r['firewall_rule']['id'] for r in fr]
|
||||||
|
data = {'firewall_policy':
|
||||||
|
{'firewall_rules': fw_rule_ids}}
|
||||||
|
req = self.new_update_request('firewall_policies', data,
|
||||||
|
fwp_id)
|
||||||
|
req.get_response(self.ext_api)
|
||||||
|
attrs = self._get_test_firewall_attrs()
|
||||||
|
attrs['firewall_policy_id'] = fwp_id
|
||||||
|
with self.firewall(firewall_policy_id=fwp_id,
|
||||||
|
admin_state_up=
|
||||||
|
test_db_firewall.ADMIN_STATE_UP,
|
||||||
|
no_delete=True) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
fw_rules = (
|
||||||
|
self.plugin._make_firewall_dict_with_rules(ctx,
|
||||||
|
fw_id)
|
||||||
|
)
|
||||||
|
self.assertEqual(fw_rules['id'], fw_id)
|
||||||
|
self._compare_firewall_rule_lists(
|
||||||
|
fwp_id, fr, fw_rules['firewall_rule_list'])
|
||||||
|
|
||||||
|
def test_make_firewall_dict_with_in_place_rules_no_policy(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
with self.firewall(no_delete=True) as fw:
|
||||||
|
fw_id = fw['firewall']['id']
|
||||||
|
fw_rules = self.plugin._make_firewall_dict_with_rules(ctx, fw_id)
|
||||||
|
self.assertEquals(fw_rules['firewall_rule_list'], [])
|
552
neutron/tests/unit/test_extension_firewall.py
Normal file
552
neutron/tests/unit/test_extension_firewall.py
Normal file
@ -0,0 +1,552 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 Big Switch Networks, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the spec
|
||||||
|
#
|
||||||
|
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo.config import cfg
|
||||||
|
from webob import exc
|
||||||
|
import webtest
|
||||||
|
|
||||||
|
from neutron.api import extensions
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
from neutron.common import config
|
||||||
|
from neutron.extensions import firewall
|
||||||
|
from neutron import manager
|
||||||
|
from neutron.openstack.common import uuidutils
|
||||||
|
from neutron.plugins.common import constants
|
||||||
|
from neutron.tests import base
|
||||||
|
from neutron.tests.unit import test_api_v2
|
||||||
|
from neutron.tests.unit import test_extensions
|
||||||
|
from neutron.tests.unit import testlib_api
|
||||||
|
|
||||||
|
|
||||||
|
_uuid = uuidutils.generate_uuid
|
||||||
|
_get_path = test_api_v2._get_path
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallTestExtensionManager(object):
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
# Add the resources to the global attribute map
|
||||||
|
# This is done here as the setup process won't
|
||||||
|
# initialize the main API router which extends
|
||||||
|
# the global attribute map
|
||||||
|
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||||
|
firewall.RESOURCE_ATTRIBUTE_MAP)
|
||||||
|
return firewall.Firewall.get_resources()
|
||||||
|
|
||||||
|
def get_actions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_request_extensions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallExtensionTestCase(testlib_api.WebTestCase):
|
||||||
|
fmt = 'json'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(FirewallExtensionTestCase, self).setUp()
|
||||||
|
plugin = 'neutron.extensions.firewall.FirewallPluginBase'
|
||||||
|
# Ensure 'stale' patched copies of the plugin are never returned
|
||||||
|
manager.NeutronManager._instance = None
|
||||||
|
|
||||||
|
# Ensure existing ExtensionManager is not used
|
||||||
|
extensions.PluginAwareExtensionManager._instance = None
|
||||||
|
|
||||||
|
# Create the default configurations
|
||||||
|
args = ['--config-file', test_api_v2.etcdir('neutron.conf.test')]
|
||||||
|
config.parse(args)
|
||||||
|
|
||||||
|
# Stubbing core plugin with Firewall plugin
|
||||||
|
cfg.CONF.set_override('core_plugin', plugin)
|
||||||
|
cfg.CONF.set_override('service_plugins', [plugin])
|
||||||
|
|
||||||
|
self._plugin_patcher = mock.patch(plugin, autospec=True)
|
||||||
|
self.plugin = self._plugin_patcher.start()
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_plugin_type.return_value = constants.FIREWALL
|
||||||
|
|
||||||
|
ext_mgr = FirewallTestExtensionManager()
|
||||||
|
self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
|
self.api = webtest.TestApp(self.ext_mdw)
|
||||||
|
super(FirewallExtensionTestCase, self).setUp()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self._plugin_patcher.stop()
|
||||||
|
self.api = None
|
||||||
|
self.plugin = None
|
||||||
|
cfg.CONF.reset()
|
||||||
|
super(FirewallExtensionTestCase, self).tearDown()
|
||||||
|
|
||||||
|
def _test_entity_delete(self, entity):
|
||||||
|
"""Does the entity deletion based on naming convention."""
|
||||||
|
entity_id = _uuid()
|
||||||
|
path_prefix = 'fw/'
|
||||||
|
|
||||||
|
if entity == 'firewall_policy':
|
||||||
|
entity_plural = 'firewall_policies'
|
||||||
|
else:
|
||||||
|
entity_plural = entity + 's'
|
||||||
|
|
||||||
|
res = self.api.delete(_get_path(path_prefix + entity_plural,
|
||||||
|
id=entity_id, fmt=self.fmt))
|
||||||
|
delete_entity = getattr(self.plugin.return_value, "delete_" + entity)
|
||||||
|
delete_entity.assert_called_with(mock.ANY, entity_id)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_create_firewall(self):
|
||||||
|
fw_id = _uuid()
|
||||||
|
data = {'firewall': {'description': 'descr_firewall1',
|
||||||
|
'name': 'firewall1',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'firewall_policy_id': _uuid(),
|
||||||
|
'shared': False,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
return_value = copy.copy(data['firewall'])
|
||||||
|
return_value.update({'id': fw_id})
|
||||||
|
# since 'shared' is hidden
|
||||||
|
del return_value['shared']
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_firewall.return_value = return_value
|
||||||
|
res = self.api.post(_get_path('fw/firewalls', fmt=self.fmt),
|
||||||
|
self.serialize(data),
|
||||||
|
content_type='application/%s' % self.fmt)
|
||||||
|
instance.create_firewall.assert_called_with(mock.ANY,
|
||||||
|
firewall=data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall', res)
|
||||||
|
self.assertEqual(res['firewall'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_list(self):
|
||||||
|
fw_id = _uuid()
|
||||||
|
return_value = [{'tenant_id': _uuid(),
|
||||||
|
'id': fw_id}]
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_firewalls.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('fw/firewalls', fmt=self.fmt))
|
||||||
|
|
||||||
|
instance.get_firewalls.assert_called_with(mock.ANY,
|
||||||
|
fields=mock.ANY,
|
||||||
|
filters=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
|
||||||
|
def test_firewall_get(self):
|
||||||
|
fw_id = _uuid()
|
||||||
|
return_value = {'tenant_id': _uuid(),
|
||||||
|
'id': fw_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_firewall.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('fw/firewalls',
|
||||||
|
id=fw_id, fmt=self.fmt))
|
||||||
|
|
||||||
|
instance.get_firewall.assert_called_with(mock.ANY,
|
||||||
|
fw_id,
|
||||||
|
fields=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall', res)
|
||||||
|
self.assertEqual(res['firewall'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_update(self):
|
||||||
|
fw_id = _uuid()
|
||||||
|
update_data = {'firewall': {'name': 'new_name'}}
|
||||||
|
return_value = {'tenant_id': _uuid(),
|
||||||
|
'id': fw_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.update_firewall.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.put(_get_path('fw/firewalls', id=fw_id,
|
||||||
|
fmt=self.fmt),
|
||||||
|
self.serialize(update_data))
|
||||||
|
|
||||||
|
instance.update_firewall.assert_called_with(mock.ANY, fw_id,
|
||||||
|
firewall=update_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall', res)
|
||||||
|
self.assertEqual(res['firewall'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_delete(self):
|
||||||
|
self._test_entity_delete('firewall')
|
||||||
|
|
||||||
|
def _test_create_firewall_rule(self, src_port, dst_port):
|
||||||
|
rule_id = _uuid()
|
||||||
|
data = {'firewall_rule': {'description': 'descr_firewall_rule1',
|
||||||
|
'name': 'rule1',
|
||||||
|
'shared': False,
|
||||||
|
'protocol': 'tcp',
|
||||||
|
'ip_version': 4,
|
||||||
|
'source_ip_address': '192.168.0.1',
|
||||||
|
'destination_ip_address': '127.0.0.1',
|
||||||
|
'source_port': src_port,
|
||||||
|
'destination_port': dst_port,
|
||||||
|
'action': 'allow',
|
||||||
|
'enabled': True,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
expected_ret_val = copy.copy(data['firewall_rule'])
|
||||||
|
expected_ret_val['source_port'] = str(src_port)
|
||||||
|
expected_ret_val['destination_port'] = str(dst_port)
|
||||||
|
expected_call_args = copy.copy(expected_ret_val)
|
||||||
|
expected_ret_val['id'] = rule_id
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_firewall_rule.return_value = expected_ret_val
|
||||||
|
res = self.api.post(_get_path('fw/firewall_rules', fmt=self.fmt),
|
||||||
|
self.serialize(data),
|
||||||
|
content_type='application/%s' % self.fmt)
|
||||||
|
instance.create_firewall_rule.assert_called_with(mock.ANY,
|
||||||
|
firewall_rule=
|
||||||
|
{'firewall_rule':
|
||||||
|
expected_call_args})
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall_rule', res)
|
||||||
|
self.assertEqual(res['firewall_rule'], expected_ret_val)
|
||||||
|
|
||||||
|
def test_create_firewall_rule_with_integer_ports(self):
|
||||||
|
self._test_create_firewall_rule(1, 10)
|
||||||
|
|
||||||
|
def test_create_firewall_rule_with_string_ports(self):
|
||||||
|
self._test_create_firewall_rule('1', '10')
|
||||||
|
|
||||||
|
def test_create_firewall_rule_with_port_range(self):
|
||||||
|
self._test_create_firewall_rule('1:20', '30:40')
|
||||||
|
|
||||||
|
def test_firewall_rule_list(self):
|
||||||
|
rule_id = _uuid()
|
||||||
|
return_value = [{'tenant_id': _uuid(),
|
||||||
|
'id': rule_id}]
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_firewall_rules.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('fw/firewall_rules', fmt=self.fmt))
|
||||||
|
|
||||||
|
instance.get_firewall_rules.assert_called_with(mock.ANY,
|
||||||
|
fields=mock.ANY,
|
||||||
|
filters=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
|
||||||
|
def test_firewall_rule_get(self):
|
||||||
|
rule_id = _uuid()
|
||||||
|
return_value = {'tenant_id': _uuid(),
|
||||||
|
'id': rule_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_firewall_rule.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('fw/firewall_rules',
|
||||||
|
id=rule_id, fmt=self.fmt))
|
||||||
|
|
||||||
|
instance.get_firewall_rule.assert_called_with(mock.ANY,
|
||||||
|
rule_id,
|
||||||
|
fields=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall_rule', res)
|
||||||
|
self.assertEqual(res['firewall_rule'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_rule_update(self):
|
||||||
|
rule_id = _uuid()
|
||||||
|
update_data = {'firewall_rule': {'action': 'deny'}}
|
||||||
|
return_value = {'tenant_id': _uuid(),
|
||||||
|
'id': rule_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.update_firewall_rule.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.put(_get_path('fw/firewall_rules', id=rule_id,
|
||||||
|
fmt=self.fmt),
|
||||||
|
self.serialize(update_data))
|
||||||
|
|
||||||
|
instance.update_firewall_rule.assert_called_with(mock.ANY,
|
||||||
|
rule_id,
|
||||||
|
firewall_rule=
|
||||||
|
update_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall_rule', res)
|
||||||
|
self.assertEqual(res['firewall_rule'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_rule_delete(self):
|
||||||
|
self._test_entity_delete('firewall_rule')
|
||||||
|
|
||||||
|
def test_create_firewall_policy(self):
|
||||||
|
policy_id = _uuid()
|
||||||
|
data = {'firewall_policy': {'description': 'descr_firewall_policy1',
|
||||||
|
'name': 'new_fw_policy1',
|
||||||
|
'shared': False,
|
||||||
|
'firewall_rules': [_uuid(), _uuid()],
|
||||||
|
'audited': False,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
return_value = copy.copy(data['firewall_policy'])
|
||||||
|
return_value.update({'id': policy_id})
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_firewall_policy.return_value = return_value
|
||||||
|
res = self.api.post(_get_path('fw/firewall_policies',
|
||||||
|
fmt=self.fmt),
|
||||||
|
self.serialize(data),
|
||||||
|
content_type='application/%s' % self.fmt)
|
||||||
|
instance.create_firewall_policy.assert_called_with(mock.ANY,
|
||||||
|
firewall_policy=
|
||||||
|
data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall_policy', res)
|
||||||
|
self.assertEqual(res['firewall_policy'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_policy_list(self):
|
||||||
|
policy_id = _uuid()
|
||||||
|
return_value = [{'tenant_id': _uuid(),
|
||||||
|
'id': policy_id}]
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_firewall_policies.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('fw/firewall_policies',
|
||||||
|
fmt=self.fmt))
|
||||||
|
|
||||||
|
instance.get_firewall_policies.assert_called_with(mock.ANY,
|
||||||
|
fields=mock.ANY,
|
||||||
|
filters=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
|
||||||
|
def test_firewall_policy_get(self):
|
||||||
|
policy_id = _uuid()
|
||||||
|
return_value = {'tenant_id': _uuid(),
|
||||||
|
'id': policy_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_firewall_policy.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('fw/firewall_policies',
|
||||||
|
id=policy_id, fmt=self.fmt))
|
||||||
|
|
||||||
|
instance.get_firewall_policy.assert_called_with(mock.ANY,
|
||||||
|
policy_id,
|
||||||
|
fields=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall_policy', res)
|
||||||
|
self.assertEqual(res['firewall_policy'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_policy_update(self):
|
||||||
|
policy_id = _uuid()
|
||||||
|
update_data = {'firewall_policy': {'audited': True}}
|
||||||
|
return_value = {'tenant_id': _uuid(),
|
||||||
|
'id': policy_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.update_firewall_policy.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.put(_get_path('fw/firewall_policies',
|
||||||
|
id=policy_id,
|
||||||
|
fmt=self.fmt),
|
||||||
|
self.serialize(update_data))
|
||||||
|
|
||||||
|
instance.update_firewall_policy.assert_called_with(mock.ANY,
|
||||||
|
policy_id,
|
||||||
|
firewall_policy=
|
||||||
|
update_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertIn('firewall_policy', res)
|
||||||
|
self.assertEqual(res['firewall_policy'], return_value)
|
||||||
|
|
||||||
|
def test_firewall_policy_delete(self):
|
||||||
|
self._test_entity_delete('firewall_policy')
|
||||||
|
|
||||||
|
def test_firewall_policy_insert_rule(self):
|
||||||
|
firewall_policy_id = _uuid()
|
||||||
|
firewall_rule_id = _uuid()
|
||||||
|
ref_firewall_rule_id = _uuid()
|
||||||
|
|
||||||
|
insert_data = {'firewall_rule_id': firewall_rule_id,
|
||||||
|
'insert_before': ref_firewall_rule_id,
|
||||||
|
'insert_after': None}
|
||||||
|
return_value = {'firewall_policy':
|
||||||
|
{'tenant_id': _uuid(),
|
||||||
|
'id': firewall_policy_id,
|
||||||
|
'firewall_rules': [ref_firewall_rule_id,
|
||||||
|
firewall_rule_id]}}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.insert_rule.return_value = return_value
|
||||||
|
|
||||||
|
path = _get_path('fw/firewall_policies', id=firewall_policy_id,
|
||||||
|
action="insert_rule",
|
||||||
|
fmt=self.fmt)
|
||||||
|
res = self.api.put(path, self.serialize(insert_data))
|
||||||
|
instance.insert_rule.assert_called_with(mock.ANY, firewall_policy_id,
|
||||||
|
insert_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertEqual(res, return_value)
|
||||||
|
|
||||||
|
def test_firewall_policy_remove_rule(self):
|
||||||
|
firewall_policy_id = _uuid()
|
||||||
|
firewall_rule_id = _uuid()
|
||||||
|
|
||||||
|
remove_data = {'firewall_rule_id': firewall_rule_id}
|
||||||
|
return_value = {'firewall_policy':
|
||||||
|
{'tenant_id': _uuid(),
|
||||||
|
'id': firewall_policy_id,
|
||||||
|
'firewall_rules': []}}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.remove_rule.return_value = return_value
|
||||||
|
|
||||||
|
path = _get_path('fw/firewall_policies', id=firewall_policy_id,
|
||||||
|
action="remove_rule",
|
||||||
|
fmt=self.fmt)
|
||||||
|
res = self.api.put(path, self.serialize(remove_data))
|
||||||
|
instance.remove_rule.assert_called_with(mock.ANY, firewall_policy_id,
|
||||||
|
remove_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
res = self.deserialize(res)
|
||||||
|
self.assertEqual(res, return_value)
|
||||||
|
|
||||||
|
|
||||||
|
class FirewallExtensionTestCaseXML(FirewallExtensionTestCase):
|
||||||
|
fmt = 'xml'
|
||||||
|
|
||||||
|
|
||||||
|
class TestFirewallAttributeValidators(base.BaseTestCase):
|
||||||
|
|
||||||
|
def test_validate_port_range(self):
|
||||||
|
msg = firewall._validate_port_range(None)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('10')
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range(10)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range(-1)
|
||||||
|
self.assertEqual(msg, "Invalid port '-1'")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('66000')
|
||||||
|
self.assertEqual(msg, "Invalid port '66000'")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('10:20')
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('1:65535')
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('0:65535')
|
||||||
|
self.assertEqual(msg, "Invalid port '0'")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('1:65536')
|
||||||
|
self.assertEqual(msg, "Invalid port '65536'")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('abc:efg')
|
||||||
|
self.assertEqual(msg, "Port 'abc' is not a valid number")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('1:efg')
|
||||||
|
self.assertEqual(msg, "Port 'efg' is not a valid number")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('-1:10')
|
||||||
|
self.assertEqual(msg, "Invalid port '-1'")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('66000:10')
|
||||||
|
self.assertEqual(msg, "Invalid port '66000'")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('10:66000')
|
||||||
|
self.assertEqual(msg, "Invalid port '66000'")
|
||||||
|
|
||||||
|
msg = firewall._validate_port_range('1:-10')
|
||||||
|
self.assertEqual(msg, "Invalid port '-10'")
|
||||||
|
|
||||||
|
def test_validate_ip_or_subnet_or_none(self):
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(None)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none('1.1.1.1')
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none('1.1.1.0/24')
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
ip_addr = '1111.1.1.1'
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(ip_addr)
|
||||||
|
self.assertEqual(msg, ("'%s' is not a valid IP address and "
|
||||||
|
"'%s' is not a valid IP subnet") % (ip_addr,
|
||||||
|
ip_addr))
|
||||||
|
|
||||||
|
ip_addr = '1.1.1.1 has whitespace'
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(ip_addr)
|
||||||
|
self.assertEqual(msg, ("'%s' is not a valid IP address and "
|
||||||
|
"'%s' is not a valid IP subnet") % (ip_addr,
|
||||||
|
ip_addr))
|
||||||
|
|
||||||
|
ip_addr = '111.1.1.1\twhitespace'
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(ip_addr)
|
||||||
|
self.assertEqual(msg, ("'%s' is not a valid IP address and "
|
||||||
|
"'%s' is not a valid IP subnet") % (ip_addr,
|
||||||
|
ip_addr))
|
||||||
|
|
||||||
|
ip_addr = '111.1.1.1\nwhitespace'
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(ip_addr)
|
||||||
|
self.assertEqual(msg, ("'%s' is not a valid IP address and "
|
||||||
|
"'%s' is not a valid IP subnet") % (ip_addr,
|
||||||
|
ip_addr))
|
||||||
|
|
||||||
|
# Valid - IPv4
|
||||||
|
cidr = "10.0.2.0/24"
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(cidr, None)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
# Valid - IPv6 without final octets
|
||||||
|
cidr = "fe80::/24"
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(cidr, None)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
# Valid - IPv6 with final octets
|
||||||
|
cidr = "fe80::0/24"
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(cidr, None)
|
||||||
|
self.assertEqual(msg, ("'%s' is not a valid IP address and "
|
||||||
|
"'%s' isn't a recognized IP subnet cidr,"
|
||||||
|
" 'fe80::/24' is recommended") % (cidr,
|
||||||
|
cidr))
|
||||||
|
|
||||||
|
cidr = "fe80::"
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(cidr, None)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
# Invalid - IPv6 with final octets, missing mask
|
||||||
|
cidr = "fe80::0"
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(cidr, None)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
# Invalid - Address format error
|
||||||
|
cidr = 'invalid'
|
||||||
|
msg = firewall._validate_ip_or_subnet_or_none(cidr, None)
|
||||||
|
self.assertEqual(msg, ("'%s' is not a valid IP address and "
|
||||||
|
"'%s' is not a valid IP subnet") % (cidr,
|
||||||
|
cidr))
|
Loading…
x
Reference in New Issue
Block a user