Support isAutohealEnabled for faultnotification

This patch suppots enabling/disabling auto-healing by isAutohealEnabled
flag in case of faultnotification autoheal. When isAutohealEnabled is
set true in vnfConfigurableProperties, Auto-healing is enabled.
Otherwise, alert message from the notification server is ignored.

Implements: blueprint support-autoheal-queue
Change-Id: Ib9069c8e11192824868716a3b46a3ce3ca284819
This commit is contained in:
Koji Shimizu 2023-01-25 14:10:35 +09:00
parent 5c851b34ba
commit a87606e995
4 changed files with 197 additions and 147 deletions

View File

@ -103,7 +103,8 @@ The ``additionalParams`` must be set when using FaultNotification.
* | **Name**: Instantiate VNF task
| **Description**: This task resource represents the ``Instantiate VNF``
operation. The client can use this resource to instantiate a VNF instance.
``Only the additionalParams for FaultNotification are described here``.
``Only the additionalParams and the vnfConfigurableProperties for
FaultNotification are described here``.
| **Method type**: POST
| **URL for the resource**: /vnflcm/v2/vnf_instances/
{vnfInstanceId}/instantiate
@ -117,6 +118,18 @@ The ``additionalParams`` must be set when using FaultNotification.
- Data type
- Cardinality
- Description
* - vnfConfigurableProperties
- KeyValuePairs
- 0..1
- Additional VNF-specific attributes that
provide the current values of the configurable
properties of the VNF instance.
* - >isAutohealEnabled:
- boolean
- 0..1
- If present, the VNF supports auto-healing. If set to
true, auto-healing is currently enabled.
If set to false, autohealing is currently disabled.
* - additionalParams
- KeyValuePairs (inlined)
- 0..1
@ -149,7 +162,8 @@ with vnflcm show command. For example:
| | "ServerNotifierFaultID": "1234" |
| | } |
| | .... |
+-----------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| VNF Configurable Properties | isAutohealEnabled=True | +-----------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| | .... |
Auto Healing
------------

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from tacker.sol_refactored.api.schemas import server_notification_schemas
from tacker.sol_refactored.api import server_notification_validator\
as validator
@ -22,6 +23,8 @@ from tacker.sol_refactored.common import monitoring_plugin_base as mon_base
from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
from tacker.sol_refactored.conductor import conductor_rpc_v2
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@ -58,12 +61,7 @@ class ServerNotification(mon_base.MonitoringPlugin):
self.rpc.server_notification_notify(context, vnf_instance_id, vnfcids)
def get_vnfc_instance_id(
self, context, vnf_instance_id, alarm_id, fault_id):
vnf_instance = inst_utils.get_inst(context, vnf_instance_id)
if not vnf_instance:
raise sol_ex.ServerNotificationValidationError(
detail="target vnf instance not found.")
self, context, vnf_instance, alarm_id, fault_id):
if (not vnf_instance.obj_attr_is_set('instantiatedVnfInfo') or
not vnf_instance.instantiatedVnfInfo.obj_attr_is_set(
'metadata') or
@ -99,8 +97,18 @@ class ServerNotification(mon_base.MonitoringPlugin):
@validator.schema(server_notification_schemas.ServerNotification)
def notify(self, request, vnf_instance_id, body):
context = request.context
vnf_instance = inst_utils.get_inst(context, vnf_instance_id)
if not vnf_instance:
raise sol_ex.ServerNotificationValidationError(
detail="target vnf instance not found.")
if (not vnf_instance.obj_attr_is_set(
'vnfConfigurableProperties') or
not vnf_instance.vnfConfigurableProperties.get(
'isAutohealEnabled')):
LOG.info("ServerNotification: skipped, isAutohealEnabled=False.")
return
vnfcids = self.get_vnfc_instance_id(
context, vnf_instance_id, body['notification']['alarm_id'],
context, vnf_instance, body['notification']['alarm_id'],
body['notification']['fault_id'])
if self._notification_callback:
self._notification_callback(context, vnf_instance_id, vnfcids)

View File

@ -102,7 +102,21 @@ class ServerNotificationTest(test_vnflcm_basic_common.CommonVnfLcmTest):
"""
self.fault_notification_basic_test(repeat=3)
def fault_notification_basic_test(self, repeat=1):
def fault_notification_autoheal_disabled_test(self):
"""Test Fault Notification isAutohealEnabled=False
* About Test operations:
This test includes the following operations.
- 1. LCM-Create
- 2. LCM-Instantiate (isAutohealEnabled=False)
- 3. ServerNotifier-Notify
- 4. LCM-Terminate
- 5. LCM-Delete
"""
self.fault_notification_basic_test(is_autoheal_enabled=False)
def fault_notification_basic_test(
self, repeat=1, is_autoheal_enabled=True):
"""Test Fault Notification basic
* About Test operations:
@ -181,6 +195,9 @@ class ServerNotificationTest(test_vnflcm_basic_common.CommonVnfLcmTest):
'ServerNotifierUri': server_notification_uri,
'ServerNotifierFaultID': '1234'
}
instantiate_req['vnfConfigurableProperties'] = {
'isAutohealEnabled': is_autoheal_enabled
}
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
self.assertEqual(202, resp.status_code)
@ -230,167 +247,172 @@ class ServerNotificationTest(test_vnflcm_basic_common.CommonVnfLcmTest):
inst_id, 'server_id', fault_notification_param)
self.assertTrue(resp.status_code == 204 or resp.status_code == 404)
time.sleep(1)
# waiting for auto healing process complete after packing timer.
time.sleep(60)
# 4. LCM-Heal
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] in ['VDU1', 'VDU2'])]
vdu1_stack_before_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU1')][0]
vdu2_stack_before_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU2')][0]
if is_autoheal_enabled:
# waiting for auto healing process complete after packing timer.
time.sleep(60)
heal_req = paramgen.heal_vnf_all_min()
resp, body = self.heal_vnf_instance(inst_id, heal_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# 4. LCM-Heal
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] in ['VDU1', 'VDU2'])]
vdu1_stack_before_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU1')][0]
vdu2_stack_before_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU2')][0]
# check stack info
stack_status, _ = self.heat_client.get_status(stack_name)
self.assertEqual("UPDATE_COMPLETE", stack_status)
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] in ['VDU1', 'VDU2'])]
vdu1_stack_after_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU1')][0]
vdu2_stack_after_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU2')][0]
heal_req = paramgen.heal_vnf_all_min()
resp, body = self.heal_vnf_instance(inst_id, heal_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
self.assertEqual("CREATE_COMPLETE",
vdu1_stack_after_heal['resource_status'])
self.assertEqual("CREATE_COMPLETE",
vdu2_stack_after_heal['resource_status'])
# check stack info
stack_status, _ = self.heat_client.get_status(stack_name)
self.assertEqual("UPDATE_COMPLETE", stack_status)
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] in ['VDU1', 'VDU2'])]
vdu1_stack_after_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU1')][0]
vdu2_stack_after_heal = [stack for stack in temp_stacks if
(stack['resource_name'] == 'VDU2')][0]
self.assertNotEqual(vdu1_stack_before_heal['physical_resource_id'],
vdu1_stack_after_heal['physical_resource_id'])
self.assertNotEqual(vdu2_stack_before_heal['physical_resource_id'],
vdu2_stack_after_heal['physical_resource_id'])
self.assertEqual("CREATE_COMPLETE",
vdu1_stack_after_heal['resource_status'])
self.assertEqual("CREATE_COMPLETE",
vdu2_stack_after_heal['resource_status'])
# Show VNF instance
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
self.check_resp_body(body, expected_inst_attrs)
self.assertNotEqual(
vdu1_stack_before_heal['physical_resource_id'],
vdu1_stack_after_heal['physical_resource_id'])
self.assertNotEqual(
vdu2_stack_before_heal['physical_resource_id'],
vdu2_stack_after_heal['physical_resource_id'])
# check instantiationState of VNF
self.assertEqual(fields.VnfInstanceState.INSTANTIATED,
body['instantiationState'])
# Show VNF instance
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
self.check_resp_body(body, expected_inst_attrs)
# check vnfState of VNF
self.assertEqual(fields.VnfOperationalStateType.STARTED,
body['instantiatedVnfInfo']['vnfState'])
# check instantiationState of VNF
self.assertEqual(fields.VnfInstanceState.INSTANTIATED,
body['instantiationState'])
# check usageState of VNF Package 2
self._check_package_usage(is_nfvo, self.svn_pkg, 'IN_USE')
# check vnfState of VNF
self.assertEqual(fields.VnfOperationalStateType.STARTED,
body['instantiatedVnfInfo']['vnfState'])
self.assertEqual(self.svn_id, body['vnfdId'])
# check usageState of VNF Package 2
self._check_package_usage(is_nfvo, self.svn_pkg, 'IN_USE')
# Heal VNF(vnfc)
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] == 'VDU2')]
vdu2_stack_before_heal = temp_stacks[0]
self.assertEqual(self.svn_id, body['vnfdId'])
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
vnfc_info = body['instantiatedVnfInfo']['vnfcInfo']
self.assertGreater(len(vnfc_info), 1)
vnfc_id = [vnfc['id'] for vnfc in vnfc_info if (
"VDU2" == vnfc['vduId'])][0]
self.assertIsNotNone(vnfc_id)
# Heal VNF(vnfc)
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] == 'VDU2')]
vdu2_stack_before_heal = temp_stacks[0]
heal_req = paramgen.heal_vnf_vnfc_min(vnfc_id)
resp, body = self.heal_vnf_instance(inst_id, heal_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
vnfc_info = body['instantiatedVnfInfo']['vnfcInfo']
self.assertGreater(len(vnfc_info), 1)
vnfc_id = [vnfc['id'] for vnfc in vnfc_info if (
"VDU2" == vnfc['vduId'])][0]
self.assertIsNotNone(vnfc_id)
# check stack info
stack_status, _ = self.heat_client.get_status(stack_name)
self.assertEqual("UPDATE_COMPLETE", stack_status)
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] == 'VDU2')]
vdu2_stack_after_heal = temp_stacks[0]
heal_req = paramgen.heal_vnf_vnfc_min(vnfc_id)
resp, body = self.heal_vnf_instance(inst_id, heal_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
self.assertEqual("CREATE_COMPLETE",
vdu2_stack_after_heal['resource_status'])
# check stack info
stack_status, _ = self.heat_client.get_status(stack_name)
self.assertEqual("UPDATE_COMPLETE", stack_status)
nested_stacks = self.heat_client.get_resources(stack_name)
temp_stacks = [stack for stack in nested_stacks if
(stack['resource_name'] == 'VDU2')]
vdu2_stack_after_heal = temp_stacks[0]
self.assertNotEqual(vdu2_stack_before_heal['physical_resource_id'],
vdu2_stack_after_heal['physical_resource_id'])
self.assertEqual("CREATE_COMPLETE",
vdu2_stack_after_heal['resource_status'])
# Show VNF instance
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
self.check_resp_body(body, expected_inst_attrs)
self.assertNotEqual(
vdu2_stack_before_heal['physical_resource_id'],
vdu2_stack_after_heal['physical_resource_id'])
# check vnfState of VNF
self.assertEqual(fields.VnfOperationalStateType.STARTED,
body['instantiatedVnfInfo']['vnfState'])
# Show VNF instance
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
self.check_resp_body(body, expected_inst_attrs)
# 5. LCM-Scale (SCALE_OUT)
# get nested stack count before scaleout
nested_stacks = self.heat_client.get_resources(stack_name)
count_before_scaleout = len(nested_stacks)
scaleout_req = paramgen.scaleout_vnf_min()
resp, body = self.scale_vnf_instance(inst_id, scaleout_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# check vnfState of VNF
self.assertEqual(fields.VnfOperationalStateType.STARTED,
body['instantiatedVnfInfo']['vnfState'])
# Show VNF instance
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
self.check_resp_body(body, expected_inst_attrs)
# 5. LCM-Scale (SCALE_OUT)
# get nested stack count before scaleout
nested_stacks = self.heat_client.get_resources(stack_name)
count_before_scaleout = len(nested_stacks)
scaleout_req = paramgen.scaleout_vnf_min()
resp, body = self.scale_vnf_instance(inst_id, scaleout_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# check vnfState of VNF
self.assertEqual(fields.VnfOperationalStateType.STARTED,
body['instantiatedVnfInfo']['vnfState'])
# Show VNF instance
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp, body = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
self.check_resp_body(body, expected_inst_attrs)
# get nested stack count after scale out
nested_stacks = self.heat_client.get_resources(stack_name)
count_after_scaleout = len(nested_stacks)
# check nested stack was created
# 3 was the sum of 1 VM, 1 CP, 1 stack(VDU1.yaml)
self.assertEqual(3, count_after_scaleout - count_before_scaleout)
# check vnfState of VNF
self.assertEqual(fields.VnfOperationalStateType.STARTED,
body['instantiatedVnfInfo']['vnfState'])
# 6. LCM-Scale (SCALE_IN)
scalein_req = paramgen.scalein_vnf_min()
resp, body = self.scale_vnf_instance(inst_id, scalein_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# get nested stack count after scale out
nested_stacks = self.heat_client.get_resources(stack_name)
count_after_scaleout = len(nested_stacks)
# check nested stack was created
# 3 was the sum of 1 VM, 1 CP, 1 stack(VDU1.yaml)
self.assertEqual(3, count_after_scaleout - count_before_scaleout)
# get nested stack count after scale in
nested_stacks = self.heat_client.get_resources(stack_name)
count_after_scalein = len(nested_stacks)
# check nested stack was deleted
# 3 was the sum of 1 VM, 1 CP, 1 stack(VDU1.yaml)
self.assertEqual(3, count_after_scaleout - count_after_scalein)
# 6. LCM-Scale (SCALE_IN)
scalein_req = paramgen.scalein_vnf_min()
resp, body = self.scale_vnf_instance(inst_id, scalein_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# get nested stack count after scale in
nested_stacks = self.heat_client.get_resources(stack_name)
count_after_scalein = len(nested_stacks)
# check nested stack was deleted
# 3 was the sum of 1 VM, 1 CP, 1 stack(VDU1.yaml)
self.assertEqual(3, count_after_scaleout - count_after_scalein)
# 7. LCM-Terminate
terminate_req = paramgen.terminate_vnf_min()
@ -438,3 +460,6 @@ class ServerNotificationTest(test_vnflcm_basic_common.CommonVnfLcmTest):
def test_fault_notification_queueing(self):
self.fault_notification_queueing_test()
def test_fault_notification_disabled(self):
self.fault_notification_autoheal_disabled_test()

View File

@ -64,6 +64,9 @@ _inst1 = {
'ServerNotifierFaultID': '1234'
}
},
'vnfConfigurableProperties': {
'isAutohealEnabled': True
}
}
_body = {