neutron-fwaas/neutron_fwaas/tests/unit/services/firewall/service_drivers/agents/test_agents.py

658 lines
28 KiB
Python

# Copyright 2016
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron import extensions as neutron_extensions
from neutron.tests.unit.extensions import test_l3
from neutron_lib import constants as nl_constants
from neutron_lib import context
from neutron_lib.exceptions import firewall_v2 as f_exc
from neutron_lib.plugins import directory
from oslo_config import cfg
from neutron_fwaas._i18n import _
from neutron_fwaas.db.firewall.v2.firewall_db_v2 import FirewallGroup
from neutron_fwaas.services.firewall.service_drivers.agents import agents
from neutron_fwaas.tests import base
from neutron_fwaas.tests.unit.services.firewall import test_fwaas_plugin_v2
FIREWALL_AGENT_PLUGIN = ('neutron_fwaas.services.firewall.service_drivers.'
'agents.agents')
FIREWALL_AGENT_PLUGIN_KLASS = FIREWALL_AGENT_PLUGIN + '.FirewallAgentDriver'
DELETEFW_PATH = (FIREWALL_AGENT_PLUGIN + '.FirewallAgentApi.'
'delete_firewall_group')
class FakeAgentApi(agents.FirewallAgentCallbacks):
"""
This class used to mock the AgentAPI delete method inherits from
FirewallCallbacks because it needs access to the firewall_deleted method.
The delete_firewall method belongs to the FirewallAgentApi, which has
no access to the firewall_deleted method normally because it's not
responsible for deleting the firewall from the DB. However, it needs
to in the unit tests since there is no agent to call back.
"""
def __init__(self):
return
def delete_firewall_group(self, context, firewall_group, **kwargs):
self.plugin = directory.get_plugin('FIREWALL_V2')
self.firewall_db = self.plugin.driver.firewall_db
self.firewall_group_deleted(context, firewall_group['id'], **kwargs)
class TestFirewallAgentApi(base.BaseTestCase):
def setUp(self):
super(TestFirewallAgentApi, self).setUp()
self.api = agents.FirewallAgentApi('topic', 'host')
def test_init(self):
self.assertEqual('topic', self.api.client.target.topic)
self.assertEqual('host', self.api.host)
def _call_test_helper(self, method_name):
with mock.patch.object(self.api.client, 'cast') as rpc_mock, \
mock.patch.object(self.api.client, 'prepare') as prepare_mock:
prepare_mock.return_value = self.api.client
getattr(self.api, method_name)(mock.sentinel.context, 'test')
prepare_args = {'fanout': True}
prepare_mock.assert_called_once_with(**prepare_args)
rpc_mock.assert_called_once_with(mock.sentinel.context, method_name,
firewall_group='test', host='host')
def test_create_firewall_group(self):
self._call_test_helper('create_firewall_group')
def test_update_firewall_group(self):
self._call_test_helper('update_firewall_group')
def test_delete_firewall_group(self):
self._call_test_helper('delete_firewall_group')
class TestAgentDriver(test_fwaas_plugin_v2.FirewallPluginV2TestCase,
test_l3.L3NatTestCaseMixin):
def setUp(self):
self._mock_agentapi_del_fw_p = mock.patch(
DELETEFW_PATH, create=True,
new=FakeAgentApi().delete_firewall_group,
)
self.agentapi_del_fw_p = self._mock_agentapi_del_fw_p.start()
self.addCleanup(self._mock_agentapi_del_fw_p.stop)
self._mock_get_client = mock.patch.object(agents.n_rpc, 'get_client')
self._mock_get_client.start()
self.addCleanup(self._mock_get_client.stop)
mock.patch.object(agents.n_rpc, 'Connection').start()
l3_plugin_str = ('neutron.tests.unit.extensions.test_l3.'
'TestL3NatServicePlugin')
l3_plugin = {'l3_plugin_name': l3_plugin_str}
super(TestAgentDriver, self).setUp(
service_provider=FIREWALL_AGENT_PLUGIN_KLASS,
extra_service_plugins=l3_plugin,
extra_extension_paths=neutron_extensions.__path__)
self.db = self.plugin.driver.firewall_db
self.callbacks = agents.FirewallAgentCallbacks(self.db)
router_distributed_opts = [
cfg.BoolOpt(
'router_distributed',
default=False,
help=_("System-wide flag to determine the type of router "
"that tenants can create. Only admin can override.")),
]
cfg.CONF.register_opts(router_distributed_opts)
@property
def _self_context(self):
return context.Context('', self._tenant_id)
def _get_test_firewall_group_attrs(self, name,
status=nl_constants.INACTIVE):
return super(TestAgentDriver, self)._get_test_firewall_group_attrs(
name, status=status)
def test_set_firewall_group_status(self):
ctx = context.get_admin_context()
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
ingress_firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP
) as fwg:
fwg_id = fwg['firewall_group']['id']
res = self.callbacks.set_firewall_group_status(ctx, fwg_id,
nl_constants.ACTIVE)
fwg_db = self.plugin.get_firewall_group(ctx, fwg_id)
self.assertEqual(nl_constants.ACTIVE, fwg_db['status'])
self.assertTrue(res)
res = self.callbacks.set_firewall_group_status(ctx, fwg_id,
nl_constants.ERROR)
fwg_db = self.plugin.get_firewall_group(ctx, fwg_id)
self.assertEqual(nl_constants.ERROR, fwg_db['status'])
self.assertFalse(res)
def test_firewall_group_deleted(self):
ctx = context.get_admin_context()
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
ingress_firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP,
do_delete=False
) as fwg:
fwg_id = fwg['firewall_group']['id']
with ctx.session.begin(subtransactions=True):
fwg_db = self.db._get_firewall_group(ctx, fwg_id)
fwg_db['status'] = nl_constants.PENDING_DELETE
observed = self.callbacks.firewall_group_deleted(ctx, fwg_id)
self.assertTrue(observed)
self.assertRaises(f_exc.FirewallGroupNotFound,
self.plugin.get_firewall_group,
ctx, fwg_id)
def test_firewall_group_deleted_concurrently(self):
ctx = context.get_admin_context()
alt_ctx = context.get_admin_context()
_get_firewall_group = self.db._get_firewall_group
def getdelete(context, fwg_id):
fwg_db = _get_firewall_group(context, fwg_id)
# NOTE(cby): Use a different session to simulate a concurrent del
with alt_ctx.session.begin(subtransactions=True):
alt_ctx.session.query(FirewallGroup).filter_by(
id=fwg_id).delete()
return fwg_db
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP,
do_delete=False
) as fwg:
fwg_id = fwg['firewall_group']['id']
with ctx.session.begin(subtransactions=True):
fwg_db = self.db._get_firewall_group(ctx, fwg_id)
fwg_db['status'] = nl_constants.PENDING_DELETE
ctx.session.flush()
with mock.patch.object(
self.db, '_get_firewall_group', side_effect=getdelete
):
observed = self.callbacks.firewall_group_deleted(
ctx, fwg_id)
self.assertTrue(observed)
self.assertRaises(f_exc.FirewallGroupNotFound,
self.plugin.get_firewall_group,
ctx, fwg_id)
def test_firewall_group_deleted_not_found(self):
ctx = context.get_admin_context()
observed = self.callbacks.firewall_group_deleted(
ctx, 'notfound')
self.assertTrue(observed)
def test_firewall_group_deleted_error(self):
ctx = context.get_admin_context()
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
firewall_policy_id=fwp_id,
admin_state_up=self.ADMIN_STATE_UP,
) as fwg:
fwg_id = fwg['firewall_group']['id']
observed = self.callbacks.firewall_group_deleted(
ctx, fwg_id)
self.assertFalse(observed)
fwg_db = self.db._get_firewall_group(ctx, fwg_id)
self.assertEqual(nl_constants.ERROR, fwg_db['status'])
def test_create_firewall_group_ports_not_specified(self):
"""neutron firewall-create test-policy """
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
def test_create_firewall_group_with_ports(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
def test_create_firewall_group_with_ports_on_diff_routers(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r2, \
self.subnet() as s3:
body = self._router_interface_action(
'add',
r2['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
fwg_ports = [port_id1, port_id2, port_id3]
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
def test_create_firewall_group_with_ports_no_policy(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
def test_update_firewall_group_with_new_ports_no_policy(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2, \
self.subnet(cidr='30.0.0.0/24') as s3:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
data = {'firewall_group': {'ports': [port_id2, port_id3]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context)
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(sorted([port_id2, port_id3]),
sorted(res['firewall_group']['ports']))
self.assertEqual(nl_constants.INACTIVE,
res['firewall_group']['status'])
def test_update_firewall_group_with_new_ports_status_pending(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2, \
self.subnet(cidr='30.0.0.0/24') as s3:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
body = self._router_interface_action(
'add',
r['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
data = {'firewall_group': {'ports': [port_id2, port_id3]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(409, res.status_int)
def test_update_firewall_group_with_new_ports_status_active(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1, \
self.subnet(cidr='20.0.0.0/24') as s2, \
self.subnet(cidr='30.0.0.0/24') as s3:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
body = self._router_interface_action(
'add',
r['router']['id'],
s3['subnet']['id'],
None)
port_id3 = body['port_id']
with self.firewall_policy() as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
ctx = context.get_admin_context()
self.callbacks.set_firewall_group_status(ctx,
fwg1['firewall_group']['id'], nl_constants.ACTIVE)
data = {'firewall_group': {'ports': [port_id2, port_id3]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context)
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(sorted([port_id2, port_id3]),
sorted(res['firewall_group']['ports']))
def test_update_firewall_rule_on_active_fwg(self):
name = "new_firewall_rule1"
attrs = self._get_test_firewall_rule_attrs(name)
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
with self.firewall_rule() as fwr:
with self.firewall_policy(
firewall_rules=[fwr['firewall_rule']['id']]) as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=[port_id1],
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
ctx = context.get_admin_context()
self.callbacks.set_firewall_group_status(ctx,
fwg1['firewall_group']['id'], nl_constants.ACTIVE)
data = {'firewall_rule': {'name': name}}
req = self.new_update_request('firewall_rules', data,
fwr['firewall_rule']['id'])
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
for k, v in attrs.items():
self.assertEqual(v, res['firewall_rule'][k])
def test_update_firewall_rule_on_pending_create_fwg(self):
"""update should fail"""
name = "new_firewall_rule1"
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet() as s1:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
with self.firewall_rule() as fwr:
with self.firewall_policy(
firewall_rules=[fwr['firewall_rule']['id']]) as fwp:
fwp_id = fwp['firewall_policy']['id']
with self.firewall_group(
name='test',
ingress_firewall_policy_id=fwp_id,
egress_firewall_policy_id=fwp_id, ports=[port_id1],
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.PENDING_CREATE,
fwg1['firewall_group']['status'])
data = {'firewall_rule': {'name': name}}
req = self.new_update_request('firewall_rules', data,
fwr['firewall_rule']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(409, res.status_int)
def test_update_firewall_group_with_non_exist_ports(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r, \
self.subnet(cidr='30.0.0.0/24') as s:
body = self._router_interface_action(
'add',
r['router']['id'],
s['subnet']['id'],
None)
port_id1 = body['port_id']
foo_port_id = 'caef152d-b118-4b9b-bc77-800661bf082d'
fwg_ports = [port_id1]
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
data = {'firewall_group': {'ports': [foo_port_id]}}
req = self.new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'])
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual('PortNotFound',
res['NeutronError']['type'])
def test_update_firewall_group_with_ports_and_policy(self):
"""neutron firewall_group create test-policy """
with self.router(name='router1', admin_state_up=True,
tenant_id=self._tenant_id) as r,\
self.subnet() as s1,\
self.subnet(cidr='20.0.0.0/24') as s2:
body = self._router_interface_action(
'add',
r['router']['id'],
s1['subnet']['id'],
None)
port_id1 = body['port_id']
body = self._router_interface_action(
'add',
r['router']['id'],
s2['subnet']['id'],
None)
port_id2 = body['port_id']
fwg_ports = [port_id1, port_id2]
with self.firewall_rule() as fwr:
with self.firewall_policy(
firewall_rules=[fwr['firewall_rule']['id']]) as fwp:
with self.firewall_group(
name='test',
default_policy=False,
ports=fwg_ports,
admin_state_up=True) as fwg1:
self.assertEqual(nl_constants.INACTIVE,
fwg1['firewall_group']['status'])
fwp_id = fwp["firewall_policy"]["id"]
data = {'firewall_group': {'ports': fwg_ports}}
req = (self.
new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context))
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(nl_constants.INACTIVE,
res['firewall_group']['status'])
data = {'firewall_group': {
'ingress_firewall_policy_id': fwp_id}}
req = (self.
new_update_request('firewall_groups', data,
fwg1['firewall_group']['id'],
context=self._self_context))
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
self.assertEqual(nl_constants.PENDING_UPDATE,
res['firewall_group']['status'])
def test_create_firewall_group_with_dvr(self):
cfg.CONF.set_override('router_distributed', True)
attrs = self._get_test_firewall_group_attrs("firewall1")
self._test_create_firewall_group(attrs)
def test_create_firewall_group(self):
attrs = self._get_test_firewall_group_attrs("firewall1")
self._test_create_firewall_group(attrs)
def test_create_firewall_group_with_empty_ports(self):
attrs = self._get_test_firewall_group_attrs("fwg1")
attrs['ports'] = []
self._test_create_firewall_group(attrs)