diff --git a/neutron_fwaas/db/firewall/v2/firewall_db_v2.py b/neutron_fwaas/db/firewall/v2/firewall_db_v2.py index f0f15167f..c6fa1de61 100644 --- a/neutron_fwaas/db/firewall/v2/firewall_db_v2.py +++ b/neutron_fwaas/db/firewall/v2/firewall_db_v2.py @@ -758,7 +758,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): count = context.session.query( FirewallGroup).filter_by(id=id).update(fwg) if not count: - raise fw_ext.FirewallNotFound(firewall_id=id) + raise fw_ext.FirewallGroupNotFound(firewall_id=id) return self.get_firewall_group(context, id) def update_firewall_group_status(self, context, id, status, not_in=None): @@ -782,7 +782,7 @@ class Firewall_db_mixin_v2(fw_ext.Firewallv2PluginBase, base_db.CommonDbMixin): count = context.session.query( FirewallGroup).filter_by(id=id).delete() if not count: - raise fw_ext.FirewallNotFound(firewall_id=id) + raise fw_ext.FirewallGroupNotFound(firewall_id=id) def get_firewall_group(self, context, id, fields=None): LOG.debug("get_firewall_group() called") diff --git a/neutron_fwaas/tests/contrib/gate_hook.sh b/neutron_fwaas/tests/contrib/gate_hook.sh index d15c30c52..4cfff8322 100755 --- a/neutron_fwaas/tests/contrib/gate_hook.sh +++ b/neutron_fwaas/tests/contrib/gate_hook.sh @@ -80,5 +80,7 @@ EOF if [[ "$IS_GATE" != "True" ]]; then if [[ "$INSTALL_MYSQL_ONLY" == "True" ]]; then _install_databases nopg + else + _install_databases fi fi diff --git a/neutron_fwaas/tests/contrib/gate_hook_tempest.sh b/neutron_fwaas/tests/contrib/gate_hook_tempest.sh new file mode 100755 index 000000000..8384f9254 --- /dev/null +++ b/neutron_fwaas/tests/contrib/gate_hook_tempest.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -ex + +FWAAS_VERSION=$1 + +GATE_DEST=$BASE/new +GATE_HOOKS=$GATE_DEST/neutron-fwaas/neutron_fwaas/tests/contrib/hooks +DEVSTACK_PATH=$GATE_DEST/devstack +LOCAL_CONF=$DEVSTACK_PATH/local.conf + +# Inject config from hook into localrc +function load_rc_hook { + local hook="$1" + config=$(cat $GATE_HOOKS/$hook) + export DEVSTACK_LOCAL_CONFIG+=" +# generated from hook '$hook' +${config} +" +} + +load_rc_hook api_extensions-base +load_rc_hook api_extensions-${FWAAS_VERSION} +$BASE/new/devstack-gate/devstack-vm-gate.sh diff --git a/neutron_fwaas/tests/contrib/hooks/api_extensions-base b/neutron_fwaas/tests/contrib/hooks/api_extensions-base new file mode 100644 index 000000000..02be81851 --- /dev/null +++ b/neutron_fwaas/tests/contrib/hooks/api_extensions-base @@ -0,0 +1 @@ +NETWORK_API_EXTENSIONS=agent,binding,dhcp_agent_scheduler,external-net,ext-gw-mode,extra_dhcp_opts,quotas,router,security-group,subnet_allocation,network-ip-availability,auto-allocated-topology,timestamp_core,tag,service-type,rbac-policies,standard-attr-description,pagination,sorting,project-id diff --git a/neutron_fwaas/tests/contrib/hooks/api_extensions-legacy b/neutron_fwaas/tests/contrib/hooks/api_extensions-legacy new file mode 100644 index 000000000..98c9f4adc --- /dev/null +++ b/neutron_fwaas/tests/contrib/hooks/api_extensions-legacy @@ -0,0 +1 @@ +NETWORK_API_EXTENSIONS+=,fwaas,fwaasrouterinsertion diff --git a/neutron_fwaas/tests/contrib/hooks/api_extensions-v1 b/neutron_fwaas/tests/contrib/hooks/api_extensions-v1 new file mode 100644 index 000000000..98c9f4adc --- /dev/null +++ b/neutron_fwaas/tests/contrib/hooks/api_extensions-v1 @@ -0,0 +1 @@ +NETWORK_API_EXTENSIONS+=,fwaas,fwaasrouterinsertion diff --git a/neutron_fwaas/tests/contrib/hooks/api_extensions-v2 b/neutron_fwaas/tests/contrib/hooks/api_extensions-v2 new file mode 100644 index 000000000..7a7e7f950 --- /dev/null +++ b/neutron_fwaas/tests/contrib/hooks/api_extensions-v2 @@ -0,0 +1 @@ +NETWORK_API_EXTENSIONS+=,fwaas_v2 diff --git a/neutron_fwaas/tests/tempest_plugin/services/v2_client.py b/neutron_fwaas/tests/tempest_plugin/services/v2_client.py new file mode 100644 index 000000000..66604188e --- /dev/null +++ b/neutron_fwaas/tests/tempest_plugin/services/v2_client.py @@ -0,0 +1,123 @@ +# Copyright (c) 2016 +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from tempest.lib import exceptions as lib_exc +from tempest.lib.services.network import base + + +class FirewallGroupsClient(base.BaseNetworkClient): + + def create_firewall_group(self, **kwargs): + uri = '/fwaas/firewall_groups' + post_data = {'firewall_group': kwargs} + return self.create_resource(uri, post_data) + + def update_firewall_group(self, firewall_group_id, **kwargs): + uri = '/fwaas/firewall_groups/%s' % firewall_group_id + post_data = {'firewall_group': kwargs} + return self.update_resource(uri, post_data) + + def show_firewall_group(self, firewall_group_id, **fields): + uri = '/fwaas/firewall_groups/%s' % firewall_group_id + return self.show_resource(uri, **fields) + + def delete_firewall_group(self, firewall_group_id): + uri = '/fwaas/firewall_groups/%s' % firewall_group_id + return self.delete_resource(uri) + + def list_firewall_groups(self, **filters): + uri = '/fwaas/firewall_groups' + return self.list_resources(uri, **filters) + + def is_resource_deleted(self, id): + try: + self.show_firewall_group(id) + except lib_exc.NotFound: + return True + return False + + @property + def resource_type(self): + """Returns the primary type of resource this client works with.""" + return 'firewall_group' + + +class FirewallRulesClient(base.BaseNetworkClient): + + def create_firewall_rule(self, **kwargs): + uri = '/fwaas/firewall_rules' + post_data = {'firewall_rule': kwargs} + return self.create_resource(uri, post_data) + + def update_firewall_rule(self, firewall_rule_id, **kwargs): + uri = '/fwaas/firewall_rules/%s' % firewall_rule_id + post_data = {'firewall_rule': kwargs} + return self.update_resource(uri, post_data) + + def show_firewall_rule(self, firewall_rule_id, **fields): + uri = '/fwaas/firewall_rules/%s' % firewall_rule_id + return self.show_resource(uri, **fields) + + def delete_firewall_rule(self, firewall_rule_id): + uri = '/fwaas/firewall_rules/%s' % firewall_rule_id + return self.delete_resource(uri) + + def list_firewall_rules(self, **filters): + uri = '/fwaas/firewall_rules' + return self.list_resources(uri, **filters) + + +class FirewallPoliciesClient(base.BaseNetworkClient): + + def create_firewall_policy(self, **kwargs): + uri = '/fwaas/firewall_policies' + post_data = {'firewall_policy': kwargs} + return self.create_resource(uri, post_data) + + def update_firewall_policy(self, firewall_policy_id, **kwargs): + uri = '/fwaas/firewall_policies/%s' % firewall_policy_id + post_data = {'firewall_policy': kwargs} + return self.update_resource(uri, post_data) + + def show_firewall_policy(self, firewall_policy_id, **fields): + uri = '/fwaas/firewall_policies/%s' % firewall_policy_id + return self.show_resource(uri, **fields) + + def delete_firewall_policy(self, firewall_policy_id): + uri = '/fwaas/firewall_policies/%s' % firewall_policy_id + return self.delete_resource(uri) + + def list_firewall_policies(self, **filters): + uri = '/fwaas/firewall_policies' + return self.list_resources(uri, **filters) + + def insert_firewall_rule_in_policy(self, firewall_policy_id, + firewall_rule_id, insert_after='', + insert_before=''): + uri = '/fwaas/firewall_policies/%s/insert_rule' % firewall_policy_id + data = { + 'firewall_rule_id': firewall_rule_id, + 'insert_after': insert_after, + 'insert_before': insert_before, + } + return self.update_resource(uri, data) + + def remove_firewall_rule_from_policy(self, firewall_policy_id, + firewall_rule_id): + uri = '/fwaas/firewall_policies/%s/remove_rule' % firewall_policy_id + data = { + 'firewall_rule_id': firewall_rule_id, + } + return self.update_resource(uri, data) diff --git a/neutron_fwaas/tests/tempest_plugin/tests/api/test_fwaasv2_extensions.py b/neutron_fwaas/tests/tempest_plugin/tests/api/test_fwaasv2_extensions.py new file mode 100644 index 000000000..482f7bd19 --- /dev/null +++ b/neutron_fwaas/tests/tempest_plugin/tests/api/test_fwaasv2_extensions.py @@ -0,0 +1,310 @@ +# Copyright 2016 +# +# 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 netaddr +import six + +from tempest import config +from tempest import exceptions +from tempest.lib.common.utils import data_utils +from tempest.lib import exceptions as lib_exc +from tempest import test + +from neutron_fwaas.tests.tempest_plugin.tests.api import v2_base + +CONF = config.CONF + + +class FWaaSv2ExtensionTestJSON(v2_base.BaseFWaaSTest): + + """ + Tests the following operations in the Neutron API using the REST client for + Neutron: + + List firewall rules + Create firewall rule + Update firewall rule + Delete firewall rule + Show firewall rule + List firewall policies + Create firewall policy + Update firewall policy + Insert firewall rule to policy + Remove firewall rule from policy + Insert firewall rule after/before rule in policy + Update firewall policy audited attribute + Delete firewall policy + Show firewall policy + List firewall group + Create firewall group + Update firewall group + Delete firewall group + Show firewall group + """ + + @classmethod + def resource_setup(cls): + super(FWaaSv2ExtensionTestJSON, cls).resource_setup() + if not test.is_extension_enabled('fwaas_v2', 'network'): + msg = "FWaaS v2 Extension not enabled." + raise cls.skipException(msg) + + def setUp(self): + super(FWaaSv2ExtensionTestJSON, self).setUp() + self.fw_rule_1 = self.create_firewall_rule(action="allow", + protocol="tcp") + self.fw_rule_2 = self.create_firewall_rule(action="deny", + protocol="udp") + self.fw_policy_1 = self.create_firewall_policy( + firewall_rules=[self.fw_rule_1['id']]) + self.fw_policy_2 = self.create_firewall_policy( + firewall_rules=[self.fw_rule_2['id']]) + + def _create_router_interfaces(self): + network_1 = self.create_network() + network_2 = self.create_network() + + cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) + mask_bits = CONF.network.project_network_mask_bits + + subnet_cidr_1 = list(cidr.subnet(mask_bits))[-1] + subnet_cidr_2 = list(cidr.subnet(mask_bits))[-2] + subnet_1 = self.create_subnet(network_1, cidr=subnet_cidr_1, + mask_bits=mask_bits) + subnet_2 = self.create_subnet(network_2, cidr=subnet_cidr_2, + mask_bits=mask_bits) + + router = self.create_router( + data_utils.rand_name('router-'), + admin_state_up=True) + self.addCleanup(self._try_delete_router, router) + + intf_1 = self.routers_client.add_router_interface(router['id'], + subnet_id=subnet_1['id']) + intf_2 = self.routers_client.add_router_interface(router['id'], + subnet_id=subnet_2['id']) + + return intf_1, intf_2 + + def _try_delete_router(self, router): + # delete router, if it exists + try: + self.delete_router(router) + # if policy is not found, this means it was deleted in the test + except lib_exc.NotFound: + pass + + def _try_delete_policy(self, policy_id): + # delete policy, if it exists + try: + self.firewall_policies_client.delete_firewall_policy(policy_id) + # if policy is not found, this means it was deleted in the test + except lib_exc.NotFound: + pass + + def _try_delete_rule(self, rule_id): + # delete rule, if it exists + try: + self.firewall_rules_client.delete_firewall_rule(rule_id) + # if rule is not found, this means it was deleted in the test + except lib_exc.NotFound: + pass + + def _try_delete_firewall_group(self, fwg_id): + # delete firewall group, if it exists + try: + self.firewall_groups_client.delete_firewall_group(fwg_id) + # if firewall is not found, this means it was deleted in the test + except lib_exc.NotFound: + pass + + self.firewall_groups_client.wait_for_resource_deletion(fwg_id) + + def _wait_until_ready(self, fwg_id): + target_states = ('ACTIVE', 'CREATED') + + def _wait(): + firewall_group = self.firewall_groups_client.show_firewall_group( + fwg_id) + firewall_group = firewall_group['firewall_group'] + return firewall_group['status'] in target_states + + if not test.call_until_true(_wait, CONF.network.build_timeout, + CONF.network.build_interval): + m = ("Timed out waiting for firewall_group %s to reach %s " + "state(s)" % + (fwg_id, target_states)) + raise exceptions.TimeoutException(m) + + @test.idempotent_id('ddccfa87-4af7-48a6-9e50-0bd0ad1348cb') + def test_list_firewall_rules(self): + # List firewall rules + fw_rules = self.firewall_rules_client.list_firewall_rules() + fw_rules = fw_rules['firewall_rules'] + self.assertIn((self.fw_rule_1['id'], + self.fw_rule_1['name'], + self.fw_rule_1['action'], + self.fw_rule_1['protocol'], + self.fw_rule_1['ip_version'], + self.fw_rule_1['enabled']), + [(m['id'], + m['name'], + m['action'], + m['protocol'], + m['ip_version'], + m['enabled']) for m in fw_rules]) + + @test.idempotent_id('ffc009fa-cd17-4029-8025-c4b81a7dd923') + def test_create_update_delete_firewall_rule(self): + # Create firewall rule + body = self.firewall_rules_client.create_firewall_rule( + name=data_utils.rand_name("fw-rule"), + action="allow", + protocol="tcp") + fw_rule_id = body['firewall_rule']['id'] + + # Update firewall rule + body = self.firewall_rules_client.update_firewall_rule(fw_rule_id, + public=True) + self.assertTrue(body["firewall_rule"]['public']) + + # Delete firewall rule + self.firewall_rules_client.delete_firewall_rule(fw_rule_id) + # Confirm deletion + fw_rules = self.firewall_rules_client.list_firewall_rules() + self.assertNotIn(fw_rule_id, + [m['id'] for m in fw_rules['firewall_rules']]) + + @test.idempotent_id('76b07afc-444e-4bb9-abec-9b8c5f994dcd') + def test_show_firewall_rule(self): + # show a created firewall rule + fw_rule = self.firewall_rules_client.show_firewall_rule( + self.fw_rule_1['id']) + for key, value in six.iteritems(fw_rule['firewall_rule']): + self.assertEqual(self.fw_rule_1[key], value) + + @test.idempotent_id('f6b83902-746f-4e74-9403-2ec9899583a3') + def test_list_firewall_policies(self): + fw_policies = self.firewall_policies_client.list_firewall_policies() + fw_policies = fw_policies['firewall_policies'] + self.assertIn((self.fw_policy_1['id'], + self.fw_policy_1['name'], + self.fw_policy_1['firewall_rules']), + [(m['id'], + m['name'], + m['firewall_rules']) for m in fw_policies]) + + @test.idempotent_id('6ef9bd02-7349-4d61-8d1f-80479f64d904') + def test_create_update_delete_firewall_policy(self): + # Create firewall policy + body = self.firewall_policies_client.create_firewall_policy( + name=data_utils.rand_name("fw-policy")) + fw_policy_id = body['firewall_policy']['id'] + self.addCleanup(self._try_delete_policy, fw_policy_id) + + # Update firewall policy + body = self.firewall_policies_client.update_firewall_policy( + fw_policy_id, + public=True, + name="updated_policy") + updated_fw_policy = body["firewall_policy"] + self.assertTrue(updated_fw_policy['public']) + self.assertEqual("updated_policy", updated_fw_policy['name']) + + # Delete firewall policy + self.firewall_policies_client.delete_firewall_policy(fw_policy_id) + # Confirm deletion + fw_policies = self.firewall_policies_client.list_firewall_policies() + fw_policies = fw_policies['firewall_policies'] + self.assertNotIn(fw_policy_id, [m['id'] for m in fw_policies]) + + @test.idempotent_id('164381de-61f4-483f-9a5a-48105b8e70e2') + def test_show_firewall_policy(self): + # show a created firewall policy + fw_policy = self.firewall_policies_client.show_firewall_policy( + self.fw_policy_1['id']) + fw_policy = fw_policy['firewall_policy'] + for key, value in six.iteritems(fw_policy): + self.assertEqual(self.fw_policy_1[key], value) + + @test.idempotent_id('48dfcd75-3924-479d-bb65-b3ed33397663') + def test_create_show_delete_firewall_group(self): + # create router and add interfaces + intf_1, intf_2 = self._create_router_interfaces() + + # Create firewall_group + body = self.firewall_groups_client.create_firewall_group( + name=data_utils.rand_name("firewall_group"), + ingress_firewall_policy_id=self.fw_policy_1['id'], + egress_firewall_policy_id=self.fw_policy_2['id'], + ports=[intf_1['port_id'], intf_2['port_id']]) + created_firewall_group = body['firewall_group'] + fwg_id = created_firewall_group['id'] + self.addCleanup(self._try_delete_firewall_group, fwg_id) + + # Wait for the firewall resource to become ready + self._wait_until_ready(fwg_id) + + # show created firewall_group + firewall_group = self.firewall_groups_client.show_firewall_group( + fwg_id) + fwg = firewall_group['firewall_group'] + + for key, value in six.iteritems(fwg): + if key == 'status': + continue + self.assertEqual(created_firewall_group[key], value) + + # list firewall_groups + firewall_groups = self.firewall_groups_client.list_firewall_groups() + fwgs = firewall_groups['firewall_groups'] + self.assertIn((created_firewall_group['id'], + created_firewall_group['name'], + created_firewall_group['ingress_firewall_policy_id'], + created_firewall_group['egress_firewall_policy_id']), + [(m['id'], + m['name'], + m['ingress_firewall_policy_id'], + m['egress_firewall_policy_id']) for m in fwgs]) + + # Delete firewall_group + self.firewall_groups_client.delete_firewall_group(fwg_id) + + @test.idempotent_id('e021baab-d4f7-4bad-b382-bde4946e0e0b') + def test_update_firewall_group(self): + # create router and add interfaces + intf_1, intf_2 = self._create_router_interfaces() + + # Create firewall_group + body = self.firewall_groups_client.create_firewall_group( + name=data_utils.rand_name("firewall_group"), + ingress_firewall_policy_id=self.fw_policy_1['id'], + egress_firewall_policy_id=self.fw_policy_2['id'], + ports=[intf_1['port_id']]) + created_firewall_group = body['firewall_group'] + fwg_id = created_firewall_group['id'] + self.addCleanup(self._try_delete_firewall_group, fwg_id) + + # Wait for the firewall resource to become ready + self._wait_until_ready(fwg_id) + + # Update firewall group + body = self.firewall_groups_client.update_firewall_group( + fwg_id, + ports=[intf_2['port_id']]) + updated_fwg = body["firewall_group"] + self.assertEqual([intf_2['port_id']], updated_fwg['ports']) + + # Delete firewall_group + self.firewall_groups_client.delete_firewall_group(fwg_id) diff --git a/neutron_fwaas/tests/tempest_plugin/tests/api/v2_base.py b/neutron_fwaas/tests/tempest_plugin/tests/api/v2_base.py new file mode 100644 index 000000000..a932705d7 --- /dev/null +++ b/neutron_fwaas/tests/tempest_plugin/tests/api/v2_base.py @@ -0,0 +1,21 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from tempest.api.network import base + +from neutron_fwaas.tests.tempest_plugin.tests import fwaas_v2_client + + +class BaseFWaaSTest(fwaas_v2_client.FWaaSClientMixin, base.BaseNetworkTest): + pass diff --git a/neutron_fwaas/tests/tempest_plugin/tests/fwaas_v2_client.py b/neutron_fwaas/tests/tempest_plugin/tests/fwaas_v2_client.py new file mode 100644 index 000000000..7dc9bb2f1 --- /dev/null +++ b/neutron_fwaas/tests/tempest_plugin/tests/fwaas_v2_client.py @@ -0,0 +1,125 @@ +# Copyright (c) 2015 Midokura SARL +# 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 time + +from tempest import config +from tempest import exceptions +from tempest.lib.common.utils import data_utils +from tempest.lib.common.utils import test_utils +from tempest.lib import exceptions as lib_exc + +from neutron_fwaas.tests.tempest_plugin.services import v2_client +from neutron_lib import constants as nl_constants + +CONF = config.CONF + + +class FWaaSClientMixin(object): + + @classmethod + def resource_setup(cls): + super(FWaaSClientMixin, cls).resource_setup() + manager = cls.manager + cls.firewall_groups_client = v2_client.FirewallGroupsClient( + manager.auth_provider, + CONF.network.catalog_type, + CONF.network.region or CONF.identity.region, + endpoint_type=CONF.network.endpoint_type, + build_interval=CONF.network.build_interval, + build_timeout=CONF.network.build_timeout, + **manager.default_params) + cls.firewall_policies_client = v2_client.FirewallPoliciesClient( + manager.auth_provider, + CONF.network.catalog_type, + CONF.network.region or CONF.identity.region, + endpoint_type=CONF.network.endpoint_type, + build_interval=CONF.network.build_interval, + build_timeout=CONF.network.build_timeout, + **manager.default_params) + cls.firewall_rules_client = v2_client.FirewallRulesClient( + manager.auth_provider, + CONF.network.catalog_type, + CONF.network.region or CONF.identity.region, + endpoint_type=CONF.network.endpoint_type, + build_interval=CONF.network.build_interval, + build_timeout=CONF.network.build_timeout, + **manager.default_params) + + def create_firewall_rule(self, **kwargs): + body = self.firewall_rules_client.create_firewall_rule( + name=data_utils.rand_name("fw-rule"), + **kwargs) + fw_rule = body['firewall_rule'] + self.addCleanup(test_utils.call_and_ignore_notfound_exc, + self.firewall_rules_client.delete_firewall_rule, + fw_rule['id']) + return fw_rule + + def create_firewall_policy(self, **kwargs): + body = self.firewall_policies_client.create_firewall_policy( + name=data_utils.rand_name("fw-policy"), + **kwargs) + fw_policy = body['firewall_policy'] + self.addCleanup(test_utils.call_and_ignore_notfound_exc, + self.firewall_policies_client.delete_firewall_policy, + fw_policy['id']) + return fw_policy + + def create_firewall_group(self, **kwargs): + body = self.firewall_groups_client.create_firewall_group( + name=data_utils.rand_name("fwg"), + **kwargs) + fwg = body['firewall_group'] + self.addCleanup(test_utils.call_and_ignore_notfound_exc, + self.delete_firewall_and_wait, + fwg['id']) + return fwg + + def delete_firewall_group_and_wait(self, firewall_group_id): + self.firewall_groups_client.delete_firewall_group(firewall_group_id) + self._wait_firewall_group_while(firewall_group_id, + [nl_constants.PENDING_DELETE], + not_found_ok=True) + + def _wait_firewall_group_ready(self, firewall_group_id): + self._wait_firewall_group_while(firewall_group_id, + [nl_constants.PENDING_CREATE, + nl_constants.PENDING_UPDATE]) + + def _wait_firewall_group_while(self, firewall_group_id, statuses, + not_found_ok=False): + start = int(time.time()) + if not_found_ok: + expected_exceptions = (lib_exc.NotFound) + else: + expected_exceptions = () + while True: + try: + fwg = self.firewall_groups_client.show_firewall_group( + firewall_group_id) + except expected_exceptions: + break + status = fwg['firewall_group']['status'] + if status not in statuses: + break + if int(time.time()) - start >= self.firewalls_client.build_timeout: + msg = ("Firewall Group %(firewall_group)s failed to reach " + "non PENDING status (current %(status)s)") % { + "firewall_group": firewall_group_id, + "status": status, + } + raise exceptions.TimeoutException(msg) + time.sleep(1)