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

View File

@ -13,14 +13,12 @@
# 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 ddt
import importlib import importlib
import json import json
import os import os
import tempfile
from unittest import mock
import ddt
import requests import requests
import tempfile
import yaml import yaml
from heatclient.v1 import resources 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.tests import uuidsentinel
from tacker.vnfm.infra_drivers.openstack import heat_client as hc from tacker.vnfm.infra_drivers.openstack import heat_client as hc
from tacker.vnfm.infra_drivers.openstack import openstack from tacker.vnfm.infra_drivers.openstack import openstack
from unittest import mock
vnf_dict = { vnf_dict = {
'instance_id': 'd1121d3c-368b-4ac2-b39d-835aa3e4ccd8' 'instance_id': 'd1121d3c-368b-4ac2-b39d-835aa3e4ccd8'
@ -2169,7 +2167,7 @@ class TestOpenStack(base.FixturedTestCase):
inst_vnf_info = fd_utils.get_vnf_instantiated_info( inst_vnf_info = fd_utils.get_vnf_instantiated_info(
virtual_storage_resource_info=[v_s_resource_info], virtual_storage_resource_info=[v_s_resource_info],
vnfc_resource_info=[vnfc_resource_info]) vnfc_resource_info=[vnfc_resource_info])
inst_vnf_info.additional_params = None
vnf_instance = fd_utils.get_vnf_instance_object( vnf_instance = fd_utils.get_vnf_instance_object(
instantiated_vnf_info=inst_vnf_info) 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( vnf_lcm_op_occs = fd_utils.get_lcm_op_occs_object(
error_point=fields.ErrorPoint.PRE_VIM_CONTROL) error_point=fields.ErrorPoint.PRE_VIM_CONTROL)
mock_get_vnflcm_op_occs.return_value = vnf_lcm_op_occs mock_get_vnflcm_op_occs.return_value = vnf_lcm_op_occs
self.openstack.heal_vnf( self.openstack.heal_vnf(
self.context, vnf_instance, vim_connection_info, self.context, vnf_instance, vim_connection_info,
heal_vnf_request) heal_vnf_request)
@ -2240,7 +2239,7 @@ class TestOpenStack(base.FixturedTestCase):
instantiated_vnf_info=inst_vnf_info) instantiated_vnf_info=inst_vnf_info)
vim_connection_info = fd_utils.get_vim_connection_info_object() vim_connection_info = fd_utils.get_vim_connection_info_object()
inst_vnf_info.additional_params = None
heal_vnf_request = objects.HealVnfRequest( heal_vnf_request = objects.HealVnfRequest(
vnfc_instance_id=[vnfc_resource_info.id], vnfc_instance_id=[vnfc_resource_info.id],
cause="healing request") cause="healing request")

View File

@ -15,8 +15,10 @@ import os
import testtools import testtools
import yaml import yaml
from tacker import objects
from tacker.objects import instantiate_vnf_req from tacker.objects import instantiate_vnf_req
from tacker.tests import constants from tacker.tests import constants
from tacker.tests import uuidsentinel
from tacker.vnfm.lcm_user_data import utils from tacker.vnfm.lcm_user_data import utils
default_initial_param_dict = { default_initial_param_dict = {
@ -198,3 +200,24 @@ class TestUtils(testtools.TestCase):
inst_req_info.ext_virtual_links = None inst_req_info.ext_virtual_links = None
cpd_vl_dict = utils.create_cpd_vl_dict(base_hot_dict, inst_req_info) cpd_vl_dict = utils.create_cpd_vl_dict(base_hot_dict, inst_req_info)
self.assertEqual({}, cpd_vl_dict) 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 # action_driver
LOG.debug("vnf_info['vnfd']['attributes'] %s", LOG.debug("vnf_info['vnfd']['attributes'] %s",
vnf_info['vnfd']['attributes']) vnf_info['vnfd']['attributes'])
self.scale(context, vnf_info, scale_vnf_request, self.scale(context, vnf_info, vnf_instance,
vim_connection_info, scale_name_list, grp_id) scale_vnf_request, vim_connection_info,
scale_name_list, grp_id)
@log.log @log.log
@revert_to_error_scale @revert_to_error_scale
@ -1241,6 +1242,7 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
self, self,
context, context,
vnf_info, vnf_info,
vnf_instance,
scale_vnf_request, scale_vnf_request,
vim_connection_info, vim_connection_info,
scale_name_list, scale_name_list,

View File

@ -322,7 +322,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
# Find existing stack # Find existing stack
name_filter = None name_filter = None
if 'stack_name' in vnf['attributes'].keys(): if 'stack_name' in vnf['attributes'].keys():
name_filter = vnf['attributes']['stack_name'] name_filter = vnf['attributes']['stack_param']
else: else:
name_filter = (vnf['name'].replace(' ', '_') name_filter = (vnf['name'].replace(' ', '_')
+ '_' + vnf['id']) + '_' + vnf['id'])
@ -402,7 +402,6 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
vdu_name = rsc.vdu_id vdu_name = rsc.vdu_id
if not vdu_name: if not vdu_name:
continue continue
if scale_group_dict: if scale_group_dict:
base_hot_dict, nested_hot_dict, vdu_none_flg = \ base_hot_dict, nested_hot_dict, vdu_none_flg = \
self._update_hot_available_scale( self._update_hot_available_scale(
@ -1458,6 +1457,64 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
for name, value in nested_hot_dict.items(): for name, value in nested_hot_dict.items():
files_dict[name] = self._format_base_hot(value) files_dict[name] = self._format_base_hot(value)
stack_update_param['files'] = files_dict 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: if stack_param:
stack_update_param['parameters'] = stack_param stack_update_param['parameters'] = stack_param
@ -1848,7 +1905,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
@log.log @log.log
def scale_in_reverse(self, context, plugin, auth_attr, vnf_info, 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): scale_name_list, grp_id):
heatclient = hc.HeatClient(auth_attr, region_name) heatclient = hc.HeatClient(auth_attr, region_name)
if grp_id: if grp_id:
@ -1858,13 +1915,75 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
resource_name=name, resource_name=name,
mark_unhealthy=True, mark_unhealthy=True,
resource_status_reason='Scale') resource_status_reason='Scale')
paramDict = {} inst_vnf_info = vnf_instance.instantiated_vnf_info
scale_json = vnf_info['attributes']['scale_group'] vnf = vnf_info
scaleGroupDict = jsonutils.loads(scale_json) stack_param = {}
for name, value in scaleGroupDict['scaleGroupDict'].items(): updated_stack_param = {}
paramDict[name + '_desired_capacity'] = value['default'] if 'stack_param' in vnf['attributes'].keys():
paramDict[scale_vnf_request.aspect_id + '_desired_capacity'] = \ param = yaml.safe_load(vnf['attributes']['stack_param'])
vnf_info['res_num'] 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 = { stack_update_param = {
'parameters': paramDict, 'parameters': paramDict,
'existing': True} 'existing': True}

View File

@ -14,8 +14,9 @@
import copy import copy
from oslo_log import log as logging from oslo_log import log as logging
from oslo_serialization import jsonutils
from tacker.common.utils import MemoryUnit from tacker.common.utils import MemoryUnit
from tacker.tosca import utils as tosca_utils
"""Define util functions that can be used in UserData. """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) fixed_ips_lst.append(fixed_ips)
return fixed_ips_lst 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