Wrap stack operations in a heat_exceptions
Heat exceptions give strings useful to the user (such as validation errors for their templates) so we need a custom exceptions wrapper to include those in the raised exception. Also the message for delete_stack exceptions now includes the name_or_id that the user passed in, which should have more meaning for them than the stack ID. Change-Id: I0bf0b9b249a311f76457115a5a7d2392244343f8
This commit is contained in:
parent
2ed2254879
commit
bceedbce3f
@ -21,6 +21,7 @@ import six
|
||||
import time
|
||||
|
||||
from decorator import decorator
|
||||
from heatclient import exc as heat_exc
|
||||
from neutronclient.common import exceptions as neutron_exc
|
||||
|
||||
from shade import _log
|
||||
@ -534,6 +535,18 @@ def cache_on_arguments(*cache_on_args, **cache_on_kwargs):
|
||||
return _inner_cache_on_arguments
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def heat_exceptions(error_message):
|
||||
try:
|
||||
yield
|
||||
except heat_exc.NotFound as e:
|
||||
raise exc.OpenStackCloudResourceNotFound(
|
||||
"{msg}: {exc}".format(msg=error_message, exc=str(e)))
|
||||
except Exception as e:
|
||||
raise exc.OpenStackCloudException(
|
||||
"{msg}: {exc}".format(msg=error_message, exc=str(e)))
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def neutron_exceptions(error_message):
|
||||
try:
|
||||
|
@ -32,6 +32,7 @@ import glanceclient.exc
|
||||
import heatclient.client
|
||||
from heatclient.common import event_utils
|
||||
from heatclient.common import template_utils
|
||||
from heatclient import exc as heat_exceptions
|
||||
import keystoneauth1.exceptions
|
||||
import keystoneclient.client
|
||||
import neutronclient.neutron.client
|
||||
@ -845,7 +846,7 @@ class OpenStackCloud(object):
|
||||
environment=env,
|
||||
timeout_mins=timeout // 60,
|
||||
)
|
||||
with _utils.shade_exceptions("Error creating stack {name}".format(
|
||||
with _utils.heat_exceptions("Error creating stack {name}".format(
|
||||
name=name)):
|
||||
self.manager.submitTask(_tasks.StackCreate(**params))
|
||||
if wait:
|
||||
@ -868,8 +869,8 @@ class OpenStackCloud(object):
|
||||
self.log.debug("Stack %s not found for deleting" % name_or_id)
|
||||
return False
|
||||
|
||||
with _utils.shade_exceptions("Failed to delete stack {id}".format(
|
||||
id=stack['id'])):
|
||||
with _utils.heat_exceptions("Failed to delete stack {id}".format(
|
||||
id=name_or_id)):
|
||||
self.manager.submitTask(_tasks.StackDelete(id=stack['id']))
|
||||
return True
|
||||
|
||||
@ -1774,8 +1775,11 @@ class OpenStackCloud(object):
|
||||
# stack names are mandatory and enforced unique in the project
|
||||
# so a StackGet can always be used for name or ID.
|
||||
with _utils.shade_exceptions("Error fetching stack"):
|
||||
stacks = [self.manager.submitTask(
|
||||
_tasks.StackGet(stack_id=name_or_id))]
|
||||
try:
|
||||
stacks = [self.manager.submitTask(
|
||||
_tasks.StackGet(stack_id=name_or_id))]
|
||||
except heat_exceptions.NotFound:
|
||||
return []
|
||||
nstacks = _utils.normalize_stacks(stacks)
|
||||
return _utils._filter_list(nstacks, name_or_id, filters)
|
||||
|
||||
|
@ -21,6 +21,7 @@ Functional tests for `shade` stack methods.
|
||||
|
||||
import tempfile
|
||||
|
||||
from shade import exc
|
||||
from shade import openstack_cloud
|
||||
from shade.tests import base
|
||||
|
||||
@ -70,6 +71,8 @@ resource_registry:
|
||||
My::Simple::Template: %s
|
||||
'''
|
||||
|
||||
validate_template = '''heat_template_version: asdf-no-such-version '''
|
||||
|
||||
|
||||
class TestStack(base.TestCase):
|
||||
|
||||
@ -82,6 +85,16 @@ class TestStack(base.TestCase):
|
||||
def _cleanup_stack(self):
|
||||
self.cloud.delete_stack(self.stack_name)
|
||||
|
||||
def test_stack_validation(self):
|
||||
test_template = tempfile.NamedTemporaryFile(delete=False)
|
||||
test_template.write(validate_template)
|
||||
test_template.close()
|
||||
stack_name = self.getUniqueString('validate_template')
|
||||
self.assertRaises(exc.OpenStackCloudException,
|
||||
self.cloud.create_stack,
|
||||
name=stack_name,
|
||||
template_file=test_template.name)
|
||||
|
||||
def test_stack_simple(self):
|
||||
test_template = tempfile.NamedTemporaryFile(delete=False)
|
||||
test_template.write(simple_template)
|
||||
|
@ -101,10 +101,10 @@ class TestStack(base.TestCase):
|
||||
def test_delete_stack_exception(self, mock_heat, mock_get):
|
||||
stack = {'id': 'stack_id', 'name': 'stack_name'}
|
||||
mock_get.return_value = stack
|
||||
mock_heat.stacks.delete.side_effect = Exception()
|
||||
mock_heat.stacks.delete.side_effect = Exception('ouch')
|
||||
with testtools.ExpectedException(
|
||||
shade.OpenStackCloudException,
|
||||
"Failed to delete stack %s" % stack['id']
|
||||
"Failed to delete stack stack_name: ouch"
|
||||
):
|
||||
self.cloud.delete_stack('stack_name')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user