diff options
29 files changed, 313 insertions, 210 deletions
diff --git a/.zuul.yaml b/.zuul.yaml index ef999cb9a..8039ad9fb 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -72,7 +72,7 @@ minimal_image_ref: ${DEFAULT_IMAGE_NAME:-cirros-0.3.6-x86_64-disk} instance_type: m1.heat_int minimal_instance_type: m1.heat_micro - image_ref: Fedora-Cloud-Base-33-1.2.x86_64 + image_ref: Fedora-Cloud-Base-36-1.5.x86_64 hidden_stack_tag: hidden heat_config_notify_script: /opt/stack/heat-agents/heat-config/bin/heat-config-notify boot_config_env: /opt/stack/heat-templates/hot/software-config/boot-config/test_image_env.yaml @@ -181,9 +181,9 @@ - ^releasenotes/.*$ - project: + queue: heat templates: - openstack-cover-jobs - - openstack-lower-constraints-jobs - openstack-python3-zed-jobs - openstack-python3-zed-jobs-arm64 - periodic-stable-jobs @@ -196,11 +196,7 @@ - heat-functional - heat-functional-legacy gate: - queue: heat jobs: - grenade-heat-multinode - heat-functional - heat-functional-legacy - experimental: - jobs: - - tripleo-ci-centos-8-scenario002-standalone diff --git a/bindep.txt b/bindep.txt index 7071c188b..55d97b80b 100644 --- a/bindep.txt +++ b/bindep.txt @@ -6,7 +6,6 @@ mariadb-server [platform:redhat] postgresql build-essential [platform:dpkg] -python-dev [platform:dpkg] python3-all-dev [platform:dpkg] libxml2-dev [platform:dpkg] libxslt1-dev [platform:dpkg] @@ -19,7 +18,6 @@ mysql-client [platform:dpkg] postgresql-client [platform:dpkg] gcc [platform:rpm] -python-devel [platform:rpm] python3-devel [platform:fedora platform:suse] python3 [platform:suse] libxml2-devel [platform:rpm] diff --git a/devstack/lib/heat b/devstack/lib/heat index d95e15266..dcd59b6f4 100644 --- a/devstack/lib/heat +++ b/devstack/lib/heat @@ -449,7 +449,7 @@ function configure_tempest_for_heat { # Skip LoadBalancerv2Test as deprecated neutron-lbaas service is not enabled iniset $TEMPEST_CONFIG heat_plugin skip_functional_test_list 'LoadBalancerv2Test, NotificationTest' - openstack flavor show m1.heat_int || openstack flavor create m1.heat_int --ram 512 --disk 4 + openstack flavor show m1.heat_int || openstack flavor create m1.heat_int --ram 512 --disk 10 openstack flavor show m1.heat_micro || openstack flavor create m1.heat_micro --ram 128 --disk 1 export OS_CLOUD=devstack @@ -463,14 +463,14 @@ function configure_tempest_for_heat { source /etc/ci/mirror_info.sh fi HEAT_TEST_FEDORA_IMAGE_UPSTREAM=https://download.fedoraproject.org/pub/fedora/linux - HEAT_TEST_FEDORA_IMAGE_PATH=releases/33/Cloud/x86_64/images/Fedora-Cloud-Base-33-1.2.x86_64.qcow2 + HEAT_TEST_FEDORA_IMAGE_PATH=releases/36/Cloud/x86_64/images/Fedora-Cloud-Base-36-1.5.x86_64.qcow2 if curl --output /dev/null --silent --head --fail "${NODEPOOL_FEDORA_MIRROR}/${HEAT_TEST_FEDORA_IMAGE_PATH}"; then export HEAT_TEST_FEDORA_IMAGE="${NODEPOOL_FEDORA_MIRROR}/${HEAT_TEST_FEDORA_IMAGE_PATH}" else export HEAT_TEST_FEDORA_IMAGE="${HEAT_TEST_FEDORA_IMAGE_UPSTREAM}/${HEAT_TEST_FEDORA_IMAGE_PATH}" fi TOKEN=$(openstack token issue -c id -f value) - local image_exists=$( openstack image list | grep "Fedora-Cloud-Base-33-1.2.x86_64" ) + local image_exists=$( openstack image list | grep "Fedora-Cloud-Base-36-1.5.x86_64" ) if [[ -z $image_exists ]]; then if is_service_enabled g-api; then upload_image $HEAT_TEST_FEDORA_IMAGE $TOKEN diff --git a/doc/source/getting_started/on_devstack.rst b/doc/source/getting_started/on_devstack.rst index 29581390d..64d607ab2 100644 --- a/doc/source/getting_started/on_devstack.rst +++ b/doc/source/getting_started/on_devstack.rst @@ -51,8 +51,8 @@ a VM image that heat can launch. To do that add the following to `[[local|localrc]]` section of `local.conf`:: IMAGE_URL_SITE="https://download.fedoraproject.org" - IMAGE_URL_PATH="/pub/fedora/linux/releases/33/Cloud/x86_64/images/" - IMAGE_URL_FILE="Fedora-Cloud-Base-33-1.2.x86_64.qcow2" + IMAGE_URL_PATH="/pub/fedora/linux/releases/36/Cloud/x86_64/images/" + IMAGE_URL_FILE="Fedora-Cloud-Base-36-1.5.x86_64.qcow2" IMAGE_URLS+=","$IMAGE_URL_SITE$IMAGE_URL_PATH$IMAGE_URL_FILE URLs for any cloud image may be specified, but fedora images from F20 contain diff --git a/heat/api/openstack/v1/software_configs.py b/heat/api/openstack/v1/software_configs.py index 41f9486e4..c27da4fe7 100644 --- a/heat/api/openstack/v1/software_configs.py +++ b/heat/api/openstack/v1/software_configs.py @@ -43,6 +43,14 @@ class SoftwareConfigController(object): except ValueError as e: raise exc.HTTPBadRequest(str(e)) + def _extract_int_param(self, name, value, + allow_zero=True, allow_negative=False): + try: + return param_utils.extract_int(name, value, + allow_zero, allow_negative) + except ValueError as e: + raise exc.HTTPBadRequest(str(e)) + def _index(self, req, use_admin_cnxt=False): param_types = { 'limit': util.PARAM_TYPE_SINGLE, @@ -50,6 +58,10 @@ class SoftwareConfigController(object): } params = util.get_allowed_params(req.params, param_types) + key = rpc_api.PARAM_LIMIT + if key in params: + params[key] = self._extract_int_param(key, params[key]) + if use_admin_cnxt: cnxt = context.get_admin_context() else: diff --git a/heat/common/environment_util.py b/heat/common/environment_util.py index 8a6ed4393..eb3b8cde1 100644 --- a/heat/common/environment_util.py +++ b/heat/common/environment_util.py @@ -12,6 +12,7 @@ # under the License. import collections +from oslo_log import log as logging from oslo_serialization import jsonutils from heat.common import environment_format as env_fmt @@ -21,15 +22,22 @@ from heat.common.i18n import _ ALLOWED_PARAM_MERGE_STRATEGIES = (OVERWRITE, MERGE, DEEP_MERGE) = ( 'overwrite', 'merge', 'deep_merge') +LOG = logging.getLogger(__name__) -def get_param_merge_strategy(merge_strategies, param_key): + +def get_param_merge_strategy(merge_strategies, param_key, + available_strategies=None): + if not available_strategies: + available_strategies = {} if merge_strategies is None: return OVERWRITE env_default = merge_strategies.get('default', OVERWRITE) + merge_strategy = merge_strategies.get( + param_key, available_strategies.get( + param_key, env_default)) - merge_strategy = merge_strategies.get(param_key, env_default) if merge_strategy in ALLOWED_PARAM_MERGE_STRATEGIES: return merge_strategy @@ -114,7 +122,7 @@ def merge_parameters(old, new, param_schemata, strategies_in_file, # if key not in param_schemata ignore it if key in param_schemata and value is not None: param_merge_strategy = get_param_merge_strategy( - strategies_in_file, key) + strategies_in_file, key, available_strategies) if key not in available_strategies: new_strategies[key] = param_merge_strategy @@ -124,12 +132,15 @@ def merge_parameters(old, new, param_schemata, strategies_in_file, param=key, env_file=env_file) if param_merge_strategy == DEEP_MERGE: + LOG.debug("Deep Merging Parameter: %s", key) param_merge(key, value, param_schemata[key], deep_merge=True) elif param_merge_strategy == MERGE: + LOG.debug("Merging Parameter: %s", key) param_merge(key, value, param_schemata[key]) else: + LOG.debug("Overriding Parameter: %s", key) old[key] = value return old, new_strategies diff --git a/heat/common/pluginutils.py b/heat/common/pluginutils.py index c4da0ec06..1fc9618ee 100644 --- a/heat/common/pluginutils.py +++ b/heat/common/pluginutils.py @@ -18,9 +18,17 @@ LOG = logging.getLogger(__name__) def log_fail_msg(manager, entrypoint, exception): - LOG.warning('Encountered exception while loading %(module_name)s: ' - '"%(message)s". Not using %(name)s.', - {'module_name': entrypoint.module, - 'message': getattr(exception, 'message', - str(exception)), - 'name': entrypoint.name}) + # importlib.metadata in Python 3.8 is quite old and the EntryPoint class + # does not have module. This logic is required to workaround AttributeError + # caused by that old implementation. + if hasattr(entrypoint, 'module'): + LOG.warning('Encountered exception while loading %(module_name)s: ' + '"%(message)s". Not using %(name)s.', + {'module_name': entrypoint.module, + 'message': getattr(exception, 'message', str(exception)), + 'name': entrypoint.name}) + else: + LOG.warning('Encountered exception: "%(message)s". ' + 'Not using %(name)s.', + {'message': getattr(exception, 'message', str(exception)), + 'name': entrypoint.name}) diff --git a/heat/engine/resources/openstack/neutron/net.py b/heat/engine/resources/openstack/neutron/net.py index d0d2ebd8d..156c03042 100644 --- a/heat/engine/resources/openstack/neutron/net.py +++ b/heat/engine/resources/openstack/neutron/net.py @@ -33,11 +33,11 @@ class Net(neutron.NeutronResource): PROPERTIES = ( NAME, VALUE_SPECS, ADMIN_STATE_UP, TENANT_ID, SHARED, DHCP_AGENT_IDS, PORT_SECURITY_ENABLED, QOS_POLICY, - DNS_DOMAIN, TAGS, + DNS_DOMAIN, AVAILABILITY_ZONE_HINTS, TAGS, ) = ( 'name', 'value_specs', 'admin_state_up', 'tenant_id', 'shared', 'dhcp_agent_ids', 'port_security_enabled', 'qos_policy', - 'dns_domain', 'tags', + 'dns_domain', 'availability_zone_hints', 'tags', ) ATTRIBUTES = ( @@ -118,6 +118,12 @@ class Net(neutron.NeutronResource): update_allowed=True, support_status=support.SupportStatus(version='7.0.0') ), + AVAILABILITY_ZONE_HINTS: properties.Schema( + properties.Schema.LIST, + _('Availability zone candidates for the network. It requires the ' + 'availability_zone extension to be available.'), + support_status=support.SupportStatus(version='19.0.0') + ), TAGS: properties.Schema( properties.Schema.LIST, _('The tags to be added to the network.'), diff --git a/heat/engine/resources/openstack/neutron/provider_net.py b/heat/engine/resources/openstack/neutron/provider_net.py index 9f5a038c7..899b29590 100644 --- a/heat/engine/resources/openstack/neutron/provider_net.py +++ b/heat/engine/resources/openstack/neutron/provider_net.py @@ -37,11 +37,13 @@ class ProviderNet(net.Net): PROPERTIES = ( NAME, PROVIDER_NETWORK_TYPE, PROVIDER_PHYSICAL_NETWORK, PROVIDER_SEGMENTATION_ID, ADMIN_STATE_UP, SHARED, - PORT_SECURITY_ENABLED, ROUTER_EXTERNAL, DNS_DOMAIN, TAGS, + PORT_SECURITY_ENABLED, ROUTER_EXTERNAL, DNS_DOMAIN, + AVAILABILITY_ZONE_HINTS, TAGS, ) = ( 'name', 'network_type', 'physical_network', 'segmentation_id', 'admin_state_up', 'shared', - 'port_security_enabled', 'router_external', 'dns_domain', 'tags', + 'port_security_enabled', 'router_external', 'dns_domain', + 'availability_zone_hints', 'tags', ) @@ -119,6 +121,13 @@ class ProviderNet(net.Net): update_allowed=True, support_status=support.SupportStatus(version='15.0.0') ), + AVAILABILITY_ZONE_HINTS: properties.Schema( + properties.Schema.LIST, + _('Availability zone candidates for the network. It requires the ' + 'availability_zone extension to be available.'), + update_allowed=True, + support_status=support.SupportStatus(version='19.0.0') + ), } attributes_schema = { diff --git a/heat/engine/resources/openstack/neutron/router.py b/heat/engine/resources/openstack/neutron/router.py index 1127a2c10..72f7dbbdd 100644 --- a/heat/engine/resources/openstack/neutron/router.py +++ b/heat/engine/resources/openstack/neutron/router.py @@ -35,10 +35,12 @@ class Router(neutron.NeutronResource): PROPERTIES = ( NAME, EXTERNAL_GATEWAY, VALUE_SPECS, ADMIN_STATE_UP, - L3_AGENT_ID, L3_AGENT_IDS, DISTRIBUTED, HA, TAGS, + L3_AGENT_ID, L3_AGENT_IDS, DISTRIBUTED, HA, AVAILABILITY_ZONE_HINTS, + TAGS, ) = ( 'name', 'external_gateway_info', 'value_specs', 'admin_state_up', - 'l3_agent_id', 'l3_agent_ids', 'distributed', 'ha', 'tags', + 'l3_agent_id', 'l3_agent_ids', 'distributed', 'ha', + 'availability_zone_hints', 'tags', ) _EXTERNAL_GATEWAY_KEYS = ( @@ -171,6 +173,13 @@ class Router(neutron.NeutronResource): 'do not support distributed and ha at the same time.'), support_status=support.SupportStatus(version='2015.1') ), + AVAILABILITY_ZONE_HINTS: properties.Schema( + properties.Schema.LIST, + _('Availability zone candidates for the router. It requires the ' + 'availability_zone extension to be available.'), + update_allowed=True, + support_status=support.SupportStatus(version='19.0.0') + ), TAGS: properties.Schema( properties.Schema.LIST, _('The tags to be added to the router.'), diff --git a/heat/tests/api/openstack_v1/test_software_configs.py b/heat/tests/api/openstack_v1/test_software_configs.py index c1516eda0..110bfaef5 100644 --- a/heat/tests/api/openstack_v1/test_software_configs.py +++ b/heat/tests/api/openstack_v1/test_software_configs.py @@ -47,6 +47,41 @@ class SoftwareConfigControllerTest(tools.ControllerTest, common.HeatTestCase): {'software_configs': []}, resp) @mock.patch.object(policy.Enforcer, 'enforce') + def test_index_limit_negative(self, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index') + params = {'limit': -1} + + with mock.patch.object( + self.controller.rpc_client, + 'list_software_configs', + return_value=[]) as mock_call: + req = self._get('/software_configs', params=params) + ex = self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.index, req, + tenant_id=self.tenant) + self.assertEqual("Value '-1' is invalid for 'limit' which only " + "accepts non-negative integer.", + str(ex)) + self.assertFalse(mock_call.called) + + @mock.patch.object(policy.Enforcer, 'enforce') + def test_index_limit_not_int(self, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index') + params = {'limit': 'not-an-int'} + + with mock.patch.object( + self.controller.rpc_client, + 'list_software_configs', + return_value=[]) as mock_call: + req = self._get('/software_configs', params=params) + ex = self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.index, req, + tenant_id=self.tenant) + self.assertEqual("Only integer is acceptable by 'limit'.", + str(ex)) + self.assertFalse(mock_call.called) + + @mock.patch.object(policy.Enforcer, 'enforce') def test_show(self, mock_enforce): self._mock_enforce_setup(mock_enforce, 'show') config_id = 'a45559cd-8736-4375-bc39-d6a7bb62ade2' diff --git a/heat/tests/api/openstack_v1/test_stacks.py b/heat/tests/api/openstack_v1/test_stacks.py index 48d1ebd61..6c1a46467 100644 --- a/heat/tests/api/openstack_v1/test_stacks.py +++ b/heat/tests/api/openstack_v1/test_stacks.py @@ -338,6 +338,20 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase): self.assertNotIn('balrog', engine_args) @mock.patch.object(rpc_client.EngineClient, 'call') + def test_index_limit_negative(self, mock_call, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index', True) + params = {'limit': -1} + req = self._get('/stacks', params=params) + + ex = self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.index, req, + tenant_id=self.tenant) + self.assertEqual("Value '-1' is invalid for 'limit' which only " + "accepts non-negative integer.", + str(ex)) + self.assertFalse(mock_call.called) + + @mock.patch.object(rpc_client.EngineClient, 'call') def test_index_limit_not_int(self, mock_call, mock_enforce): self._mock_enforce_setup(mock_enforce, 'index', True) params = {'limit': 'not-an-int'} @@ -1936,6 +1950,31 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase): version='1.36' ) + def test_update_timeout_negative(self, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'update', True) + identity = identifier.HeatIdentifier(self.tenant, 'wibble', '6') + template = {u'Foo': u'bar'} + parameters = {u'InstanceType': u'm1.xlarge'} + body = {'template': template, + 'parameters': parameters, + 'files': {}, + 'timeout_mins': -1} + + req = self._put('/stacks/%(stack_name)s/%(stack_id)s' % identity, + json.dumps(body)) + + mock_call = self.patchobject(rpc_client.EngineClient, 'call') + ex = self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.update, req, + tenant_id=identity.tenant, + stack_name=identity.stack_name, + stack_id=identity.stack_id, + body=body) + self.assertEqual("Value '-1' is invalid for 'timeout_mins' which only " + "accepts non-negative integer.", + str(ex)) + self.assertFalse(mock_call.called) + def test_update_timeout_not_int(self, mock_enforce): self._mock_enforce_setup(mock_enforce, 'update', True) identity = identifier.HeatIdentifier(self.tenant, 'wibble', '6') @@ -2149,6 +2188,31 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase): version='1.36' ) + def test_update_with_patch_timeout_negative(self, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'update_patch', True) + identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '6') + template = {u'Foo': u'bar'} + parameters = {u'InstanceType': u'm1.xlarge'} + body = {'template': template, + 'parameters': parameters, + 'files': {}, + 'timeout_mins': -1} + + req = self._patch('/stacks/%(stack_name)s/%(stack_id)s' % identity, + json.dumps(body)) + + mock_call = self.patchobject(rpc_client.EngineClient, 'call') + ex = self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.update_patch, req, + tenant_id=identity.tenant, + stack_name=identity.stack_name, + stack_id=identity.stack_id, + body=body) + self.assertEqual("Value '-1' is invalid for 'timeout_mins' which only " + "accepts non-negative integer.", + str(ex)) + self.assertFalse(mock_call.called) + def test_update_with_patch_timeout_not_int(self, mock_enforce): self._mock_enforce_setup(mock_enforce, 'update_patch', True) identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '6') diff --git a/heat/tests/openstack/neutron/test_neutron_net.py b/heat/tests/openstack/neutron/test_neutron_net.py index 63a68c582..f45479806 100644 --- a/heat/tests/openstack/neutron/test_neutron_net.py +++ b/heat/tests/openstack/neutron/test_neutron_net.py @@ -40,6 +40,8 @@ resources: - 28c25a04-3f73-45a7-a2b4-59e183943ddc port_security_enabled: False dns_domain: openstack.org. + availability_zone_hints: + - az1 value_specs: {'mtu': 1500} tags: - tag1 @@ -186,6 +188,7 @@ class NeutronNetTest(common.HeatTestCase): 'dns_domain': u'openstack.org.', 'shared': True, 'port_security_enabled': False, + 'availability_zone_hints': ['az1'], 'mtu': 1500} } ) diff --git a/heat/tests/openstack/neutron/test_neutron_provider_net.py b/heat/tests/openstack/neutron/test_neutron_provider_net.py index a528c4d4d..9909f160e 100644 --- a/heat/tests/openstack/neutron/test_neutron_provider_net.py +++ b/heat/tests/openstack/neutron/test_neutron_provider_net.py @@ -40,6 +40,8 @@ resources: segmentation_id: 101 router_external: False shared: true + availability_zone_hints: + - az1 tags: - tag1 - tag2 @@ -128,7 +130,8 @@ class NeutronProviderNetTest(common.HeatTestCase): 'provider:physical_network': 'physnet_1', 'provider:segmentation_id': '101', 'router:external': False, - 'shared': True + 'shared': True, + 'availability_zone_hints': ['az1'], } }) self.mockclient.replace_tag.assert_called_with( @@ -180,7 +183,8 @@ class NeutronProviderNetTest(common.HeatTestCase): 'provider:physical_network': 'physnet_1', 'provider:segmentation_id': '101', 'router:external': False, - 'shared': True} + 'shared': True, + 'availability_zone_hints': ['az1']} }) self.mockclient.replace_tag.assert_called_with( resource_type, @@ -243,6 +247,7 @@ class NeutronProviderNetTest(common.HeatTestCase): 'port_security_enabled': True, 'segmentation_id': None, 'router_external': False, + 'availability_zone_hints': [], 'tags': ['tag1', 'tag2'], } diff --git a/heat/tests/openstack/neutron/test_neutron_router.py b/heat/tests/openstack/neutron/test_neutron_router.py index 442668a2b..6c489301b 100644 --- a/heat/tests/openstack/neutron/test_neutron_router.py +++ b/heat/tests/openstack/neutron/test_neutron_router.py @@ -36,6 +36,8 @@ resources: properties: l3_agent_ids: - 792ff887-6c85-4a56-b518-23f24fa65581 + availability_zone_hints: + - az1 router_interface: type: OS::Neutron::RouterInterface @@ -262,6 +264,7 @@ class NeutronRouterTest(common.HeatTestCase): create_body = { 'router': { 'name': utils.PhysName(stack.name, 'router'), + 'availability_zone_hints': ['az1'], 'admin_state_up': True}} router_base_info = { 'router': { diff --git a/heat/tests/test_common_env_util.py b/heat/tests/test_common_env_util.py index dff4c9c3d..fca3a9b34 100644 --- a/heat/tests/test_common_env_util.py +++ b/heat/tests/test_common_env_util.py @@ -202,7 +202,13 @@ class TestMergeEnvironments(common.HeatTestCase): 'lst_value1': "merge", 'json_value1': "deep_merge"} + env3_merge_strategies = { + 'default': "overwrite", + 'lst_value1': "deep_merge", + 'json_value1': "merge"} + self.env_2['parameter_merge_strategies'] = merge_strategies + self.env_3['parameter_merge_strategies'] = env3_merge_strategies files = {'env_1': json.dumps(self.env_1), 'env_2': json.dumps(self.env_2), @@ -221,7 +227,12 @@ class TestMergeEnvironments(common.HeatTestCase): 'default': "overwrite", 'lst_value2': "merge"} + env4_merge_strategies = { + 'default': "overwrite", + 'lst_value2': "overwrite"} + self.env_2['parameter_merge_strategies'] = merge_strategies + self.env_4['parameter_merge_strategies'] = env4_merge_strategies files = {'env_1': json.dumps(self.env_1), 'env_2': json.dumps(self.env_2), diff --git a/heat/tests/test_common_pluginutils.py b/heat/tests/test_common_pluginutils.py new file mode 100644 index 000000000..7a6264543 --- /dev/null +++ b/heat/tests/test_common_pluginutils.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# +# 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 importlib.metadata as importlib_metadata +from unittest import mock + +from heat.common import pluginutils +from heat.tests import common + + +class TestPluginUtil(common.HeatTestCase): + + def test_log_fail_msg(self): + ep = importlib_metadata.EntryPoint( + name=None, group=None, + value='package.module:attr [extra1, extra2]') + + exc = Exception('Something went wrong') + pluginutils.log_fail_msg(mock.Mock(), ep, exc) + self.assertIn("Something went wrong", self.LOG.output) diff --git a/heat_integrationtests/cleanup_test_env.sh b/heat_integrationtests/cleanup_test_env.sh index 12791c9fd..8cc5fb1ce 100755 --- a/heat_integrationtests/cleanup_test_env.sh +++ b/heat_integrationtests/cleanup_test_env.sh @@ -30,4 +30,4 @@ openstack flavor delete m1.heat_int openstack flavor delete m1.heat_micro # delete the image created -openstack image delete Fedora-Cloud-Base-33-1.2.x86_64 +openstack image delete Fedora-Cloud-Base-36-1.5.x86_64 diff --git a/heat_integrationtests/prepare_test_env.sh b/heat_integrationtests/prepare_test_env.sh index 45b86e493..d4e440f73 100755 --- a/heat_integrationtests/prepare_test_env.sh +++ b/heat_integrationtests/prepare_test_env.sh @@ -46,7 +46,7 @@ function _config_iniset { iniset $conf_file heat_plugin instance_type m1.heat_int iniset $conf_file heat_plugin minimal_instance_type m1.heat_micro - iniset $conf_file heat_plugin image_ref Fedora-Cloud-Base-33-1.2.x86_64 + iniset $conf_file heat_plugin image_ref Fedora-Cloud-Base-36-1.5.x86_64 iniset $conf_file heat_plugin minimal_image_ref $default_image_name iniset $conf_file heat_plugin hidden_stack_tag hidden diff --git a/lower-constraints.txt b/lower-constraints.txt deleted file mode 100644 index fae3b3a64..000000000 --- a/lower-constraints.txt +++ /dev/null @@ -1,161 +0,0 @@ -alembic==0.9.8 -amqp==2.6.0 -aodhclient==0.9.0 -appdirs==1.4.3 -asn1crypto==0.24.0 -Babel==2.3.4 -bandit==1.1.0 -bcrypt==3.1.4 -cachetools==2.0.1 -certifi==2018.1.18 -cffi==1.14.0 -chardet==3.0.4 -cliff==2.11.0 -cmd2==0.8.1 -contextlib2==0.5.5 -coverage==4.0 -croniter==0.3.4 -cryptography==2.5 -ddt==1.4.1 -debtcollector==1.19.0 -decorator==4.3.0 -deprecation==2.0 -doc8==0.8.1 -docker-pycreds==0.2.2 -docker==3.1.1 -docutils==0.13.1 -dogpile.cache==0.6.5 -enum-compat==0.0.2 -eventlet==0.18.2 -extras==1.0.0 -fasteners==0.14.1 -fixtures==3.0.0 -flake8==3.7.0 -future==0.16.0 -futurist==1.6.0 -gitdb2==2.0.3 -GitPython==2.1.8 -greenlet==0.4.17 -idna==2.6 -iso8601==0.1.12 -Jinja2==2.10 -jmespath==0.9.3 -jsonpatch==1.21 -jsonpointer==2.0 -jsonschema==2.6.0 -keystoneauth1==3.18.0 -keystonemiddleware==5.1.0 -kombu==5.0.1 -linecache2==1.0.0 -lxml==4.5.0 -Mako==1.0.7 -MarkupSafe==1.1.1 -mccabe==0.6.0 -mock==3.0.3 -monotonic==1.4 -mox3==0.28.0 -msgpack==0.5.6 -msgpack-python==0.5.6 -munch==2.2.0 -netaddr==0.7.18 -netifaces==0.10.6 -neutron-lib==1.14.0 -openstacksdk==0.28.0 -os-client-config==1.29.0 -os-service-types==1.2.0 -osc-lib==1.10.0 -oslo.cache==1.26.0 -oslo.concurrency==3.26.0 -oslo.config==6.8.0 -oslo.context==2.22.0 -oslo.db==6.0.0 -oslo.i18n==3.20.0 -oslo.log==4.3.0 -oslo.messaging==5.29.0 -oslo.middleware==3.31.0 -oslo.policy==3.7.0 -oslo.reports==1.18.0 -oslo.serialization==2.25.0 -oslo.service==1.24.0 -oslo.upgradecheck==1.3.0 -oslo.utils==4.5.0 -oslo.versionedobjects==1.31.2 -oslotest==3.2.0 -osprofiler==1.4.0 -packaging==20.4 -paramiko==2.7.1 -Paste==2.0.3 -PasteDeploy==1.5.0 -pbr==3.1.1 -pika-pool==0.1.3 -pika==0.10.0 -ply==3.11 -prettytable==0.7.2 -psutil==5.4.3 -pyasn1==0.4.2 -pycadf==2.7.0 -pycparser==2.18 -Pygments==2.2.0 -pyinotify==0.9.6 -PyMySQL==0.8.0 -PyNaCl==1.2.1 -pyOpenSSL==17.5.0 -pyparsing==2.2.0 -pyperclip==1.6.0 -python-barbicanclient==4.5.2 -python-blazarclient===1.0.1 -python-cinderclient==3.3.0 -python-dateutil==2.7.0 -python-designateclient==2.7.0 -python-editor==1.0.3 -python-glanceclient==2.8.0 -python-heatclient==1.10.0 -python-ironicclient==2.8.0 -python-keystoneclient==3.8.0 -python-magnumclient==2.3.0 -python-manilaclient==1.16.0 -python-mimeparse==1.6.0 -python-mistralclient==3.1.0 -python-monascaclient==1.12.0 -python-neutronclient==6.14.0 -python-novaclient==9.1.0 -python-octaviaclient==1.8.0 -python-openstackclient==3.12.0 -python-saharaclient==1.4.0 -python-subunit==1.2.0 -python-swiftclient==3.2.0 -python-troveclient==2.2.0 -python-vitrageclient==2.7.0 -python-zaqarclient==1.3.0 -python-zunclient==3.4.0 -pytz==2013.6 -PyYAML==5.1 -repoze.lru==0.7 -requests==2.23.0 -requestsexceptions==1.4.0 -rfc3986==1.2.0 -Routes==2.3.1 -simplejson==3.13.2 -smmap2==2.0.3 -sqlalchemy-migrate==0.13.0 -SQLAlchemy==1.0.10 -sqlparse==0.2.4 -statsd==3.2.2 -stestr==2.0.0 -stevedore==3.1.0 -tempest==17.1.0 -Tempita==0.5.2 -tenacity==6.1.0 -testresources==2.0.0 -testscenarios==0.4 -testtools==2.2.0 -traceback2==1.4.0 -unittest2==1.1.0 -urllib3==1.22 -vine==1.1.4 -voluptuous==0.11.1 -warlock==1.2.0 -WebOb==1.7.1 -websocket-client==0.47.0 -wrapt==1.10.11 -yaql==1.1.3 diff --git a/releasenotes/notes/availability_zone_hints_Neutron_network_router-d01df1463193d9e6.yaml b/releasenotes/notes/availability_zone_hints_Neutron_network_router-d01df1463193d9e6.yaml new file mode 100644 index 000000000..83ee5628f --- /dev/null +++ b/releasenotes/notes/availability_zone_hints_Neutron_network_router-d01df1463193d9e6.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds the 'availability_zone_hints' property for the OS::Neutron::Router, + OS::Neutron::Net and OS::Neutron::ProviderNet resources. diff --git a/releasenotes/notes/drop-python-3-6-and-3-7-69dcd178c443e177.yaml b/releasenotes/notes/drop-python-3-6-and-3-7-69dcd178c443e177.yaml new file mode 100644 index 000000000..3d5e4e3d3 --- /dev/null +++ b/releasenotes/notes/drop-python-3-6-and-3-7-69dcd178c443e177.yaml @@ -0,0 +1,5 @@ +--- +upgrade: + - | + Python 3.6 & 3.7 support has been dropped. The minimum version of Python now + supported is Python 3.8.
\ No newline at end of file diff --git a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po index 68b70f458..279a46cfd 100644 --- a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po +++ b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po @@ -3,15 +3,16 @@ # Andi Chandler <andi@gowling.com>, 2019. #zanata # Andi Chandler <andi@gowling.com>, 2020. #zanata # Andi Chandler <andi@gowling.com>, 2021. #zanata +# Andi Chandler <andi@gowling.com>, 2022. #zanata msgid "" msgstr "" "Project-Id-Version: openstack-heat\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-11-01 17:53+0000\n" +"POT-Creation-Date: 2022-05-25 07:40+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2021-09-18 07:40+0000\n" +"PO-Revision-Date: 2022-05-25 09:20+0000\n" "Last-Translator: Andi Chandler <andi@gowling.com>\n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" @@ -58,6 +59,9 @@ msgstr "13.0.0" msgid "13.0.1" msgstr "13.0.1" +msgid "13.1.0-19" +msgstr "13.1.0-19" + msgid "14.0.0" msgstr "14.0.0" @@ -67,12 +71,21 @@ msgstr "14.2.0" msgid "15.0.0" msgstr "15.0.0" -msgid "15.0.0-21" -msgstr "15.0.0-21" +msgid "15.1.0" +msgstr "15.1.0" msgid "16.0.0" msgstr "16.0.0" +msgid "17.0.0" +msgstr "17.0.0" + +msgid "18.0.0" +msgstr "18.0.0" + +msgid "18.0.0-4" +msgstr "18.0.0-4" + msgid "5.0.1" msgstr "5.0.1" @@ -739,6 +752,15 @@ msgstr "" "openstack.org/heat/pike/`." msgid "" +"Allow Heat resources to accept more than one required_service_extension. For " +"cases where a resource required multiple service extensions. A developer can " +"now provide a list of those extensions." +msgstr "" +"Allow Heat resources to accept more than one required_service_extension. For " +"cases where a resource required multiple service extensions. A developer can " +"now provide a list of those extensions." + +msgid "" "Allow to configure Heat service to forbid creation of stacks containing " "Volume resources with ``deletion_policy`` set to ``Snapshot`` when there is " "no Cinder backup service available." @@ -1391,6 +1413,13 @@ msgstr "" "which allows users to create a network port without any fixed IPs." msgid "" +"Now the ``[DEFAULT] shared_services_types`` option includes ``volumev3`` " +"service type by default." +msgstr "" +"Now the ``[DEFAULT] shared_services_types`` option includes ``volumev3`` " +"service type by default." + +msgid "" "OS::Aodh::CompositeAlarm resource plugin is added to manage Aodh composite " "alarm, aim to replace OS::Aodh::CombinationAlarm which has been deprecated " "in Newton release." @@ -1847,6 +1876,9 @@ msgstr "" msgid "Support external resource reference in template." msgstr "Support external resource reference in template." +msgid "Support for Block Storage API v2 has been removed." +msgstr "Support for Block Storage API v2 has been removed." + msgid "" "Support shared services in multi region mode. The services are declared in a " "list in config. shared_services_types=image, volume, volumev2." @@ -2395,6 +2427,9 @@ msgstr "" msgid "Xena Series Release Notes" msgstr "Xena Series Release Notes" +msgid "Yoga Series Release Notes" +msgstr "Yoga Series Release Notes" + msgid "" "``OS::Neutron::Port`` resources will now be replaced when the " "``mac_address`` property is modified. Neutron is unable to update the MAC " diff --git a/requirements.txt b/requirements.txt index f263179a1..a6a85292a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,7 @@ +# Requirements lower bounds listed here are our best effort to keep them up to +# date but we do not test them so no guarantee of having them all correct. If +# you find any incorrect lower bounds, let us know or propose a fix. + # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. diff --git a/roles/run-heat-tests/defaults/main.yaml b/roles/run-heat-tests/defaults/main.yaml index b601d49d9..22ce4a490 100644 --- a/roles/run-heat-tests/defaults/main.yaml +++ b/roles/run-heat-tests/defaults/main.yaml @@ -1,2 +1,5 @@ devstack_base_dir: /opt/stack tempest_test_timeout: '' +tempest_tox_environment: {} +heat_tempest_plugin: /opt/stack/heat-tempest-plugin +constraints_file: /opt/stack/requirements/upper-constraints.txt diff --git a/roles/run-heat-tests/tasks/main.yaml b/roles/run-heat-tests/tasks/main.yaml index 75122f2a1..4af1d0e03 100644 --- a/roles/run-heat-tests/tasks/main.yaml +++ b/roles/run-heat-tests/tasks/main.yaml @@ -1,3 +1,23 @@ +- name: Set OS_TEST_TIMEOUT if requested + set_fact: + tempest_tox_environment: "{{ tempest_tox_environment | combine({'OS_TEST_TIMEOUT': tempest_test_timeout}) }}" + when: tempest_test_timeout != '' + +- name: Set TOX_CONSTRAINTS_FILE + set_fact: + tempest_tox_environment: "{{ tempest_tox_environment | combine({'UPPER_CONSTRAINTS_FILE': constraints_file}) | combine({'TOX_CONSTRAINTS_FILE': constraints_file}) }}" + +- name: Allow git to read plugin directories + become: true + command: git config --system --add safe.directory {{heat_tempest_plugin}} + +- name: Install plugins + command: tox -evenv-tempest -- pip install -c{{constraints_file}} {{heat_tempest_plugin}} + become: true + args: + chdir: "{{devstack_base_dir}}/tempest" + environment: "{{ tempest_tox_environment }}" + - name: Run heat tests command: tox -evenv-tempest -- stestr --test-path={{devstack_base_dir}}/heat/heat_integrationtests \ --top-dir={{devstack_base_dir}}/heat \ @@ -5,5 +25,4 @@ args: chdir: "{{devstack_base_dir}}/tempest" become: true - become_user: tempest - environment: '{{ {"OS_TEST_TIMEOUT": tempest_test_timeout} if tempest_test_timeout else {} }}' + environment: "{{ tempest_tox_environment }}" @@ -6,7 +6,7 @@ description-file = author = OpenStack author-email = openstack-discuss@lists.openstack.org home-page = https://docs.openstack.org/heat/latest/ -python-requires = >=3.6 +python-requires = >=3.8 classifier = Environment :: OpenStack Intended Audience :: Information Technology @@ -16,8 +16,6 @@ classifier = Programming Language :: Python Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -18,4 +18,5 @@ import setuptools setuptools.setup( setup_requires=['pbr>=2.0.0'], + py_modules=[], pbr=True) @@ -1,5 +1,5 @@ [tox] -envlist = py36,py37,py38,py39,pep8 +envlist = py38,py39,pep8 ignore_basepython_conflict = True minversion = 3.18.0 skipsdist = True @@ -153,10 +153,3 @@ commands = deps = bindep commands = bindep test usedevelop = False - -[testenv:lower-constraints] -install_command = pip install {opts} {packages} -deps = - -c{toxinidir}/lower-constraints.txt - -r{toxinidir}/test-requirements.txt - -r{toxinidir}/requirements.txt |