Merge "Use exception_filter in RPC client"
This commit is contained in:
commit
48ef79c5f7
@ -112,12 +112,9 @@ class MultipartMime(software_config.SoftwareConfig):
|
|||||||
part = config
|
part = config
|
||||||
|
|
||||||
if uuidutils.is_uuid_like(config):
|
if uuidutils.is_uuid_like(config):
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
sc = self.rpc_client().show_software_config(
|
sc = self.rpc_client().show_software_config(
|
||||||
self.context, config)
|
self.context, config)
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
else:
|
|
||||||
part = sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
part = sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
||||||
|
|
||||||
if part_type == self.MULTIPART:
|
if part_type == self.MULTIPART:
|
||||||
|
@ -130,14 +130,12 @@ class SoftwareComponent(sc.SoftwareConfig):
|
|||||||
an empty list is returned.
|
an empty list is returned.
|
||||||
"""
|
"""
|
||||||
if name == self.CONFIGS_ATTR and self.resource_id:
|
if name == self.CONFIGS_ATTR and self.resource_id:
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
sc = self.rpc_client().show_software_config(
|
sc = self.rpc_client().show_software_config(
|
||||||
self.context, self.resource_id)
|
self.context, self.resource_id)
|
||||||
# configs list is stored in 'config' property of parent class
|
# configs list is stored in 'config' property of parent class
|
||||||
# (see handle_create)
|
# (see handle_create)
|
||||||
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG].get(self.CONFIGS)
|
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG].get(self.CONFIGS)
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
"""Validate SoftwareComponent properties consistency."""
|
"""Validate SoftwareComponent properties consistency."""
|
||||||
|
@ -113,11 +113,9 @@ class SoftwareConfig(resource.Resource):
|
|||||||
if self.resource_id is None:
|
if self.resource_id is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
self.rpc_client().delete_software_config(
|
self.rpc_client().delete_software_config(
|
||||||
self.context, self.resource_id)
|
self.context, self.resource_id)
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
|
|
||||||
def _resolve_attribute(self, name):
|
def _resolve_attribute(self, name):
|
||||||
"""Retrieve attributes of the SoftwareConfig resource.
|
"""Retrieve attributes of the SoftwareConfig resource.
|
||||||
@ -126,12 +124,10 @@ class SoftwareConfig(resource.Resource):
|
|||||||
software config does not exist, returns an empty string.
|
software config does not exist, returns an empty string.
|
||||||
"""
|
"""
|
||||||
if name == self.CONFIG_ATTR and self.resource_id:
|
if name == self.CONFIG_ATTR and self.resource_id:
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
sc = self.rpc_client().show_software_config(
|
sc = self.rpc_client().show_software_config(
|
||||||
self.context, self.resource_id)
|
self.context, self.resource_id)
|
||||||
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
|
|
||||||
|
|
||||||
def resource_mapping():
|
def resource_mapping():
|
||||||
|
@ -209,11 +209,9 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||||||
return props
|
return props
|
||||||
|
|
||||||
def _delete_derived_config(self, derived_config_id):
|
def _delete_derived_config(self, derived_config_id):
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
self.rpc_client().delete_software_config(
|
self.rpc_client().delete_software_config(
|
||||||
self.context, derived_config_id)
|
self.context, derived_config_id)
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
|
|
||||||
def _create_derived_config(self, action, source_config):
|
def _create_derived_config(self, action, source_config):
|
||||||
|
|
||||||
@ -466,10 +464,8 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||||||
return self._check_complete()
|
return self._check_complete()
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
return self._handle_action(self.DELETE)
|
return self._handle_action(self.DELETE)
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
|
|
||||||
def check_delete_complete(self, sd=None):
|
def check_delete_complete(self, sd=None):
|
||||||
if not sd or not self._server_exists(sd) or self._check_complete():
|
if not sd or not self._server_exists(sd) or self._check_complete():
|
||||||
@ -479,12 +475,10 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||||||
def _delete_resource(self):
|
def _delete_resource(self):
|
||||||
derived_config_id = None
|
derived_config_id = None
|
||||||
if self.resource_id is not None:
|
if self.resource_id is not None:
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
derived_config_id = self._get_derived_config_id()
|
derived_config_id = self._get_derived_config_id()
|
||||||
self.rpc_client().delete_software_deployment(
|
self.rpc_client().delete_software_deployment(
|
||||||
self.context, self.resource_id)
|
self.context, self.resource_id)
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
|
|
||||||
if derived_config_id:
|
if derived_config_id:
|
||||||
self._delete_derived_config(derived_config_id)
|
self._delete_derived_config(derived_config_id)
|
||||||
|
@ -702,12 +702,10 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
|
|||||||
self.USER_DATA_FORMAT] == self.SOFTWARE_CONFIG
|
self.USER_DATA_FORMAT] == self.SOFTWARE_CONFIG
|
||||||
|
|
||||||
def get_software_config(self, ud_content):
|
def get_software_config(self, ud_content):
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('NotFound'):
|
||||||
sc = self.rpc_client().show_software_config(
|
sc = self.rpc_client().show_software_config(
|
||||||
self.context, ud_content)
|
self.context, ud_content)
|
||||||
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'NotFound')
|
|
||||||
return ud_content
|
return ud_content
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
|
@ -521,14 +521,12 @@ class StackResource(resource.Resource):
|
|||||||
if stack_identity is None:
|
if stack_identity is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
with self.rpc_client().ignore_error_by_name('EntityNotFound'):
|
||||||
if self.abandon_in_progress:
|
if self.abandon_in_progress:
|
||||||
self.rpc_client().abandon_stack(self.context, stack_identity)
|
self.rpc_client().abandon_stack(self.context, stack_identity)
|
||||||
else:
|
else:
|
||||||
self.rpc_client().delete_stack(self.context, stack_identity,
|
self.rpc_client().delete_stack(self.context, stack_identity,
|
||||||
cast=False)
|
cast=False)
|
||||||
except Exception as ex:
|
|
||||||
self.rpc_client().ignore_error_named(ex, 'EntityNotFound')
|
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
return self.delete_nested()
|
return self.delete_nested()
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
"""Client side of the heat engine RPC API."""
|
"""Client side of the heat engine RPC API."""
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from oslo_utils import excutils
|
||||||
from oslo_utils import reflection
|
from oslo_utils import reflection
|
||||||
|
|
||||||
from heat.common import messaging
|
from heat.common import messaging
|
||||||
@ -100,14 +103,26 @@ class EngineClient(object):
|
|||||||
error_name = reflection.get_class_name(error, fully_qualified=False)
|
error_name = reflection.get_class_name(error, fully_qualified=False)
|
||||||
return error_name.split('_Remote')[0]
|
return error_name.split('_Remote')[0]
|
||||||
|
|
||||||
|
def ignore_error_by_name(self, name):
|
||||||
|
"""Returns a context manager that filters exceptions with a given name.
|
||||||
|
|
||||||
|
:param name: Name to compare the local exception name to.
|
||||||
|
"""
|
||||||
|
def error_name_matches(err):
|
||||||
|
return self.local_error_name(err) == name
|
||||||
|
|
||||||
|
return excutils.exception_filter(error_name_matches)
|
||||||
|
|
||||||
def ignore_error_named(self, error, name):
|
def ignore_error_named(self, error, name):
|
||||||
"""Raises the error unless its local name matches the supplied name.
|
"""Raises the error unless its local name matches the supplied name.
|
||||||
|
|
||||||
:param error: Remote raised error to derive the local name from.
|
:param error: Remote raised error to derive the local name from.
|
||||||
:param name: Name to compare local name to.
|
:param name: Name to compare local name to.
|
||||||
"""
|
"""
|
||||||
if self.local_error_name(error) != name:
|
warnings.warn("Use ignore_error_by_name() to get a context manager "
|
||||||
raise error
|
"instead.",
|
||||||
|
DeprecationWarning)
|
||||||
|
return self.ignore_error_by_name(name)(error)
|
||||||
|
|
||||||
def identify_stack(self, ctxt, stack_name):
|
def identify_stack(self, ctxt, stack_name):
|
||||||
"""Returns the full stack identifier for a single, live stack.
|
"""Returns the full stack identifier for a single, live stack.
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import email
|
import email
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@ -99,7 +100,17 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||||||
'type': 'text'
|
'type': 'text'
|
||||||
}]
|
}]
|
||||||
self.init_config(parts=parts)
|
self.init_config(parts=parts)
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exc_filter():
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exc.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.rpc_client.ignore_error_by_name.return_value = exc_filter()
|
||||||
self.rpc_client.show_software_config.side_effect = exc.NotFound()
|
self.rpc_client.show_software_config.side_effect = exc.NotFound()
|
||||||
|
|
||||||
result = self.config.get_message()
|
result = self.config.get_message()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import mock
|
import mock
|
||||||
import six
|
import six
|
||||||
|
|
||||||
@ -59,6 +60,15 @@ class SoftwareComponentTest(common.HeatTestCase):
|
|||||||
self.rpc_client = mock.MagicMock()
|
self.rpc_client = mock.MagicMock()
|
||||||
self.component._rpc_client = self.rpc_client
|
self.component._rpc_client = self.rpc_client
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exc_filter(*args):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exc.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.rpc_client.ignore_error_by_name.side_effect = exc_filter
|
||||||
|
|
||||||
def test_handle_create(self):
|
def test_handle_create(self):
|
||||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||||
value = {'id': config_id}
|
value = {'id': config_id}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from heat.common import exception as exc
|
from heat.common import exception as exc
|
||||||
@ -45,6 +46,15 @@ class SoftwareConfigTest(common.HeatTestCase):
|
|||||||
self.rpc_client = mock.MagicMock()
|
self.rpc_client = mock.MagicMock()
|
||||||
self.config._rpc_client = self.rpc_client
|
self.config._rpc_client = self.rpc_client
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exc_filter(*args):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exc.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.rpc_client.ignore_error_by_name.side_effect = exc_filter
|
||||||
|
|
||||||
def test_handle_create(self):
|
def test_handle_create(self):
|
||||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||||
value = {'id': config_id}
|
value = {'id': config_id}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
@ -204,6 +205,15 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||||||
self.rpc_client = mock.MagicMock()
|
self.rpc_client = mock.MagicMock()
|
||||||
self.deployment._rpc_client = self.rpc_client
|
self.deployment._rpc_client = self.rpc_client
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exc_filter(*args):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exc.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.rpc_client.ignore_error_by_name.side_effect = exc_filter
|
||||||
|
|
||||||
def test_validate(self):
|
def test_validate(self):
|
||||||
template = dict(self.template_with_server)
|
template = dict(self.template_with_server)
|
||||||
props = template['Resources']['server']['Properties']
|
props = template['Resources']['server']['Properties']
|
||||||
@ -1188,7 +1198,11 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||||||
}],
|
}],
|
||||||
'outputs': [],
|
'outputs': [],
|
||||||
}
|
}
|
||||||
self.rpc_client.show_software_config.return_value = config
|
|
||||||
|
def show_sw_config(*args):
|
||||||
|
return config.copy()
|
||||||
|
|
||||||
|
self.rpc_client.show_software_config.side_effect = show_sw_config
|
||||||
mock_sd = self.mock_deployment()
|
mock_sd = self.mock_deployment()
|
||||||
|
|
||||||
self.rpc_client.show_software_deployment.return_value = mock_sd
|
self.rpc_client.show_software_deployment.return_value = mock_sd
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
@ -686,6 +687,14 @@ class ServersTest(common.HeatTestCase):
|
|||||||
self.rpc_client = mock.MagicMock()
|
self.rpc_client = mock.MagicMock()
|
||||||
server._rpc_client = self.rpc_client
|
server._rpc_client = self.rpc_client
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exc_filter(*args):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exception.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.rpc_client.ignore_error_by_name.side_effect = exc_filter
|
||||||
self.rpc_client.show_software_config.side_effect = exception.NotFound
|
self.rpc_client.show_software_config.side_effect = exception.NotFound
|
||||||
mock_create = self.patchobject(self.fc.servers, 'create',
|
mock_create = self.patchobject(self.fc.servers, 'create',
|
||||||
return_value=return_server)
|
return_value=return_server)
|
||||||
|
@ -56,6 +56,24 @@ class EngineRpcAPITestCase(common.HeatTestCase):
|
|||||||
reflection.get_class_name(exr, fully_qualified=False))
|
reflection.get_class_name(exr, fully_qualified=False))
|
||||||
self.assertEqual('NotFound', self.rpcapi.local_error_name(exr))
|
self.assertEqual('NotFound', self.rpcapi.local_error_name(exr))
|
||||||
|
|
||||||
|
def test_ignore_error_by_name(self):
|
||||||
|
ex = exception.NotFound()
|
||||||
|
exr = self._to_remote_error(ex)
|
||||||
|
|
||||||
|
filter_exc = self.rpcapi.ignore_error_by_name('NotFound')
|
||||||
|
|
||||||
|
with filter_exc:
|
||||||
|
raise ex
|
||||||
|
with filter_exc:
|
||||||
|
raise exr
|
||||||
|
|
||||||
|
def should_raise(exc):
|
||||||
|
with self.rpcapi.ignore_error_by_name('NotSupported'):
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
self.assertRaises(exception.NotFound, should_raise, ex)
|
||||||
|
self.assertRaises(exception.NotFound, should_raise, exr)
|
||||||
|
|
||||||
def test_ignore_error_named(self):
|
def test_ignore_error_named(self):
|
||||||
ex = exception.NotFound()
|
ex = exception.NotFound()
|
||||||
exr = self._to_remote_error(ex)
|
exr = self._to_remote_error(ex)
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@ -204,7 +205,16 @@ class StackResourceTest(StackResourceBaseTest):
|
|||||||
self.assertEqual({}, ret)
|
self.assertEqual({}, ret)
|
||||||
|
|
||||||
def test_abandon_nested_sends_rpc_abandon(self):
|
def test_abandon_nested_sends_rpc_abandon(self):
|
||||||
rpcc = mock.Mock()
|
rpcc = mock.MagicMock()
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exc_filter(*args):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exception.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
rpcc.ignore_error_by_name.side_effect = exc_filter
|
||||||
self.parent_resource.rpc_client = rpcc
|
self.parent_resource.rpc_client = rpcc
|
||||||
self.parent_resource.resource_id = 'fake_id'
|
self.parent_resource.resource_id = 'fake_id'
|
||||||
|
|
||||||
@ -509,8 +519,17 @@ class StackResourceTest(StackResourceBaseTest):
|
|||||||
|
|
||||||
def test_delete_nested_not_found_nested_stack(self):
|
def test_delete_nested_not_found_nested_stack(self):
|
||||||
self.parent_resource.resource_id = 'fake_id'
|
self.parent_resource.resource_id = 'fake_id'
|
||||||
rpcc = mock.Mock()
|
rpcc = mock.MagicMock()
|
||||||
self.parent_resource.rpc_client = rpcc
|
self.parent_resource.rpc_client = rpcc
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def exc_filter(*args):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exception.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
rpcc.return_value.ignore_error_by_name.side_effect = exc_filter
|
||||||
rpcc.return_value.delete_stack = mock.Mock(
|
rpcc.return_value.delete_stack = mock.Mock(
|
||||||
side_effect=exception.NotFound())
|
side_effect=exception.NotFound())
|
||||||
self.assertIsNone(self.parent_resource.delete_nested())
|
self.assertIsNone(self.parent_resource.delete_nested())
|
||||||
|
Loading…
Reference in New Issue
Block a user