[WIP] Heal and scale method support of lcm_user_data

Customization of stack parameter during heal and scale through
lcm_user_data.

Implement: blueprint stack-parameter-customization
Change-Id: I393c0fd3ee32ee545ce5adf70b57af97d4177f2c
This commit is contained in:
Renu 2022-01-19 11:06:09 +00:00 committed by renu rani
parent ef9384cc1b
commit 9185acab66
7 changed files with 687 additions and 29 deletions

View File

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

View File

@ -1768,9 +1768,14 @@ class TestVnflcmDriver(db_base.SqlTestCase):
vim_type="openstack")
scale_name_list = ["fake"]
grp_id = "fake_id"
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED,
task_state=fields.VnfInstanceTaskState.SCALING)
driver = vnflcm_driver.VnfLcmDriver()
driver.scale(self.context, vnf_info, scale_vnf_request,
vim_connection_info, scale_name_list, grp_id)
driver.scale(self.context, vnf_info, vnf_instance,
scale_vnf_request, vim_connection_info,
scale_name_list, grp_id)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@ -1796,12 +1801,17 @@ class TestVnflcmDriver(db_base.SqlTestCase):
vim_type="openstack")
scale_name_list = ["fake"]
grp_id = "fake_id"
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED,
task_state=fields.VnfInstanceTaskState.SCALING)
with open(vnf_info["attributes"]["heat_template"], "r") as f:
mock_safe_load.return_value = yaml.safe_load(f)
print(mock_safe_load.return_value)
driver = vnflcm_driver.VnfLcmDriver()
driver.scale(self.context, vnf_info, scale_vnf_request,
vim_connection_info, scale_name_list, grp_id)
driver.scale(self.context, vnf_info, vnf_instance,
scale_vnf_request, vim_connection_info,
scale_name_list, grp_id)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@ -1827,12 +1837,16 @@ class TestVnflcmDriver(db_base.SqlTestCase):
vim_type="openstack")
scale_name_list = ["fake"]
grp_id = "fake_id"
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED,
task_state=fields.VnfInstanceTaskState.SCALING)
with open(vnf_info["attributes"]["heat_template"], "r") as f:
mock_safe_load.return_value = yaml.safe_load(f)
print(mock_safe_load.return_value)
driver = vnflcm_driver.VnfLcmDriver()
driver.scale(self.context, vnf_info, scale_vnf_request,
vim_connection_info, scale_name_list, grp_id)
driver.scale(self.context, vnf_info, vnf_instance,
scale_vnf_request,
vim_connection_info, scale_name_list, grp_id)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@ -1858,12 +1872,17 @@ class TestVnflcmDriver(db_base.SqlTestCase):
vim_type="openstack")
scale_name_list = ["fake"]
grp_id = "fake_id"
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED,
task_state=fields.VnfInstanceTaskState.SCALING)
with open(vnf_info["attributes"]["heat_template"], "r") as f:
mock_safe_load.return_value = yaml.safe_load(f)
print(mock_safe_load.return_value)
driver = vnflcm_driver.VnfLcmDriver()
driver.scale(self.context, vnf_info, scale_vnf_request,
vim_connection_info, scale_name_list, grp_id)
driver.scale(self.context, vnf_info, vnf_instance,
scale_vnf_request,
vim_connection_info, scale_name_list, grp_id)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@ -1968,6 +1987,9 @@ class TestVnflcmDriver(db_base.SqlTestCase):
'username': 'test_user',
'project_name': 'test_project'}}
self.vim_client.get_vim.return_value = vim_obj
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED,
task_state=fields.VnfInstanceTaskState.SCALING)
driver.scale_vnf(self.context, vnf_info, vnf_instance,
scale_vnf_request)
@ -1993,13 +2015,16 @@ class TestVnflcmDriver(db_base.SqlTestCase):
scale_name_list = ["fake"]
grp_id = "fake_id"
driver = vnflcm_driver.VnfLcmDriver()
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED,
task_state=fields.VnfInstanceTaskState.SCALING)
msg = 'Unknown scale type'
self.assertRaisesRegex(exceptions.VnfScaleFailed,
msg,
driver.scale,
self.context,
vnf_info,
vnf_instance,
scale_vnf_request,
vim_connection_info,
scale_name_list,
@ -2029,11 +2054,15 @@ class TestVnflcmDriver(db_base.SqlTestCase):
driver = vnflcm_driver.VnfLcmDriver()
msg = 'Unknown vim type'
vnf_instance = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED,
task_state=fields.VnfInstanceTaskState.SCALING)
self.assertRaisesRegex(exceptions.VnfScaleFailed,
msg,
driver.scale,
self.context,
vnf_info,
vnf_instance,
scale_vnf_request,
vim_connection_info,
scale_name_list,

View File

@ -13,14 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import importlib
import json
import os
import tempfile
from unittest import mock
import ddt
import requests
import tempfile
import yaml
from heatclient.v1 import resources
@ -43,7 +41,7 @@ from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import \
from tacker.tests import uuidsentinel
from tacker.vnfm.infra_drivers.openstack import heat_client as hc
from tacker.vnfm.infra_drivers.openstack import openstack
from unittest import mock
vnf_dict = {
'instance_id': 'd1121d3c-368b-4ac2-b39d-835aa3e4ccd8'
@ -2169,7 +2167,7 @@ class TestOpenStack(base.FixturedTestCase):
inst_vnf_info = fd_utils.get_vnf_instantiated_info(
virtual_storage_resource_info=[v_s_resource_info],
vnfc_resource_info=[vnfc_resource_info])
inst_vnf_info.additional_params = None
vnf_instance = fd_utils.get_vnf_instance_object(
instantiated_vnf_info=inst_vnf_info)
@ -2205,6 +2203,7 @@ class TestOpenStack(base.FixturedTestCase):
vnf_lcm_op_occs = fd_utils.get_lcm_op_occs_object(
error_point=fields.ErrorPoint.PRE_VIM_CONTROL)
mock_get_vnflcm_op_occs.return_value = vnf_lcm_op_occs
self.openstack.heal_vnf(
self.context, vnf_instance, vim_connection_info,
heal_vnf_request)
@ -2240,7 +2239,7 @@ class TestOpenStack(base.FixturedTestCase):
instantiated_vnf_info=inst_vnf_info)
vim_connection_info = fd_utils.get_vim_connection_info_object()
inst_vnf_info.additional_params = None
heal_vnf_request = objects.HealVnfRequest(
vnfc_instance_id=[vnfc_resource_info.id],
cause="healing request")

View File

@ -15,8 +15,10 @@ import os
import testtools
import yaml
from tacker import objects
from tacker.objects import instantiate_vnf_req
from tacker.tests import constants
from tacker.tests import uuidsentinel
from tacker.vnfm.lcm_user_data import utils
default_initial_param_dict = {
@ -198,3 +200,24 @@ class TestUtils(testtools.TestCase):
inst_req_info.ext_virtual_links = None
cpd_vl_dict = utils.create_cpd_vl_dict(base_hot_dict, inst_req_info)
self.assertEqual({}, cpd_vl_dict)
def test_create_desired_capacity_dict(self):
base_hot_dict = {}
vnfd_dict = {}
base_hot_dict['heat_template'] = self._read_file(
"hot_lcm_user_data_with_scale.yaml")
expected_desired_capaity = {'VDU1_scale': 1}
vnfd_dict = self._read_file('vnf_vnfd_dict_scale.yaml')
s_status = {"aspect_id": "VDU1_scale", "scale_level": 0}
scale_status = objects.ScaleInfo(**s_status)
instantiated_vnf_info = {
'flavour_id': uuidsentinel.flavour_id,
'vnf_state': 'STARTED',
'instance_id': '',
"scale_status": [scale_status]
}
inst_req_info = objects.InstantiatedVnfInfo(**instantiated_vnf_info)
actual_desired_capacity = utils.get_desired_capacity_dict(
base_hot_dict, vnfd_dict, inst_req_info)
self.assertEqual(actual_desired_capacity, expected_desired_capaity)

View File

@ -1180,8 +1180,9 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
# action_driver
LOG.debug("vnf_info['vnfd']['attributes'] %s",
vnf_info['vnfd']['attributes'])
self.scale(context, vnf_info, scale_vnf_request,
vim_connection_info, scale_name_list, grp_id)
self.scale(context, vnf_info, vnf_instance,
scale_vnf_request, vim_connection_info,
scale_name_list, grp_id)
@log.log
@revert_to_error_scale
@ -1241,6 +1242,7 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
self,
context,
vnf_info,
vnf_instance,
scale_vnf_request,
vim_connection_info,
scale_name_list,

View File

@ -322,7 +322,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
# Find existing stack
name_filter = None
if 'stack_name' in vnf['attributes'].keys():
name_filter = vnf['attributes']['stack_name']
name_filter = vnf['attributes']['stack_param']
else:
name_filter = (vnf['name'].replace(' ', '_')
+ '_' + vnf['id'])
@ -402,7 +402,6 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
vdu_name = rsc.vdu_id
if not vdu_name:
continue
if scale_group_dict:
base_hot_dict, nested_hot_dict, vdu_none_flg = \
self._update_hot_available_scale(
@ -1458,6 +1457,64 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
for name, value in nested_hot_dict.items():
files_dict[name] = self._format_base_hot(value)
stack_update_param['files'] = files_dict
additional_param = inst_vnf_info.additional_params
if additional_param is not None:
param = yaml.safe_load(vnf_dict['attributes']['stack_name'])
vnf_instance = vnf_instance
lcm_user_data_path = None
lcm_user_data_class = None
lcm_user_data_path = additional_param.get(
'lcm-operation-user-data')
lcm_user_data_class = additional_param.get(
'lcm-operation-user-data-class')
LOG.debug('UserData path: %s', lcm_user_data_path)
LOG.debug('UserData class: %s', lcm_user_data_class)
vnf_pack_path = vnflcm_utils._get_vnf_package_path(
context, vnf_dict['vnfd_id'])
LOG.debug('VNF package path: %s', vnf_pack_path)
lcm_user_data_module = os.path.splitext(
os.path.basename(lcm_user_data_path))[0]
LOG.debug('UserData module name: %s', lcm_user_data_module)
try:
spec = importlib.util.spec_from_file_location(
lcm_user_data_module,
vnf_pack_path + '/' + lcm_user_data_path)
lcm_user_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(lcm_user_module)
LOG.debug('lcm_user_module: %s', lcm_user_module)
except Exception:
error_reason = _(
"failed to get UserData path based on "
"lcm-operation-user-data from additionalParams.")
raise vnfm.LCMUserDataFailed(reason=error_reason)
try:
lcm_user_class = getattr(lcm_user_module, lcm_user_data_class)
user_method_heal = getattr(lcm_user_class, "heal", None)
except Exception:
error_reason = _(
"failed to get UserData class based on "
"lcm-operation-user-data-class from additionalParams.")
raise vnfm.LCMUserDataFailed(reason=error_reason)
LOG.debug('Check target method: {}'.format(user_method_heal))
if callable(user_method_heal):
LOG.debug('The above is callable')
if base_hot_dict is None:
error_reason = _("failed to get Base HOT.")
raise vnfm.LCMUserDataFailed(reason=error_reason)
if base_hot_dict is None:
nested_hot_dict = {}
param_base_hot_dict = copy.deepcopy(nested_hot_dict)
param_base_hot_dict['heat_template'] = base_hot_dict
vnfd_dict = yaml.safe_load(
vnf_dict['vnfd']['attributes']['vnfd_' +
inst_vnf_info.flavour_id])
vnfc_resource_info = \
self._get_vnfc_resources_from_heal_request(
inst_vnf_info, heal_vnf_request)
updated_stack_param = user_method_heal(
param_base_hot_dict, vnfd_dict, heal_vnf_request,
vnf_instance, inst_vnf_info, param, vnfc_resource_info)
stack_param = {**updated_stack_param}
if stack_param:
stack_update_param['parameters'] = stack_param
@ -1848,7 +1905,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
@log.log
def scale_in_reverse(self, context, plugin, auth_attr, vnf_info,
scale_vnf_request, region_name,
vnf_instance, scale_vnf_request, region_name,
scale_name_list, grp_id):
heatclient = hc.HeatClient(auth_attr, region_name)
if grp_id:
@ -1858,13 +1915,75 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
resource_name=name,
mark_unhealthy=True,
resource_status_reason='Scale')
paramDict = {}
scale_json = vnf_info['attributes']['scale_group']
scaleGroupDict = jsonutils.loads(scale_json)
for name, value in scaleGroupDict['scaleGroupDict'].items():
paramDict[name + '_desired_capacity'] = value['default']
paramDict[scale_vnf_request.aspect_id + '_desired_capacity'] = \
vnf_info['res_num']
inst_vnf_info = vnf_instance.instantiated_vnf_info
vnf = vnf_info
stack_param = {}
updated_stack_param = {}
if 'stack_param' in vnf['attributes'].keys():
param = yaml.safe_load(vnf['attributes']['stack_param'])
additional_param = inst_vnf_info.additional_params
if additional_param is not None:
lcm_user_data_path = None
lcm_user_data_class = None
lcm_user_data_path = additional_param.get(
'lcm-operation-user-data')
lcm_user_data_class = additional_param.get(
'lcm-operation-user-data-class')
LOG.debug('UserData path: %s', lcm_user_data_path)
LOG.debug('UserData class: %s', lcm_user_data_class)
vnf_pack_path = vnflcm_utils._get_vnf_package_path(
context, vnf['vnfd_id'])
LOG.debug('VNF package path: %s', vnf_pack_path)
lcm_user_data_module = os.path.splitext(
os.path.basename(lcm_user_data_path))[0]
LOG.debug('UserData module name: %s', lcm_user_data_module)
try:
spec = importlib.util.spec_from_file_location(
lcm_user_data_module,
vnf_pack_path + '/' + lcm_user_data_path)
lcm_user_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(lcm_user_module)
LOG.debug('lcm_user_module: %s', lcm_user_module)
except Exception:
error_reason = _(
"failed to get UserData path based on "
"lcm-operation-user-data from additionalParams.")
raise vnfm.LCMUserDataFailed(reason=error_reason)
try:
lcm_user_class = getattr(lcm_user_module,
lcm_user_data_class)
user_method_scale = getattr(lcm_user_class, "scale", None)
except Exception:
error_reason = _(
"failed to get UserData class based on "
"lcm-operation-user-data-class from additionalParams.")
raise vnfm.LCMUserDataFailed(reason=error_reason)
if callable(user_method_scale):
base_hot_dict, nested_hot_dict = \
vnflcm_utils._get_base_nest_hot_dict(
context, inst_vnf_info.flavour_id,
vnf_instance.vnfd_id)
if base_hot_dict is None:
error_reason = _("failed to get Base HOT.")
raise vnfm.LCMUserDataFailed(reason=error_reason)
if base_hot_dict is None:
nested_hot_dict = {}
param_base_hot_dict = copy.deepcopy(nested_hot_dict)
param_base_hot_dict['heat_template'] = base_hot_dict
vnfd_dict = yaml.safe_load(
vnf['vnfd']['attributes']['vnfd_' +
inst_vnf_info.flavour_id])
updated_stack_param = user_method_scale(
param_base_hot_dict, vnfd_dict, scale_vnf_request,
vnf_instance, inst_vnf_info, param, vnf['res_num'])
stack_param = {**stack_param, **updated_stack_param}
else:
stack_param = {**stack_param, **param}
else:
stack_param = {**stack_param, **param}
paramDict = stack_param
stack_update_param = {
'parameters': paramDict,
'existing': True}

View File

@ -14,8 +14,9 @@
import copy
from oslo_log import log as logging
from oslo_serialization import jsonutils
from tacker.common.utils import MemoryUnit
from tacker.tosca import utils as tosca_utils
"""Define util functions that can be used in UserData.
@ -412,3 +413,85 @@ def _create_fixed_ips_list(ext_cp):
fixed_ips_lst.append(fixed_ips)
return fixed_ips_lst
def _create_scale_group_dict(base_hot_dict, vnfd_dict, inst_req_info):
base_hot = base_hot_dict['heat_template']
LOG.debug("base_hot: %s", base_hot)
scaling_group_dict = {}
for name, rsc in base_hot.get('resources').items():
if rsc['type'] == 'OS::Heat::AutoScalingGroup':
key_name = name.replace('_group', '')
scaling_group_dict[key_name] = name
LOG.debug("scaling_group_dict: %s", scaling_group_dict)
if scaling_group_dict:
vnf = {'attributes': {'scaling_group_names':
jsonutils.dump_as_bytes(scaling_group_dict)}}
scale_group_dict = tosca_utils.get_scale_group(
vnf, vnfd_dict, inst_req_info)
LOG.debug("scale_group_dict: %s", scale_group_dict)
return scale_group_dict
else:
LOG.debug("no scale_group_dict")
return {}
def create_desired_capacity_dict(base_hot_dict, vnfd_dict, inst_req_info):
"""Create a dict containing information about desired capacity.
:param base_hot_dict: dict(Base HOT dict format)
:param vnfd_dict: dict(VNFD dict format)
:param inst_req_info: dict(Instantiation request information format)
:return: dict(Scaling aspect name, Desired capacity value)
"""
scale_group_dict = _create_scale_group_dict(
base_hot_dict, vnfd_dict, inst_req_info)
param_dict = {}
if scale_group_dict.get('scaleGroupDict'):
for name, value in scale_group_dict['scaleGroupDict'].items():
param_dict[name] = value['default']
LOG.info("desired_capacity dict: %s", param_dict)
return param_dict
def _calc_desired_capacity(inst_vnf_info, name, value):
for scale_status in inst_vnf_info.scale_status:
if scale_status.aspect_id == name:
LOG.debug("scale_level of %s: %d",
name, scale_status.scale_level)
increase = value['num'] * scale_status.scale_level
desired_capacity = value['initialNum'] + increase
LOG.debug("desired_capacity: %d", desired_capacity)
return desired_capacity
LOG.debug("scale_level of %s: None", name)
return None
def get_desired_capacity_dict(base_hot_dict, vnfd_dict, inst_vnf_info):
"""Get a dict containing information about desired capacity.
:param base_hot_dict: dict(Base HOT dict format)
:param vnfd_dict: dict(VNFD dict format)
:param inst_vnf_info: dict(Instantiated VNF Info dict format)
:return: dict(Scaling aspect name, Desired capacity value)
"""
scale_group_dict = _create_scale_group_dict(
base_hot_dict, vnfd_dict, {})
param_dict = {}
if scale_group_dict.get('scaleGroupDict'):
for name, value in scale_group_dict['scaleGroupDict'].items():
desired_capacity = _calc_desired_capacity(
inst_vnf_info, name, value)
if desired_capacity is not None:
param_dict[name] = desired_capacity
LOG.info("desired_capacity dict: %s", param_dict)
return param_dict