Merge "Fix issue of healing after scale out v1 VNF"

This commit is contained in:
Zuul 2024-12-16 04:37:44 +00:00 committed by Gerrit Code Review
commit d900a73e50
8 changed files with 1302 additions and 111 deletions

View File

@ -1034,13 +1034,8 @@ class BaseVnfLcmTest(base.BaseTackerTest):
notify_mock_responses[0],
'VnfIdentifierDeletionNotification')
def assert_instantiate_vnf(
self,
resp,
vnf_instance_id,
http_client=None,
h_client=None,
fake_server_manager=None):
def assert_instantiate_vnf(self, resp, vnf_instance_id, http_client=None,
h_client=None, fake_server_manager=None, expected_show_res=None):
if http_client is None:
http_client = self.http_client
if h_client is None:
@ -1083,14 +1078,12 @@ class BaseVnfLcmTest(base.BaseTackerTest):
'VnfLcmOperationOccurrenceNotification',
'COMPLETED')
def assert_heal_vnf(
self,
resp,
vnf_instance_id,
expected_stack_status='UPDATE_COMPLETE',
http_client=None,
h_client=None,
fake_server_manager=None):
if expected_show_res:
self._assert_show_res(vnf_instance, expected_show_res)
def assert_heal_vnf(self, resp, vnf_instance_id,
expected_stack_status='UPDATE_COMPLETE', http_client=None,
h_client=None, fake_server_manager=None, expected_show_res=None):
if http_client is None:
http_client = self.http_client
if h_client is None:
@ -1133,6 +1126,9 @@ class BaseVnfLcmTest(base.BaseTackerTest):
'VnfLcmOperationOccurrenceNotification',
'COMPLETED')
if expected_show_res:
self._assert_show_res(vnf_instance, expected_show_res)
def assert_terminate_vnf(
self,
resp,
@ -1195,17 +1191,10 @@ class BaseVnfLcmTest(base.BaseTackerTest):
'VnfLcmOperationOccurrenceNotification',
'COMPLETED')
def assert_scale_vnf(
self,
resp,
vnf_instance_id,
pre_stack_resource_list,
post_stack_resource_list,
scale_type='SCALE_OUT',
expected_stack_status='CREATE_COMPLETE',
http_client=None,
h_client=None,
fake_server_manager=None):
def assert_scale_vnf(self, resp, vnf_instance_id, pre_stack_resource_list,
post_stack_resource_list, scale_type='SCALE_OUT',
expected_stack_status='CREATE_COMPLETE', http_client=None,
h_client=None, fake_server_manager=None, expected_show_res=None):
if http_client is None:
http_client = self.http_client
if h_client is None:
@ -1263,6 +1252,9 @@ class BaseVnfLcmTest(base.BaseTackerTest):
'VnfLcmOperationOccurrenceNotification',
'COMPLETED')
if expected_show_res:
self._assert_show_res(vnf_instance, expected_show_res)
def assert_rollback_vnf(self, resp, vnf_instance_id,
fake_server_manager=None):
self.assertEqual(202, resp.status_code)
@ -1523,3 +1515,21 @@ class BaseVnfLcmTest(base.BaseTackerTest):
return resource_dict
return resource_dict['VDU'][resource_name]['image']
def _assert_show_res(self, vnf_instance, expected_show_res):
# Check result of show vnf instance
if expected_show_res['len_vnfc_res_info']:
vnfc_res_info = vnf_instance.get('instantiatedVnfInfo', {}).get(
'vnfcResourceInfo', [])
self.assertEqual(len(vnfc_res_info),
expected_show_res['len_vnfc_res_info'])
if expected_show_res['len_storage_res_info']:
storage_res_info = vnf_instance.get('instantiatedVnfInfo', {}).get(
'virtualStorageResourceInfo', [])
self.assertEqual(len(storage_res_info),
expected_show_res['len_storage_res_info'])
if expected_show_res['len_vnfc_info']:
vnfc_info = vnf_instance.get('instantiatedVnfInfo', {}).get(
'vnfcInfo', [])
self.assertEqual(len(vnfc_info),
expected_show_res['len_vnfc_info'])

View File

@ -111,6 +111,142 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
- Instantiate VNF.
- Get VNF informations.
- Scale-Out VNF
- Scale-In(is_reverse) VNF
- Terminate VNF
- Delete VNF
- Delete subscription
"""
# Create subscription and register it.
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
self._testMethodName)
request_body = fake_vnflcm.Subscription.make_create_request_body(
'http://localhost:{}{}'.format(
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
callback_url))
resp, response_body = self._register_subscription(request_body)
self.assertEqual(201, resp.status_code)
self.assert_http_header_location_for_subscription(resp.headers)
self.assert_notification_get(callback_url)
subscription_id = response_body.get('id')
self.addCleanup(
self._delete_subscription,
subscription_id)
# Pre Setting: Create vnf package.
sample_name = 'functional5'
csar_package_path = self._sample_path(sample_name)
tempname, _ = vnflcm_base._create_csar_with_unique_vnfd_id(
csar_package_path)
# upload vnf package
vnf_package_id, vnfd_id = vnflcm_base._create_and_upload_vnf_package(
self.tacker_client, user_defined_data={
"key": sample_name}, temp_csar_path=tempname)
# Post Setting: Reserve deleting vnf package.
self.addCleanup(vnflcm_base._delete_vnf_package, self.tacker_client,
vnf_package_id)
# Create vnf instance
resp, vnf_instance = self._create_vnf_instance_from_body(
fake_vnflcm.VnfInstances.make_create_request_body(vnfd_id))
vnf_instance_id = vnf_instance['id']
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
self.assert_create_vnf(resp, vnf_instance, vnf_package_id)
self.addCleanup(self._delete_vnf_instance, vnf_instance_id)
# Instantiate vnf instance
request_body = fake_vnflcm.VnfInstances.\
make_inst_request_body_include_num_dynamic(
self.vim['tenant_id'], self.ext_networks,
self.ext_mngd_networks, self.ext_link_ports, self.ext_subnets)
resp, _ = self._instantiate_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
expected_show_res = {
'len_vnfc_res_info': 2, # = 1(VDU1) + 1(VDU2)
'len_storage_res_info': 1, # = 1(VDU1)
'len_vnfc_info': 2 # = 1(VDU1) + 1(VDU2)
}
self.assert_instantiate_vnf(resp, vnf_instance_id, vnf_package_id,
expected_show_res=expected_show_res)
# Scale-out vnf instance
stack = self._get_heat_stack(vnf_instance_id)
pre_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
request_body = fake_vnflcm.VnfInstances.make_scale_request_body(
'SCALE_OUT')
resp, _ = self._scale_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
post_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
expected_show_res = {
'len_vnfc_res_info': 3, # = 2(VDU1) + 1(VDU2)
'len_storage_res_info': 2, # = 2(VDU1)
'len_vnfc_info': 3 # = 2(VDU1) + 1(VDU2)
}
self._assert_scale_vnf(resp, vnf_instance_id, vnf_package_id,
pre_stack_resource_list, post_stack_resource_list,
scale_type='SCALE_OUT', expected_stack_status='CREATE_COMPLETE',
expected_show_res=expected_show_res)
# Scale-in vnf instance
stack = self._get_heat_stack(vnf_instance_id)
pre_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
request_body = (fake_vnflcm.VnfInstances
.make_reverse_scale_request_body('SCALE_IN'))
resp, _ = self._scale_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
post_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
expected_show_res = {
'len_vnfc_res_info': 2, # = 1(VDU1) + 1(VDU2)
'len_storage_res_info': 1, # = 1(VDU1)
'len_vnfc_info': 2 # = 1(VDU1) + 1(VDU2)
}
self._assert_scale_vnf(resp, vnf_instance_id, vnf_package_id,
pre_stack_resource_list, post_stack_resource_list,
scale_type='SCALE_IN', expected_stack_status='UPDATE_COMPLETE',
expected_show_res=expected_show_res)
# Terminate VNF
stack = self._get_heat_stack(vnf_instance_id)
resources_list = self._get_heat_resource_list(stack.id)
resource_name_list = [r.resource_name for r in resources_list]
glance_image_id_list = self._get_glance_image_list_from_stack_resource(
stack.id, resource_name_list)
terminate_req_body = fake_vnflcm.VnfInstances.make_term_request_body()
resp, _ = self._terminate_vnf_instance(
vnf_instance_id, terminate_req_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
self.assert_terminate_vnf(resp, vnf_instance_id, stack.id,
resource_name_list, glance_image_id_list, vnf_package_id)
# Delete VNF
resp, _ = self._delete_vnf_instance(vnf_instance_id)
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
self.assert_delete_vnf(resp, vnf_instance_id, vnf_package_id)
# Subscription delete
resp, response_body = self._delete_subscription(subscription_id)
self.assertEqual(204, resp.status_code)
resp, _ = self._show_subscription(subscription_id)
self.assertEqual(404, resp.status_code)
def test_inst_scaling_heal(self):
"""Test basic life cycle operations with sample VNFD.
In this test case, we do following steps.
- Create subscription.
- Create VNF package.
- Upload VNF package.
- Create VNF instance.
- Instantiate VNF.
- Get VNF informations.
- Scale-Out VNF
- heal all VNF
- Scale-In VNF
- Terminate VNF
- Delete VNF
@ -161,39 +297,66 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
self.ext_mngd_networks, self.ext_link_ports, self.ext_subnets)
resp, _ = self._instantiate_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
self.assert_instantiate_vnf(resp, vnf_instance_id, vnf_package_id)
# Show vnf instance
resp, vnf_instance = self._show_vnf_instance(vnf_instance_id)
self.assertEqual(200, resp.status_code)
expected_show_res = {
'len_vnfc_res_info': 2, # = 1(VDU1) + 1(VDU2)
'len_storage_res_info': 1, # = 1(VDU1)
'len_vnfc_info': 2 # = 1(VDU1) + 1(VDU2)
}
self.assert_instantiate_vnf(resp, vnf_instance_id, vnf_package_id,
expected_show_res=expected_show_res)
# Scale-out vnf instance
stack = self._get_heat_stack(vnf_instance_id)
pre_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
request_body = fake_vnflcm.VnfInstances.make_scale_request_body(
'SCALE_OUT')
resp, _ = self._scale_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
post_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
expected_show_res = {
'len_vnfc_res_info': 3, # = 2(VDU1) + 1(VDU2)
'len_storage_res_info': 2, # = 2(VDU1)
'len_vnfc_info': 3 # = 2(VDU1) + 1(VDU2)
}
self._assert_scale_vnf(resp, vnf_instance_id, vnf_package_id,
pre_stack_resource_list, post_stack_resource_list,
scale_type='SCALE_OUT', expected_stack_status='CREATE_COMPLETE')
scale_type='SCALE_OUT', expected_stack_status='CREATE_COMPLETE',
expected_show_res=expected_show_res)
# Heal vnf (do not specify vnfc_instace_id)
# pre check heat status.
self.assert_heat_stack_status(vnf_instance_id)
# Heal
request_body = fake_vnflcm.VnfInstances.make_heal_request_body()
resp, _ = self._heal_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
expected_show_res = {
'len_vnfc_res_info': 3, # = 2(VDU1) + 1(VDU2)
'len_storage_res_info': 2, # = 2(VDU1)
'len_vnfc_info': 3 # = 2(VDU1) + 1(VDU2)
}
# post check heat status.
self.assert_heal_vnf(resp, vnf_instance_id, vnf_package_id,
expected_stack_status='CREATE_COMPLETE',
expected_show_res=expected_show_res)
# Scale-in vnf instance
stack = self._get_heat_stack(vnf_instance_id)
pre_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
request_body = (fake_vnflcm.VnfInstances
.make_reverse_scale_request_body('SCALE_IN'))
.make_scale_request_body('SCALE_IN'))
resp, _ = self._scale_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
post_stack_resource_list = self._get_heat_resource_list(stack.id, 2)
expected_show_res = {
'len_vnfc_res_info': 2, # = 1(VDU1) + 1(VDU2)
'len_storage_res_info': 1, # = 1(VDU1)
'len_vnfc_info': 2 # = 1(VDU1) + 1(VDU2)
}
self._assert_scale_vnf(resp, vnf_instance_id, vnf_package_id,
pre_stack_resource_list, post_stack_resource_list,
scale_type='SCALE_IN', expected_stack_status='UPDATE_COMPLETE')
scale_type='SCALE_IN', expected_stack_status='CREATE_COMPLETE',
expected_show_res=expected_show_res)
# Terminate VNF
stack = self._get_heat_stack(vnf_instance_id)
@ -2186,25 +2349,20 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
vnf_pkg_info,
expected_usage_state=fields.PackageUsageStateType.NOT_IN_USE)
def assert_instantiate_vnf(
self,
resp,
vnf_instance_id,
vnf_pkg_id):
super().assert_instantiate_vnf(resp, vnf_instance_id)
def assert_instantiate_vnf(self, resp, vnf_instance_id, vnf_pkg_id,
expected_show_res=None):
super().assert_instantiate_vnf(resp, vnf_instance_id,
expected_show_res=expected_show_res)
resp, vnf_pkg_info = vnflcm_base._show_vnf_package(
self.tacker_client, vnf_pkg_id)
self.assert_vnf_package_usage_state(vnf_pkg_info)
def assert_heal_vnf(
self,
resp,
vnf_instance_id,
vnf_pkg_id,
expected_stack_status='UPDATE_COMPLETE'):
super().assert_heal_vnf(
resp, vnf_instance_id, expected_stack_status=expected_stack_status)
def assert_heal_vnf(self, resp, vnf_instance_id, vnf_pkg_id,
expected_stack_status='UPDATE_COMPLETE', expected_show_res=None):
super().assert_heal_vnf(resp, vnf_instance_id,
expected_stack_status=expected_stack_status,
expected_show_res=expected_show_res)
resp, vnf_pkg_info = vnflcm_base._show_vnf_package(
self.tacker_client, vnf_pkg_id)
@ -2235,20 +2393,13 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
resp, _ = self._show_subscription(sub_id)
self.assertEqual(404, resp.status_code)
def _assert_scale_vnf(
self,
resp,
vnf_instance_id,
vnf_pkg_id,
pre_stack_resource_list,
post_stack_resource_list,
scale_type, expected_stack_status):
super().assert_scale_vnf(
resp,
vnf_instance_id,
pre_stack_resource_list,
post_stack_resource_list,
scale_type=scale_type, expected_stack_status=expected_stack_status)
def _assert_scale_vnf(self, resp, vnf_instance_id, vnf_pkg_id,
pre_stack_resource_list, post_stack_resource_list, scale_type,
expected_stack_status, expected_show_res=None):
super().assert_scale_vnf(resp, vnf_instance_id,
pre_stack_resource_list, post_stack_resource_list,
scale_type=scale_type, expected_stack_status=expected_stack_status,
expected_show_res=expected_show_res)
resp, vnf_pkg_info = vnflcm_base._show_vnf_package(
self.tacker_client, vnf_pkg_id)

View File

@ -721,6 +721,667 @@ def get_vnfd_dict(image_path=None):
return vnfd_dict
def get_vnfd_dict_for_convert_desired_capacity():
vnfd_dict = {
'imports': [
'etsi_nfv_sol001_common_types.yaml',
'etsi_nfv_sol001_vnfd_types.yaml',
'helloworld3_types.yaml'
],
'description': 'Simple deployment flavour for Sample VNF',
'topology_template': {
'inputs': {
'descriptor_id': {
'type': 'string'
},
'flavour_description': {
'type': 'string'
},
'software_version': {
'type': 'string'
},
'flavour_id': {
'type': 'string'
},
'descriptor_version': {
'type': 'string'
},
'provider': {
'type': 'string'
},
'vnfm_info': {
'entry_schema': {
'type': 'string'
},
'type': 'list'
},
'product_name': {
'type': 'string'
}
},
'node_templates': {
'VDU1': {
'requirements': [
{
'virtual_storage': 'VirtualStorage'
}
],
'type': 'tosca.nodes.nfv.Vdu.Compute',
'properties': {
'vdu_profile': {
'max_number_of_instances': 3,
'min_number_of_instances': 1
},
'description': 'VDU1 compute node',
'name': 'VDU1'
},
'capabilities': {
'virtual_compute': {
'properties': {
'requested_additional_capabilities': {
'properties': {
'requested_additional_capability_name':
'm1.tiny',
'target_performance_parameters': {
'entry_schema': 'test'
},
'support_mandatory': 'true'
}
},
'virtual_cpu': {
'num_virtual_cpu': 1
},
'virtual_memory': {
'virtual_mem_size': '512 MB'
},
'virtual_local_storage': [
{
'size_of_storage': '3 GB'
}
]
}
}
}
},
'VirtualStorage': {
'type': 'tosca.nodes.nfv.Vdu.VirtualBlockStorage',
'properties': {
'sw_image_data': {
'name': 'cirros-0.5.2-x86_64-disk',
'checksum': {
'hash': 'fake hash',
'algorithm': 'sha-256'
},
'min_ram': '256 MB',
'disk_format': 'qcow2',
'version': '0.5.2',
'container_format': 'bare',
'min_disk': '0 GB',
'size': '12 GB'
},
'virtual_block_storage_data': {
'size_of_storage': '1 GB',
'rdma_enabled': 'true'
}
}
},
'VDU1_CP3': {
'requirements': [
{
'virtual_binding': 'VDU1'
},
{
'virtual_link': 'internalVL1'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 2
}
},
'VDU2_CP5': {
'requirements': [
{
'virtual_binding': 'VDU2'
},
{
'virtual_link': 'internalVL3'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 4
}
},
'VDU2_CP4': {
'requirements': [
{
'virtual_binding': 'VDU2'
},
{
'virtual_link': 'internalVL2'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 3
}
},
'VDU2_CP1': {
'requirements': [
{
'virtual_binding': 'VDU2'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 0
}
},
'VDU2_CP3': {
'requirements': [
{
'virtual_binding': 'VDU2'
},
{
'virtual_link': 'internalVL1'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 2
}
},
'VDU2_CP2': {
'requirements': [
{
'virtual_binding': 'VDU2'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 1
}
},
'internalVL1': {
'type': 'tosca.nodes.nfv.VnfVirtualLink',
'properties': {
'connectivity_type': {
'layer_protocols': [
'ipv4'
]
},
'vl_profile': {
'virtual_link_protocol_data': [
{
'l3_protocol_data': {
'ip_version': 'ipv4',
'cidr': '33.33.0.0/24'
},
'associated_layer_protocol': 'ipv4'
}
],
'min_bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
},
'max_bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
},
'description':
'External Managed Virtual link in the VNF'
}
},
'internalVL2': {
'type': 'tosca.nodes.nfv.VnfVirtualLink',
'properties': {
'connectivity_type': {
'layer_protocols': [
'ipv4'
]
},
'vl_profile': {
'virtual_link_protocol_data': [
{
'l3_protocol_data': {
'ip_version': 'ipv4',
'cidr': '33.34.0.0/24'
},
'associated_layer_protocol': 'ipv4'
}
],
'min_bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
},
'max_bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
},
'description':
'External Managed Virtual link in the VNF'
}
},
'VDU1_CP1': {
'requirements': [
{
'virtual_binding': 'VDU1'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 0
}
},
'VDU1_CP2': {
'requirements': [
{
'virtual_binding': 'VDU1'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 1
}
},
'VNF': {
'interfaces': {
'Vnflcm': {
'instantiate': [],
'modify_information_start': [],
'modify_information_end': [],
'terminate_start': [],
'instantiate_start': [],
'terminate': [],
'instantiate_end': [],
'terminate_end': [],
'modify_information': []
}
},
'type': 'company.provider.VNF',
'properties': {
'flavour_description': 'A simple flavour'
}
},
'VDU2': {
'type': 'tosca.nodes.nfv.Vdu.Compute',
'properties': {
'vdu_profile': {
'max_number_of_instances': 1,
'min_number_of_instances': 1
},
'description': 'VDU2 compute node',
'sw_image_data': {
'name': 'cirros-0.5.2-x86_64-disk',
'checksum': {
'hash': 'fake hash',
'algorithm': 'sha-256'
},
'min_ram': '256 MB',
'disk_format': 'qcow2',
'version': '0.5.2',
'container_format': 'bare',
'min_disk': '0 GB',
'size': '12 GB'
},
'name': 'VDU2'
},
'capabilities': {
'virtual_compute': {
'properties': {
'requested_additional_capabilities': {
'properties': {
'requested_additional_capability_name':
'm1.tiny',
'target_performance_parameters': {
'entry_schema': 'test'
},
'support_mandatory': 'true'
}
},
'virtual_cpu': {
'num_virtual_cpu': 1
},
'virtual_memory': {
'virtual_mem_size': '512 MB'
},
'virtual_local_storage': [
{
'size_of_storage': '3 GB'
}
]
}
}
}
},
'VDU1_CP4': {
'requirements': [
{
'virtual_binding': 'VDU1'
},
{
'virtual_link': 'internalVL2'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 3
}
},
'VDU1_CP5': {
'requirements': [
{
'virtual_binding': 'VDU1'
},
{
'virtual_link': 'internalVL3'
}
],
'type': 'tosca.nodes.nfv.VduCp',
'properties': {
'layer_protocols': [
'ipv4'
],
'order': 4
}
},
'internalVL3': {
'type': 'tosca.nodes.nfv.VnfVirtualLink',
'properties': {
'connectivity_type': {
'layer_protocols': [
'ipv4'
]
},
'vl_profile': {
'virtual_link_protocol_data': [
{
'l3_protocol_data': {
'ip_version': 'ipv4',
'cidr': '33.35.0.0/24'
},
'associated_layer_protocol': 'ipv4'
}
],
'min_bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
},
'max_bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
},
'description': 'Internal Virtual link in the VNF'
}
}
},
'substitution_mappings': {
'node_type': 'company.provider.VNF',
'properties': {
'flavour_id': 'simple'
}
},
'policies': [
{
'scaling_aspects': {
'type': 'tosca.policies.nfv.ScalingAspects',
'properties': {
'aspects': {
'VDU1_scale': {
'max_scale_level': 2,
'description': 'VDU1 scaling aspect',
'name': 'VDU1_scale',
'step_deltas': [
'delta_1'
]
}
}
}
}
},
{
'VDU1_initial_delta': {
'type': 'tosca.policies.nfv.VduInitialDelta',
'properties': {
'initial_delta': {
'number_of_instances': 1
}
},
'targets': [
'VDU1'
]
}
},
{
'VDU2_initial_delta': {
'type': 'tosca.policies.nfv.VduInitialDelta',
'properties': {
'initial_delta': {
'number_of_instances': 1
}
},
'targets': [
'VDU2'
]
}
},
{
'VDU1_scaling_aspect_deltas': {
'type': 'tosca.policies.nfv.VduScalingAspectDeltas',
'properties': {
'deltas': {
'delta_1': {
'number_of_instances': 1
}
},
'aspect': 'VDU1_scale'
},
'targets': [
'VDU1'
]
}
},
{
'instantiation_levels': {
'type': 'tosca.policies.nfv.InstantiationLevels',
'properties': {
'default_level': 'instantiation_level_1',
'levels': {
'instantiation_level_1': {
'scale_info': {
'VDU1_scale': {
'scale_level': 0
}
},
'description': 'Smallest size'
},
'instantiation_level_2': {
'scale_info': {
'VDU1_scale': {
'scale_level': 2
}
},
'description': 'Largest size'
}
}
}
}
},
{
'VDU1_instantiation_levels': {
'type': 'tosca.policies.nfv.VduInstantiationLevels',
'properties': {
'levels': {
'instantiation_level_1': {
'number_of_instances': 1
},
'instantiation_level_2': {
'number_of_instances': 3
}
}
},
'targets': [
'VDU1'
]
}
},
{
'VDU2_instantiation_levels': {
'type': 'tosca.policies.nfv.VduInstantiationLevels',
'properties': {
'levels': {
'instantiation_level_1': {
'number_of_instances': 1
},
'instantiation_level_2': {
'number_of_instances': 1
}
}
},
'targets': [
'VDU2'
]
}
},
{
'internalVL1_instantiation_levels': {
'type':
'tosca.policies.nfv.'
'VirtualLinkInstantiationLevels',
'properties': {
'levels': {
'instantiation_level_1': {
'bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
},
'instantiation_level_2': {
'bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
}
}
},
'targets': [
'internalVL1'
]
}
},
{
'internalVL2_instantiation_levels': {
'type':
'tosca.policies.nfv.'
'VirtualLinkInstantiationLevels',
'properties': {
'levels': {
'instantiation_level_1': {
'bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
},
'instantiation_level_2': {
'bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
}
}
},
'targets': [
'internalVL2'
]
}
},
{
'internalVL3_instantiation_levels': {
'type':
'tosca.policies.nfv.'
'VirtualLinkInstantiationLevels',
'properties': {
'levels': {
'instantiation_level_1': {
'bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
},
'instantiation_level_2': {
'bitrate_requirements': {
'leaf': 1048576,
'root': 1048576
}
}
}
},
'targets': [
'internalVL3'
]
}
},
{
'policy_antiaffinity_vdu1': {
'type': 'tosca.policies.nfv.AntiAffinityRule',
'properties': {
'scope': 'zone'
},
'targets': [
'VDU1'
]
}
},
{
'policy_antiaffinity_vdu2': {
'type': 'tosca.policies.nfv.AntiAffinityRule',
'properties': {
'scope': 'zone'
},
'targets': [
'VDU2'
]
}
}
]
},
'tosca_definitions_version': 'tosca_simple_yaml_1_2'
}
return vnfd_dict
def get_dummy_vim_connection_info():
return {'access_info': {
'auth_url': 'fake/url',

View File

@ -14,9 +14,11 @@
# limitations under the License.
import os
import shutil
import ddt
from oslo_config import cfg
import yaml
from tacker.common import exceptions
from tacker.objects import fields
@ -24,6 +26,7 @@ from tacker.objects.instantiate_vnf_req import InstantiateVnfRequest
from tacker.objects.vim_connection import VimConnectionInfo
from tacker.tests.unit import base
from tacker.tests.unit.vnflcm import fakes
from tacker.tests import utils
from tacker.tests import uuidsentinel
from tacker.vnflcm import utils as vnflcm_utils
@ -140,3 +143,72 @@ class VnfLcmUtilsTestCase(base.TestCase):
'VduInitialDelta parameter from policies '
'definition in VNFD.')
self.assertEqual(expected_error, str(error))
def test_convert_desired_capacity_scale_status_none(self):
vnfd_dict = fakes.get_vnfd_dict_for_convert_desired_capacity()
etsi_common_file_path = utils.test_etc_sample('etsi/nfv',
'common/Definitions/etsi_nfv_sol001_common_types.yaml')
etsi_vnfd_file_path = utils.test_etc_sample('etsi/nfv',
'common/Definitions/etsi_nfv_sol001_vnfd_types.yaml')
helloworld_path = utils.test_etc_sample('etsi/nfv',
'common_artifact/Definitions/helloworld3_types.yaml')
etsi_common_file_path_tmp = os.path.join(
os.path.dirname(__file__), 'etsi_nfv_sol001_common_types.yaml')
types_file_path_tmp = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'types.yaml'))
shutil.copy(etsi_common_file_path, etsi_common_file_path_tmp)
self.addCleanup(os.remove, etsi_common_file_path_tmp)
shutil.copy(helloworld_path, types_file_path_tmp)
self.addCleanup(os.remove, types_file_path_tmp)
with open(types_file_path_tmp) as f:
data = yaml.safe_load(f)
data['imports'] = [etsi_common_file_path, etsi_vnfd_file_path]
with open(types_file_path_tmp, 'w', encoding='utf-8') as f:
yaml.dump(data, f)
vnfd_dict['imports'] = [etsi_common_file_path, etsi_vnfd_file_path,
types_file_path_tmp]
desired_capacity = vnflcm_utils._convert_desired_capacity(
'instantiation_level_1', vnfd_dict, 'VDU1')
self.assertEqual(desired_capacity, 1)
def test_convert_desired_capacity_scale_status_specified(self):
vnfd_dict = fakes.get_vnfd_dict_for_convert_desired_capacity()
etsi_common_file_path = utils.test_etc_sample('etsi/nfv',
'common/Definitions/etsi_nfv_sol001_common_types.yaml')
etsi_vnfd_file_path = utils.test_etc_sample('etsi/nfv',
'common/Definitions/etsi_nfv_sol001_vnfd_types.yaml')
helloworld_path = utils.test_etc_sample('etsi/nfv',
'common_artifact/Definitions/helloworld3_types.yaml')
etsi_common_file_path_tmp = os.path.join(
os.path.dirname(__file__), 'etsi_nfv_sol001_common_types.yaml')
types_file_path_tmp = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'types.yaml'))
shutil.copy(etsi_common_file_path, etsi_common_file_path_tmp)
self.addCleanup(os.remove, etsi_common_file_path_tmp)
shutil.copy(helloworld_path, types_file_path_tmp)
self.addCleanup(os.remove, types_file_path_tmp)
with open(types_file_path_tmp) as f:
data = yaml.safe_load(f)
data['imports'] = [etsi_common_file_path, etsi_vnfd_file_path]
with open(types_file_path_tmp, 'w', encoding='utf-8') as f:
yaml.dump(data, f)
vnfd_dict['imports'] = [etsi_common_file_path, etsi_vnfd_file_path,
types_file_path_tmp]
scale_status = [{'aspect_id': 'VDU1_scale', 'scale_level': 1}]
desired_capacity = vnflcm_utils._convert_desired_capacity(
'instantiation_level_1', vnfd_dict, 'VDU1',
scale_status=scale_status)
self.assertEqual(desired_capacity, 2)

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import ddt
import importlib
import json
@ -327,6 +328,103 @@ class TestOpenStack(base.FixturedTestCase):
grant_info=grant_info_test,
vnf_instance=vnf_instance)
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._create_stack_with_user_data')
@mock.patch('tacker.tosca.utils.get_scale_group')
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._format_base_hot')
@mock.patch('tacker.vnflcm.utils._get_vnflcm_interface')
@mock.patch('tacker.vnflcm.utils.get_base_nest_hot_dict')
@mock.patch('tacker.common.clients.OpenstackClients')
def test_create_normal_with_scaling_group_and_scale_status(
self, mock_OpenstackClients_heat, mock_get_base_hot_dict,
mock_get_vnflcm_interface, mock_format_base_hot,
mock_get_scale_group, mock_create_stack_with_user_data):
vnf = utils.get_dummy_vnf_etsi(instance_id=self.instance_uuid,
scaling_group=True, flavour='simple')
vnf['placement_attr'] = {'region_name': 'dummy_region'}
s_status = {'aspect_id': 'VDU1_scale', 'scale_level': 1}
vnf['scale_status'] = [objects.ScaleInfo(**s_status)]
vnf_package_path_test = self._nfv_sample(
'user_data_sample_normal_scaling')
inst_req_info_test = type('', (), {})
test_json = self._json_load(
'instantiate_vnf_request_lcm_userdata.json')
inst_req_info_test.additional_params = test_json['additionalParams']
inst_req_info_test.ext_virtual_links = None
inst_req_info_test.flavour_id = 'simple'
vnf_resource = type('', (), {})
vnf_resource.resource_identifier = constants.INVALID_UUID
grant_info_test = {'vdu_name': {vnf_resource}}
nested_hot_dict = {'parameters': {'vnf': 'test'}}
base_hot_dict = self._read_file(scale_input_file=True)
mock_get_base_hot_dict.return_value = (base_hot_dict, nested_hot_dict)
mock_get_scale_group.return_value = {
'scaleGroupDict': {'VDU1_scale': {'vdu': ['VDU1'],
'num': 1, 'maxLevel': 2, 'initialNum': 1,
'initialLevel': 0, 'default': 1}}}
vnf_instance = fd_utils.get_vnf_instance_object()
vnf['before_error_point'] = fields.ErrorPoint.PRE_VIM_CONTROL
self.openstack.create(self.plugin, self.context, vnf,
self.auth_attr, inst_req_info=inst_req_info_test,
vnf_package_path=vnf_package_path_test,
grant_info=grant_info_test,
vnf_instance=vnf_instance)
self.assertEqual(mock_create_stack_with_user_data.call_count, 1)
# Expect desired_capacity in base_hot_dict to be changed
# by specified scale_statue
(base_hot_dict['resources']['VDU1_scale']['properties']
['desired_capacity']) = 2
mock_create_stack_with_user_data.assert_called_with(
mock.ANY, mock.ANY, base_hot_dict, mock.ANY, mock.ANY
)
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._create_stack_with_user_data')
@mock.patch('tacker.tosca.utils.get_scale_group')
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._format_base_hot')
@mock.patch('tacker.vnflcm.utils._get_vnflcm_interface')
@mock.patch('tacker.vnflcm.utils.get_base_nest_hot_dict')
@mock.patch('tacker.common.clients.OpenstackClients')
def test_create_normal_with_scaling_group_and_not_scale_status(
self, mock_OpenstackClients_heat, mock_get_base_hot_dict,
mock_get_vnflcm_interface, mock_format_base_hot,
mock_get_scale_group, mock_create_stack_with_user_data):
vnf = utils.get_dummy_vnf_etsi(instance_id=self.instance_uuid,
scaling_group=True, flavour='simple')
vnf['placement_attr'] = {'region_name': 'dummy_region'}
vnf_package_path_test = self._nfv_sample(
'user_data_sample_normal_scaling')
inst_req_info_test = type('', (), {})
test_json = self._json_load(
'instantiate_vnf_request_lcm_userdata.json')
inst_req_info_test.additional_params = test_json['additionalParams']
inst_req_info_test.ext_virtual_links = None
inst_req_info_test.flavour_id = 'simple'
vnf_resource = type('', (), {})
vnf_resource.resource_identifier = constants.INVALID_UUID
grant_info_test = {'vdu_name': {vnf_resource}}
nested_hot_dict = {'parameters': {'vnf': 'test'}}
base_hot_dict = self._read_file(scale_input_file=True)
mock_get_base_hot_dict.return_value = (base_hot_dict, nested_hot_dict)
mock_get_scale_group.return_value = {
'scaleGroupDict': {'VDU1_scale': {'vdu': ['VDU1'],
'num': 1, 'maxLevel': 2, 'initialNum': 1,
'initialLevel': 0, 'default': 1}}}
vnf_instance = fd_utils.get_vnf_instance_object()
vnf['before_error_point'] = fields.ErrorPoint.PRE_VIM_CONTROL
self.openstack.create(self.plugin, self.context, vnf,
self.auth_attr, inst_req_info=inst_req_info_test,
vnf_package_path=vnf_package_path_test,
grant_info=grant_info_test,
vnf_instance=vnf_instance)
self.assertEqual(mock_create_stack_with_user_data.call_count, 1)
# Expect desired_capacity in base_hot_dict to be unchanged
mock_create_stack_with_user_data.assert_called_with(
mock.ANY, mock.ANY, base_hot_dict, mock.ANY, mock.ANY
)
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._format_base_hot')
@mock.patch('tacker.vnflcm.utils._get_vnflcm_interface')
@ -825,30 +923,45 @@ class TestOpenStack(base.FixturedTestCase):
grant_info=grant_info_test,
vnf_instance=vnf_instance)
@mock.patch('tacker.vnflcm.utils.get_vnfd_dict')
@mock.patch('tacker.common.clients.OpenstackClients')
def test_create_heat_stack(self, mock_OpenstackClients_heat):
def test_create_heat_stack(self, mock_OpenstackClients_heat,
mock_vnfd_dict):
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
vnf['placement_attr'] = {'region_name': 'dummy_region'}
vnf_package_path = None
vnf['before_error_point'] = fields.ErrorPoint.PRE_VIM_CONTROL
mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf()
vnf_instance = fd_utils.get_vnf_instance_object()
inst_req_info = fd_utils.get_instantiate_vnf_request()
self.assertIsNone(vnf.get('scale_status', None))
self.openstack.create(self.plugin, self.context, vnf,
self.auth_attr, vnf_package_path)
self.auth_attr, vnf_package_path, inst_req_info=inst_req_info,
grant_info=None, vnf_instance=vnf_instance)
self.assertIsNotNone(vnf.get('scale_status', None))
@mock.patch('tacker.vnflcm.utils.get_vnfd_dict')
@mock.patch('tacker.common.clients.OpenstackClients')
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._update_stack')
@mock.patch.object(hc.HeatClient, "find_stack")
def test_create_heat_stack_with_error_point_post_vim_control(self,
mock_find_stack, mock_update_stack,
mock_OpenstackClients_heat):
mock_OpenstackClients_heat, mock_vnfd_dict):
vnf = utils.get_dummy_vnf(instance_id=self.instance_uuid)
vnf['placement_attr'] = {'region_name': 'dummy_region'}
vnf_package_path = None
vnf['before_error_point'] = fields.ErrorPoint.POST_VIM_CONTROL
mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf()
vnf_instance = fd_utils.get_vnf_instance_object()
inst_req_info = fd_utils.get_instantiate_vnf_request()
self.assertIsNone(vnf.get('scale_status', None))
self.openstack.create(self.plugin, self.context, vnf,
self.auth_attr, vnf_package_path)
self.auth_attr, vnf_package_path, inst_req_info=inst_req_info,
grant_info=None, vnf_instance=vnf_instance)
mock_find_stack.assert_called_once()
mock_update_stack.assert_called_once()
self.assertIsNotNone(vnf.get('scale_status', None))
@mock.patch('tacker.common.clients.OpenstackClients')
def test_create_userdata_none(self, mock_OpenstackClients_heat):
@ -1919,11 +2032,12 @@ class TestOpenStack(base.FixturedTestCase):
mock_log.info.assert_called()
self.assertEqual(delete_image_url.call_count, 2)
@mock.patch('tacker.vnflcm.utils.get_vnfd_dict')
@mock.patch('tacker.vnfm.infra_drivers.openstack.translate_template.'
'TOSCAToHOT._get_unsupported_resource_props')
@mock.patch.object(hc.HeatClient, "find_stack")
def test_instantiate_vnf(self, mock_get_unsupported_resource_props,
mock_find_stack):
mock_find_stack, mock_vnfd_dict):
vim_connection_info = fd_utils.get_vim_connection_info_object()
inst_req_info = fd_utils.get_instantiate_vnf_request()
grant_response = fd_utils.get_grant_response_dict()
@ -1939,7 +2053,7 @@ class TestOpenStack(base.FixturedTestCase):
'before_error_point': fields.ErrorPoint.PRE_VIM_CONTROL,
'status': ''
}
mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf()
instance_id = self.openstack.instantiate_vnf(
self.context, vnf_instance, vnfd_dict, vim_connection_info,
inst_req_info, grant_response, self.plugin)
@ -3320,8 +3434,8 @@ class TestOpenStack(base.FixturedTestCase):
vnf_virtual_link_resource_info[0].vnf_link_ports[0].
resource_handle.resource_id)
@mock.patch.object(hc.HeatClient, "resource_get")
@mock.patch.object(hc.HeatClient, "resource_get_list")
@mock.patch.object(hc.HeatClient, 'resource_get')
@mock.patch.object(hc.HeatClient, 'resource_get_list')
def test_scale_resource_update_scale_out_with_grant(
self, mock_list, mock_resource):
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
@ -3332,11 +3446,11 @@ class TestOpenStack(base.FixturedTestCase):
number_of_steps=1)
vim_connection_info = fd_utils.get_vim_connection_info_object()
vnf_info = {}
v_s_resource_info = fd_utils.\
get_virtual_storage_resource_info_for_grant(desc_id="storage1")
v_s_resource_info = (fd_utils.
get_virtual_storage_resource_info_for_grant(desc_id='storage1'))
storage_resource_ids = [v_s_resource_info.id]
vnfc_resource_info = fd_utils.get_vnfc_resource_info_with_vnf_info(
vdu_id="workerNode", storage_resource_ids=storage_resource_ids)
vdu_id='workerNode', storage_resource_ids=storage_resource_ids)
vnfc_resource_info_list = []
vnfc_resource_info_list.append(vnfc_resource_info)
virtual_st_rsc_list = []
@ -3422,16 +3536,25 @@ class TestOpenStack(base.FixturedTestCase):
self.assertEqual(
vnf_instance.instantiated_vnf_info.vnfc_resource_info[0].id,
uuidsentinel.vnfc_resource_id)
return_vnfc_res = \
vnf_instance.instantiated_vnf_info.vnfc_resource_info[0]
return_vnfc_res = (
vnf_instance.instantiated_vnf_info.vnfc_resource_info[0])
self.assertEqual(return_vnfc_res.vnfc_cp_info[0].id,
uuidsentinel.vnfc_cp_info_id)
self.assertEqual(uuidsentinel.storage_id_1,
vnf_instance.instantiated_vnf_info.
virtual_storage_resource_info[0].id)
self.assertEqual(
len(vnf_instance.instantiated_vnf_info.vnfc_info), 1)
self.assertEqual(
return_vnfc_res.compute_resource.vim_level_resource_type,
'OS::Nova::Server')
self.assertEqual(
(vnf_instance.instantiated_vnf_info.
virtual_storage_resource_info[0].storage_resource.
vim_level_resource_type), 'OS::Cinder::Volume')
@mock.patch.object(hc.HeatClient, "resource_get")
@mock.patch.object(hc.HeatClient, "resource_get_list")
@mock.patch.object(hc.HeatClient, 'resource_get')
@mock.patch.object(hc.HeatClient, 'resource_get_list')
def test_scale_resource_update_scale_out(self, mock_list, mock_resource):
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
vnf_instance = fd_utils.get_vnf_instance_object(
@ -3440,11 +3563,11 @@ class TestOpenStack(base.FixturedTestCase):
aspect_id='worker_instance',
number_of_steps=1)