From a6d52af58afc68de1cfc571ad28de9dcea7ebad5 Mon Sep 17 00:00:00 2001 From: Shawn Wang Date: Tue, 8 Oct 2019 11:25:18 -0700 Subject: [PATCH] Include error code in RealizationErrorStateError in Policy In Policy API, RealizationErrorStateError is raised if an intent entity gets into ERROR state during wait. Currently only error message is included in the exception. This patch adds both error_code and related_error_codes in the exception to make it more informative. Change-Id: I45b7c50a50b1a69e37b79f684b324bb17496a9df --- .../tests/unit/v3/policy/test_lb_resources.py | 33 +++++++++++++++++++ .../tests/unit/v3/policy/test_resources.py | 24 ++++++++++++++ vmware_nsxlib/v3/policy/core_resources.py | 32 +++++++++++------- 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/vmware_nsxlib/tests/unit/v3/policy/test_lb_resources.py b/vmware_nsxlib/tests/unit/v3/policy/test_lb_resources.py index fd7aba27..5144691c 100644 --- a/vmware_nsxlib/tests/unit/v3/policy/test_lb_resources.py +++ b/vmware_nsxlib/tests/unit/v3/policy/test_lb_resources.py @@ -807,6 +807,39 @@ class TestPolicyLBService(test_resources.NsxPolicyLibTestCase): lbs_id, max_attempts=5, sleep=0.1, tenant=TEST_TENANT) + def test_wait_until_realized_error(self): + lbs_id = 'test_lbs' + error_code = 23500 + related_error_code = 23707 + error_msg = 'Found errors in the request.' + related_error_msg = 'Exceed maximum number of load balancer.' + info = {'state': constants.STATE_ERROR, + 'realization_specific_identifier': lbs_id, + 'entity_type': 'LbServiceDto', + 'alarms': [{ + 'message': error_msg, + 'error_details': { + 'related_errors': [{ + 'error_code': related_error_code, + 'module_name': 'LOAD-BALANCER', + 'error_message': related_error_msg + }], + 'error_code': error_code, + 'module_name': 'LOAD-BALANCER', + 'error_message': error_msg + } + }]} + with mock.patch.object(self.resourceApi, "_get_realization_info", + return_value=info): + with self.assertRaises(nsxlib_exc.RealizationErrorStateError) as e: + self.resourceApi.wait_until_realized( + lbs_id, tenant=TEST_TENANT) + error_msg_tail = "%s: %s" % (error_msg, related_error_msg) + self.assertTrue(e.exception.msg.endswith(error_msg_tail)) + self.assertEqual(e.exception.error_code, error_code) + self.assertEqual(e.exception.related_error_codes, + [related_error_code]) + def test_wait_until_realized_succeed(self): lbs_id = 'test_lbs' info = {'state': constants.STATE_REALIZED, diff --git a/vmware_nsxlib/tests/unit/v3/policy/test_resources.py b/vmware_nsxlib/tests/unit/v3/policy/test_resources.py index cc4e6cee..b30d5905 100644 --- a/vmware_nsxlib/tests/unit/v3/policy/test_resources.py +++ b/vmware_nsxlib/tests/unit/v3/policy/test_resources.py @@ -4034,6 +4034,30 @@ class TestPolicyIpPool(NsxPolicyLibTestCase): ip_pool_id, max_attempts=5, sleep=0.1, tenant=TEST_TENANT) + def test_wait_until_realized_error(self): + ip_alloc_id = 'ip_alloc_1' + error_code = 5109 + error_msg = 'Insufficient free IP addresses.' + info = {'state': constants.STATE_ERROR, + 'realization_specific_identifier': ip_alloc_id, + 'entity_type': 'AllocationIpAddress', + 'alarms': [{ + 'message': error_msg, + 'error_details': { + 'error_code': error_code, + 'module_name': 'id-allocation service', + 'error_message': error_msg + } + }]} + with mock.patch.object(self.resourceApi, "_get_realization_info", + return_value=info): + with self.assertRaises(nsxlib_exc.RealizationErrorStateError) as e: + self.resourceApi.wait_until_realized( + ip_alloc_id, tenant=TEST_TENANT) + self.assertTrue(e.exception.msg.endswith(error_msg)) + self.assertEqual(e.exception.error_code, error_code) + self.assertEqual(e.exception.related_error_codes, []) + def test_wait_until_realized_succeed(self): ip_pool_id = 'p1' info = {'state': constants.STATE_REALIZED, diff --git a/vmware_nsxlib/v3/policy/core_resources.py b/vmware_nsxlib/v3/policy/core_resources.py index bc986e63..5145086b 100644 --- a/vmware_nsxlib/v3/policy/core_resources.py +++ b/vmware_nsxlib/v3/policy/core_resources.py @@ -223,17 +223,23 @@ class NsxPolicyResourceBase(object): realization_info.get('realization_specific_identifier')): return realization_info['realization_specific_identifier'] - def _get_realization_error_message(self, info): + def _get_realization_error_message_and_code(self, info): error_msg = 'unknown' + error_code = None + related_error_codes = [] if info.get('alarms'): alarm = info['alarms'][0] error_msg = alarm.get('message') - if (alarm.get('error_details') and - alarm['error_details'].get('related_errors')): - related = alarm['error_details']['related_errors'][0] - error_msg = '%s: %s' % (error_msg, - related.get('error_message')) - return error_msg + if alarm.get('error_details'): + error_code = alarm['error_details'].get('error_code') + if alarm['error_details'].get('related_errors'): + related = alarm['error_details']['related_errors'] + for err_obj in related: + error_msg = '%s: %s' % (error_msg, + err_obj.get('error_message')) + if err_obj.get('error_code'): + related_error_codes.append(err_obj['error_code']) + return error_msg, error_code, related_error_codes def _wait_until_realized(self, resource_def, entity_type=None, sleep=None, max_attempts=None): @@ -254,11 +260,13 @@ class NsxPolicyResourceBase(object): if info['state'] == constants.STATE_REALIZED: return info if info['state'] == constants.STATE_ERROR: - error_msg = self._get_realization_error_message(info) + error_msg, error_code, related_error_codes = \ + self._get_realization_error_message_and_code(info) raise exceptions.RealizationErrorStateError( resource_type=resource_def.resource_type(), resource_id=resource_def.get_id(), - error=error_msg) + error=error_msg, error_code=error_code, + related_error_codes=related_error_codes) try: return get_info() @@ -302,11 +310,13 @@ class NsxPolicyResourceBase(object): if resource_def and test_num % check_status == (check_status - 1): info = self._get_realization_info(resource_def) if info and info['state'] == constants.STATE_ERROR: - error_msg = self._get_realization_error_message(info) + error_msg, error_code, related_error_codes = \ + self._get_realization_error_message_and_code(info) raise exceptions.RealizationErrorStateError( resource_type=resource_def.resource_type(), resource_id=resource_def.get_id(), - error=error_msg) + error=error_msg, error_code=error_code, + related_error_codes=related_error_codes) if (info and info['state'] == constants.STATE_REALIZED and info.get('realization_specific_identifier')): LOG.warning("Realization ID for %s was not found via "