Improve nfv parameter setting by additionalParams

This patch improves the behavior of nfv parameter setting by
additionalParams when using StandardUserData in the following
v2 APIs.

* Scale (Scale Out) VNF
* Heal VNF
* Change current VNF package
* Change external VNF connectivity

Implements: blueprint individual-vnfc-management
Change-Id: I2c8d979da42db7a0eb1d2594854f8e9d5bdf9226
This commit is contained in:
Ken Fujimoto 2023-07-12 12:55:54 +00:00
parent 075c4bca97
commit 7f42fa88c0
13 changed files with 347 additions and 210 deletions

View File

@ -84,7 +84,7 @@ Following shows sample output.
scale()
^^^^^^^
The method must return the following structure.
The method must return the following structure if it is necessary to modify.
Data are for update stack API in HEAT.
The requirements of HEAT API are described in
`reference of Orchestration Service API v1
@ -106,7 +106,7 @@ Following shows sample output.
scale_rollback()
^^^^^^^^^^^^^^^^
The method must return the following structure.
The method must return the following structure if it is necessary to modify.
Data are for update stack API in HEAT.
The requirements of HEAT API are described in
`reference of Orchestration Service API v1

View File

@ -26,6 +26,7 @@ import eventlet
from oslo_log import log as logging
from oslo_utils import uuidutils
from tacker.sol_refactored.common import common_script_utils
from tacker.sol_refactored.common import config
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import lcm_op_occ_utils as lcmocc_utils
@ -92,7 +93,7 @@ class Openstack(object):
def instantiate(self, req, inst, grant_req, grant, vnfd):
# make HOT
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
vdu_ids = self._get_vdu_id_from_fields(fields)
vdu_ids = self._get_additional_vdu_id(grant_req, inst)
# create or update stack
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
@ -174,7 +175,8 @@ class Openstack(object):
def scale(self, req, inst, grant_req, grant, vnfd):
# make HOT
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
vdu_ids = self._get_vdu_id_from_fields(fields)
if req.type == 'SCALE_OUT':
vdu_ids = self._get_additional_vdu_id(grant_req, inst)
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
heat_client = heat_utils.HeatClient(vim_info)
@ -751,9 +753,20 @@ class Openstack(object):
return (vdu_id,
vdu_dict.get(vdu_id, {}).get('locationConstraints'))
def _get_vdu_id_from_fields(self, fields):
vdu_dict = fields['parameters']['nfv']['VDU']
return set(vdu_dict.keys())
def _get_additional_vdu_id(self, grant_req, inst):
add_vdus = {}
for res_def in grant_req.addResources:
if res_def.type == 'COMPUTE':
add_vdus.setdefault(res_def.resourceTemplateId, 0)
add_vdus[res_def.resourceTemplateId] += 1
vdu_ids = set()
for vdu_name, num in add_vdus.items():
current_vdu_num = common_script_utils.get_current_capacity(
vdu_name, inst)
for idx in range(current_vdu_num, current_vdu_num + num):
vdu_ids.add(f'{vdu_name}-{idx}')
return vdu_ids
def _get_vdu_id_from_grant_req(self, grant_req, inst):
vnfc_res_ids = [res_def.resource.resourceId
@ -1563,7 +1576,8 @@ class Openstack(object):
inst.instantiatedVnfInfo.obj_attr_is_set('metadata')):
inst_vnf_info.metadata.update(inst.instantiatedVnfInfo.metadata)
# store stack_id into metadata
# store stack_id and nfv parameters into metadata
inst_vnf_info.metadata['stack_id'] = stack_id
inst_vnf_info.metadata['nfv'] = nfv_dict
inst.instantiatedVnfInfo = inst_vnf_info

View File

@ -93,37 +93,14 @@ def _get_new_cps_from_req(cps, req, grant):
return new_cps
def _get_new_cps_from_inst(cps, inst):
# used by change_ext_conn_rollback and change_vnfpkg_rollback
new_cps = {}
for cp_name_idx, cp_value in cps.items():
cp_name = rm_idx(cp_name_idx)
if 'network' in cp_value:
network = common_script_utils.get_param_network_from_inst(
cp_name, inst)
if network is None:
continue
new_cps.setdefault(cp_name_idx, {})
new_cps[cp_name_idx]['network'] = network
if 'fixed_ips' in cp_value:
ext_fixed_ips = (
common_script_utils.get_param_fixed_ips_from_inst(
cp_name, inst))
fixed_ips = []
for i in range(len(ext_fixed_ips)):
if i not in cp_value['fixed_ips']:
break
ips_i = cp_value['fixed_ips'][i]
if 'subnet' in ips_i:
ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
if 'ip_address' in ips_i:
ips_i['ip_address'] = ext_fixed_ips[i].get(
'ip_address')
fixed_ips.append(ips_i)
new_cps.setdefault(cp_name_idx, {})
new_cps[cp_name_idx]['fixed_ips'] = fixed_ips
return new_cps
def _merge_additional_params(nfv_dict, req, grant):
if 'nfv' in req.get('additionalParams', {}):
nfv_dict = inst_utils.json_merge_patch(
nfv_dict, req['additionalParams']['nfv'])
if 'nfv' in grant.get('additionalParams', {}):
nfv_dict = inst_utils.json_merge_patch(
nfv_dict, grant['additionalParams']['nfv'])
return nfv_dict
class StandardUserData(userdata_utils.AbstractUserData):
@ -195,13 +172,7 @@ class StandardUserData(userdata_utils.AbstractUserData):
cp_value['fixed_ips'] = fixed_ips
common_script_utils.apply_ext_managed_vls(top_hot, req, grant)
if 'nfv' in req.get('additionalParams', {}):
nfv_dict = inst_utils.json_merge_patch(nfv_dict,
req['additionalParams']['nfv'])
if 'nfv' in grant.get('additionalParams', {}):
nfv_dict = inst_utils.json_merge_patch(nfv_dict,
grant['additionalParams']['nfv'])
nfv_dict = _merge_additional_params(nfv_dict, req, grant)
fields = {
'template': yaml.safe_dump(top_hot),
@ -267,6 +238,10 @@ class StandardUserData(userdata_utils.AbstractUserData):
vdu_name, flavour_id, vnfd, grant)
if 'locationConstraints' in vdu_value:
vdu_value['locationConstraints'] = zones[vdu_name_idx]
exclude_params = [param for param, value in vdu_value.items()
if value is None]
for exclude_param in exclude_params:
del vdu_value[exclude_param]
cps = nfv_dict.get('CP', {})
for cp_name, cp_value in cps.items():
@ -291,8 +266,13 @@ class StandardUserData(userdata_utils.AbstractUserData):
'ip_address')
fixed_ips.append(ips_i)
cp_value['fixed_ips'] = fixed_ips
exclude_params = [param for param, value in cp_value.items()
if value is None]
for exclude_param in exclude_params:
del cp_value[exclude_param]
common_script_utils.apply_ext_managed_vls_from_inst(top_hot, inst)
nfv_dict = _merge_additional_params(nfv_dict, req, grant)
fields = {
'template': yaml.safe_dump(top_hot),
@ -303,13 +283,8 @@ class StandardUserData(userdata_utils.AbstractUserData):
@staticmethod
def _scale_in(req, inst, grant_req, grant, tmp_csar_dir):
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
flavour_id = inst['instantiatedVnfInfo']['flavourId']
vdu_nodes = vnfd.get_vdu_nodes(flavour_id)
template = {'resources': {}}
vdus = {}
cps = {}
for res in grant_req['removeResources']:
if res['type'] != 'COMPUTE':
continue
@ -321,19 +296,9 @@ class StandardUserData(userdata_utils.AbstractUserData):
break
vdu_name = res['resourceTemplateId']
template['resources'][add_idx(vdu_name, vdu_idx)] = None
vdus[add_idx(vdu_name, vdu_idx)] = None
for str_name in vnfd.get_vdu_storages(vdu_nodes[vdu_name]):
# may overspec, but no problem
vdus[add_idx(str_name, vdu_idx)] = None
for cp_name in vnfd.get_vdu_cps(flavour_id, vdu_name):
# may overspec, but no problem
cps[add_idx(cp_name, vdu_idx)] = None
fields = {
'template': yaml.safe_dump(template),
'parameters': {'nfv': {'VDU': vdus, 'CP': cps}}
}
return fields
@ -350,8 +315,6 @@ class StandardUserData(userdata_utils.AbstractUserData):
vdu_name, inst)
template = {'resources': {}}
vdus = {}
cps = {}
for res in grant_req['addResources']:
if res['type'] != 'COMPUTE':
continue
@ -359,19 +322,9 @@ class StandardUserData(userdata_utils.AbstractUserData):
vdu_idx = vdu_idxes[vdu_name]
vdu_idxes[vdu_name] += 1
template['resources'][add_idx(vdu_name, vdu_idx)] = None
vdus[add_idx(vdu_name, vdu_idx)] = None
for str_name in vnfd.get_vdu_storages(vdu_nodes[vdu_name]):
# may overspec, but no problem
vdus[add_idx(str_name, vdu_idx)] = None
for cp_name in vnfd.get_vdu_cps(flavour_id, vdu_name):
# may overspec, but no problem
cps[add_idx(cp_name, vdu_idx)] = None
fields = {
'template': yaml.safe_dump(template),
'parameters': {'nfv': {'VDU': vdus, 'CP': cps}}
}
return fields
@ -411,38 +364,18 @@ class StandardUserData(userdata_utils.AbstractUserData):
cps = nfv_dict.get('CP', {})
new_cps = _get_new_cps_from_req(cps, req, grant)
fields = {'parameters': {'nfv': {'CP': new_cps}}}
nfv_dict = _merge_additional_params({'CP': new_cps}, req, grant)
fields = {'parameters': {'nfv': nfv_dict}}
return fields
@staticmethod
def change_ext_conn_rollback(req, inst, grant_req, grant, tmp_csar_dir):
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
flavour_id = inst['instantiatedVnfInfo']['flavourId']
hot_dict = vnfd.get_base_hot(flavour_id)
top_hot = hot_dict['template']
# first modify VDU resources
popped_vdu = {}
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
for inst_vnfc in inst['instantiatedVnfInfo'].get(
'vnfcResourceInfo', []):
vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
if vdu_idx is None:
continue
vdu_name = inst_vnfc['vduId']
res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
cps = nfv_dict.get('CP', {})
new_cps = _get_new_cps_from_inst(cps, inst)
fields = {'parameters': {'nfv': {'CP': new_cps}}}
fields = {
'parameters': {
'nfv': inst['instantiatedVnfInfo']['metadata']['nfv']
}
}
return fields
@ -451,14 +384,7 @@ class StandardUserData(userdata_utils.AbstractUserData):
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
flavour_id = inst['instantiatedVnfInfo']['flavourId']
hot_dict = vnfd.get_base_hot(flavour_id)
top_hot = hot_dict['template']
# first modify VDU resources
popped_vdu = {}
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
vdus = inst['instantiatedVnfInfo']['metadata']['nfv'].get('VDU', {})
for res in grant_req['removeResources']:
if res['type'] != 'COMPUTE':
continue
@ -466,32 +392,16 @@ class StandardUserData(userdata_utils.AbstractUserData):
if (inst_vnfc['computeResource']['resourceId'] ==
res['resource']['resourceId']):
# must be found
vdu_name = inst_vnfc['vduId']
vdu_idx = inst_vnfc['metadata']['vdu_idx']
image = common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant, fallback_vnfd=False)
if image is not None:
vdus[add_idx(vdu_name, vdu_idx)]['vcImageId'] = image
break
vdu_name = res['resourceTemplateId']
res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
vdus = nfv_dict.get('VDU', {})
for vdu_name, vdu_value in vdus.items():
vdu_name = rm_idx(vdu_name)
if 'computeFlavourId' in vdu_value:
vdu_value.pop('computeFlavourId')
if 'vcImageId' in vdu_value:
image = common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant, fallback_vnfd=False)
if image is not None:
vdu_value['vcImageId'] = image
else:
# the case is that this is a storage image and
# 'all' is False.
vdu_value.pop('vcImageId')
if 'locationConstraints' in vdu_value:
vdu_value.pop('locationConstraints')
fields = {'parameters': {'nfv': {'VDU': vdus}}}
nfv_dict = _merge_additional_params({'VDU': vdus}, req, grant)
fields = {'parameters': {'nfv': nfv_dict}}
return fields
@ -517,9 +427,6 @@ class StandardUserData(userdata_utils.AbstractUserData):
cur_hot_reses = {}
new_hot_reses = {}
images = {}
flavors = {}
zones = {}
for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
if vdu_idx is None:
@ -537,51 +444,29 @@ class StandardUserData(userdata_utils.AbstractUserData):
else:
cur_hot_reses[vdu_name_idx] = res
# NOTE: only zone is necessary for new_hot_reses
for key, value in inst_vnfc['metadata'].items():
if key == 'flavor':
flavors[vdu_name_idx] = value
elif key == 'zone':
zones[vdu_name_idx] = value
elif key.startswith('image-'):
image_vdu = key.replace('image-', '')
images[image_vdu] = value
cur_nfv_dict = common_script_utils.init_nfv_dict(
{'resources': cur_hot_reses})
new_nfv_dict = common_script_utils.init_nfv_dict(
{'resources': new_hot_reses})
cur_vdus = cur_nfv_dict.get('VDU', {})
new_vdus = new_nfv_dict.get('VDU', {})
for vdu_name_idx, vdu_value in cur_vdus.items():
if 'computeFlavourId' in vdu_value:
vdu_value['computeFlavourId'] = flavors.get(vdu_name_idx)
if 'vcImageId' in vdu_value:
vdu_value['vcImageId'] = images.get(vdu_name_idx)
if 'locationConstraints' in vdu_value:
vdu_value['locationConstraints'] = zones.get(vdu_name_idx)
vdus = inst['instantiatedVnfInfo']['metadata']['nfv'].get('VDU', {})
for vdu_name_idx, vdu_value in new_vdus.items():
vdu_name = rm_idx(vdu_name_idx)
if 'computeFlavourId' in vdu_value:
vdu_value['computeFlavourId'] = (
vdus[vdu_name_idx]['computeFlavourId'] = (
common_script_utils.get_param_flavor(
vdu_name, flavour_id, vnfd, grant))
if 'vcImageId' in vdu_value:
vdu_value['vcImageId'] = common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant)
if 'locationConstraints' in vdu_value:
vdu_value['locationConstraints'] = zones.get(vdu_name_idx)
vdus = cur_vdus
vdus.update(new_vdus)
vdus[vdu_name_idx]['vcImageId'] = (
common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant))
cps = cur_nfv_dict.get('CP', {})
cps.update(new_nfv_dict.get('CP', {}))
# NOTE: req includes only different part. some CPs in new_nfv_dict
# may be necessary to get from inst.
cur_cps = _get_new_cps_from_inst(cps, inst)
cur_cps = inst['instantiatedVnfInfo']['metadata']['nfv'].get('CP', {})
req_cps = _get_new_cps_from_req(cps, req, grant)
for cp_name in cps.keys():
if cp_name in req_cps:
@ -591,9 +476,12 @@ class StandardUserData(userdata_utils.AbstractUserData):
common_script_utils.apply_ext_managed_vls(top_hot, req, grant)
nfv_dict = _merge_additional_params({'VDU': vdus, 'CP': cps},
req, grant)
fields = {
'template': yaml.safe_dump(top_hot),
'parameters': {'nfv': {'VDU': vdus, 'CP': cps}},
'parameters': {'nfv': nfv_dict},
'files': {},
'existing': False
}
@ -615,9 +503,6 @@ class StandardUserData(userdata_utils.AbstractUserData):
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
images = {}
flavors = {}
zones = {}
for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
if vdu_idx is None:
@ -629,35 +514,12 @@ class StandardUserData(userdata_utils.AbstractUserData):
res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
top_hot['resources'][vdu_name_idx] = res
for key, value in inst_vnfc['metadata'].items():
if key == 'flavor':
flavors[vdu_name_idx] = value
elif key == 'zone':
zones[vdu_name_idx] = value
elif key.startswith('image-'):
image_vdu = key.replace('image-', '')
images[image_vdu] = value
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
vdus = nfv_dict.get('VDU', {})
for vdu_name_idx, vdu_value in vdus.items():
vdu_name = rm_idx(vdu_name)
if 'computeFlavourId' in vdu_value:
vdu_value['computeFlavourId'] = flavors.get(vdu_name_idx)
if 'vcImageId' in vdu_value:
vdu_value['vcImageId'] = images.get(vdu_name_idx)
if 'locationConstraints' in vdu_value:
vdu_value['locationConstraints'] = zones.get(vdu_name_idx)
cps = nfv_dict.get('CP', {})
new_cps = _get_new_cps_from_inst(cps, inst)
common_script_utils.apply_ext_managed_vls(top_hot, req, grant)
fields = {
'template': yaml.safe_dump(top_hot),
'parameters': {'nfv': {'VDU': vdus, 'CP': new_cps}},
'parameters': {
'nfv': inst['instantiatedVnfInfo']['metadata']['nfv']},
'files': {},
'existing': False
}

View File

@ -178,6 +178,16 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
storage_res_ids = vnfc.get('storageResourceIds', [])
return sorted(storage_res_ids)
def _get_server_name(self, inst, vdu, index):
for vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
if (vnfc['vduId'] == vdu and
vnfc['metadata'].get('vdu_idx') == index):
# must be found
server_id = vnfc['computeResource']['resourceId']
break
server_details = self.get_server_details_by_id(server_id)
return server_details.get('name')
def test_basic_operations(self):
"""Test basic operations using StandardUserData
@ -232,6 +242,9 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
# check vnfcInfo ids
self.assertEqual('a-001', self._get_vnfc_info_id(inst_1, 'VDU1', 0))
self.assertEqual('b-000', self._get_vnfc_info_id(inst_1, 'VDU2', 0))
# check server name
self.assertEqual('VDU1-a-001-instantiate',
self._get_server_name(inst_1, 'VDU1', 0))
# 2. Scale out operation
scale_out_req = paramgen.sample3_scale_out()
@ -251,6 +264,11 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
# check vnfcInfo ids
self.assertEqual('a-010', self._get_vnfc_info_id(inst_2, 'VDU1', 1))
self.assertEqual('a-011', self._get_vnfc_info_id(inst_2, 'VDU1', 2))
# check server names
self.assertEqual('VDU1-a-010-scale_out',
self._get_server_name(inst_2, 'VDU1', 1))
self.assertEqual('VDU1-a-011-instantiate',
self._get_server_name(inst_2, 'VDU1', 2))
# 3. Heal operation
heal_req = paramgen.sample3_heal()
@ -278,6 +296,9 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
self._get_vnfc_id(inst_3, 'VDU2', 0))
# check vnfcInfo id of VDU1-1 is not changed.
self.assertEqual('a-010', self._get_vnfc_info_id(inst_3, 'VDU1', 1))
# check server name
self.assertEqual('VDU1-a-010-heal',
self._get_server_name(inst_3, 'VDU1', 1))
# 4. Scale in operation
scale_in_req = paramgen.sample3_scale_in()
@ -327,6 +348,12 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
self.assertEqual(net_ids['net1'],
self._get_vnfc_cp_net_id(inst_5, 'VDU2', 0, 'VDU2_CP1'))
# check server names
self.assertEqual('VDU1-a-001-change_ext_conn',
self._get_server_name(inst_5, 'VDU1', 0))
self.assertEqual('VDU1-a-010-change_ext_conn',
self._get_server_name(inst_5, 'VDU1', 1))
# 6. Change_vnfpkg operation
change_vnfpkg_req = paramgen.sample4_change_vnfpkg(self.new_vnfd_id,
net_ids, subnet_ids)
@ -386,6 +413,11 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
self.assertEqual('a-001', self._get_vnfc_info_id(inst_6, 'VDU1', 0))
self.assertEqual('a-010', self._get_vnfc_info_id(inst_6, 'VDU1', 1))
self.assertEqual('b-000', self._get_vnfc_info_id(inst_6, 'VDU2', 0))
# check server names
self.assertEqual('VDU1-a-001-change_vnfpkg',
self._get_server_name(inst_6, 'VDU1', 0))
self.assertEqual('VDU1-a-010-change_vnfpkg',
self._get_server_name(inst_6, 'VDU1', 1))
# Terminate VNF instance
terminate_req = paramgen.sample4_terminate()
@ -498,6 +530,9 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
self._get_vnfc_cp_net_id(inst_2, 'VDU1', 0, 'VDU1_CP1'))
self.assertEqual(net_ids['net1'],
self._get_vnfc_cp_net_id(inst_2, 'VDU2', 0, 'VDU2_CP1'))
# check server name is not changed
self.assertEqual('VDU1-a-001-instantiate',
self._get_server_name(inst_2, 'VDU1', 0))
# 3. Change_vnfpkg operation
self.put_fail_file('change_vnfpkg')
@ -549,6 +584,9 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
self._get_vnfc_cp_net_id(inst_3, 'VDU1', 0, 'VDU1_CP1'))
self.assertEqual(net_ids['net1'],
self._get_vnfc_cp_net_id(inst_3, 'VDU2', 0, 'VDU2_CP1'))
# check server name is not changed
self.assertEqual('VDU1-a-001-instantiate',
self._get_server_name(inst_3, 'VDU1', 0))
# Terminate VNF instance
terminate_req = paramgen.sample3_terminate()

View File

@ -168,6 +168,12 @@ class BaseSolV2Test(base_v2.BaseTackerTestV2):
server_details = server
return server_details
def get_server_details_by_id(self, server_id):
path = f"/servers/{server_id}"
resp, resp_body = self.nova_client.do_request(path, "GET")
return resp_body.get('server', {})
def get_zone_list(self):
path = "/os-services"
resp, resp_body = self.nova_client.do_request(path, "GET")

View File

@ -1049,7 +1049,14 @@ def sample3_instantiate(net_ids, subnet_ids, auth_url):
},
"additionalParams": {
"lcm-operation-user-data": "./UserData/userdata_standard.py",
"lcm-operation-user-data-class": "StandardUserData"
"lcm-operation-user-data-class": "StandardUserData",
"nfv": {
"VDU": {
"VDU1-0": {"name": "VDU1-a-001-instantiate"},
"VDU1-1": {"name": "VDU1-a-010-instantiate"},
"VDU1-2": {"name": "VDU1-a-011-instantiate"}
}
}
}
}
@ -1061,7 +1068,15 @@ def sample3_scale_out():
"numberOfSteps": 2,
"additionalParams": {
"lcm-operation-user-data": "./UserData/userdata_standard.py",
"lcm-operation-user-data-class": "StandardUserData"
"lcm-operation-user-data-class": "StandardUserData",
# In this sample, VDU1-2 nfv parameters is not set for test,
# but in normal operation, it is recommended to set nfv parameters
# when adding or updating.
"nfv": {
"VDU": {
"VDU1-1": {"name": "VDU1-a-010-scale_out"},
}
}
}
}
@ -1083,7 +1098,12 @@ def sample3_heal():
"vnfcInstanceId": [], # should be filled
"additionalParams": {
"lcm-operation-user-data": "./UserData/userdata_standard.py",
"lcm-operation-user-data-class": "StandardUserData"
"lcm-operation-user-data-class": "StandardUserData",
"nfv": {
"VDU": {
"VDU1-1": {"name": "VDU1-a-010-heal"},
}
}
}
}
@ -1112,7 +1132,14 @@ def sample3_change_ext_conn(net_ids):
],
"additionalParams": {
"lcm-operation-user-data": "./UserData/userdata_standard.py",
"lcm-operation-user-data-class": "StandardUserData"
"lcm-operation-user-data-class": "StandardUserData",
"nfv": {
"VDU": {
"VDU1-0": {"name": "VDU1-a-001-change_ext_conn"},
"VDU1-1": {"name": "VDU1-a-010-change_ext_conn"},
"VDU1-2": {"name": "VDU1-a-011-change_ext_conn"}
}
}
}
}
@ -1229,7 +1256,14 @@ def sample4_change_vnfpkg(vnfd_id, net_ids, subnet_ids):
}
],
"lcm-operation-user-data": "./UserData/userdata_standard.py",
"lcm-operation-user-data-class": "StandardUserData"
"lcm-operation-user-data-class": "StandardUserData",
"nfv": {
"VDU": {
"VDU1-0": {"name": "VDU1-a-001-change_vnfpkg"},
"VDU1-1": {"name": "VDU1-a-010-change_vnfpkg"},
"VDU1-2": {"name": "VDU1-a-011-change_vnfpkg"},
}
}
}
}
@ -1402,7 +1436,14 @@ def sample5_change_vnfpkg(vnfd_id, net_ids, subnet_ids):
}
],
"lcm-operation-user-data": "./UserData/userdata_standard.py",
"lcm-operation-user-data-class": "StandardUserData"
"lcm-operation-user-data-class": "StandardUserData",
"nfv": {
"VDU": {
"VDU1-0": {"name": "VDU1-a-001-change_vnfpkg"},
"VDU1-1": {"name": "VDU1-a-010-change_vnfpkg"},
"VDU1-2": {"name": "VDU1-a-011-change_vnfpkg"}
}
}
}
}

View File

@ -8,6 +8,8 @@ parameters:
type: string
zone:
type: string
name:
type: string
net1:
type: string
net2:
@ -20,7 +22,7 @@ resources:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
name: VDU1
name: { get_param: name }
image: { get_param: image-VDU1 }
networks:
- port:

View File

@ -12,6 +12,7 @@ resources:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] }
name: { get_param: [ nfv, VDU, VDU1, name] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
net2: { get_resource: internalVL1 }
net3: { get_resource: internalVL2 }

View File

@ -8,6 +8,8 @@ parameters:
type: string
zone:
type: string
name:
type: string
net1:
type: string
net2:
@ -20,7 +22,7 @@ resources:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
name: VDU1
name: { get_param: name }
image: { get_param: image-VDU1 }
networks:
- port:

View File

@ -12,6 +12,7 @@ resources:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] }
name: { get_param: [ nfv, VDU, VDU1, name] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
net2: { get_resource: internalVL1 }
net3: { get_resource: internalVL2 }

View File

@ -16,13 +16,15 @@ parameters:
type: string
zone:
type: string
name:
type: string
resources:
VDU1:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
name: VDU1
name: { get_param: name }
image: { get_param: image-VDU1 }
networks:
- port:

View File

@ -16,6 +16,7 @@ resources:
net3: { get_resource: internalVL3 }
net4: { get_param: [ nfv, CP, VDU1_CP4, network ] }
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints ] }
name: { get_param: [ nfv, VDU, VDU1, name] }
VDU2:
type: VDU2-ver2.yaml

View File

@ -2230,7 +2230,17 @@ _expected_inst_info = {
"vnfcState": "STARTED"
}
],
"metadata": {"stack_id": STACK_ID}
"metadata": {
"stack_id": STACK_ID,
"nfv": {
"VDU": {
"VDU1": {"computeFlavourId": "m1.tiny"},
"VDU1-VirtualStorage": {"vcImageId": "image-VDU1"},
"VDU2": {"computeFlavourId": "m1.small",
"vcImageId": "image-VDU2"}
}
}
}
}
_expected_inst_info_vnfc_updated = copy.copy(_expected_inst_info)
@ -2256,6 +2266,48 @@ _expected_inst_info_vnfc_updated["vnfcInfo"] = [
}
]
_expected_inst_info_vnfc_updated["metadata"] = {
"stack_id": STACK_ID,
"nfv": {
"VDU": {
"VDU1": {
"desired_capacity": 1,
"computeFlavourId": "m1.tiny",
"locationConstraints": None
},
"VirtualStorage": {
"vcImageId": "image-1.0.0-x86_64-disk"
},
"VDU2": {
"computeFlavourId": "m1.small",
"vcImageId": "image-VDU2"
}
},
"CP": {
"VDU1_CP1": {
"network": "res_id_ext_vl_1"
},
"VDU1_CP2": {
"network": "res_id_id_ext_vl_2",
"fixed_ips": [{
"subnet": "res_id_subnet_1"
}]
},
"VDU2_CP1": {
"network": "res_id_ext_vl_1",
"fixed_ips": [{
"ip_address": "10.10.0.102"
}]
},
"VDU2_CP2": {
"network": "res_id_id_ext_vl_2",
"fixed_ips": []
}
}
}
}
# expected results for change_ext_conn
_expected_inst_info_change_ext_conn = {
"flavourId": "simple",
@ -2675,7 +2727,44 @@ _expected_inst_info_change_ext_conn = {
_expected_inst_info["virtualStorageResourceInfo"],
"vnfcInfo": _expected_inst_info["vnfcInfo"],
"metadata": {
"stack_id": STACK_ID
"stack_id": STACK_ID,
"nfv": {
"VDU": {
"VDU1": {
"desired_capacity": 1,
"computeFlavourId": "m1.tiny",
"locationConstraints": None
},
"VirtualStorage": {
"vcImageId": "image-1.0.0-x86_64-disk"
},
"VDU2": {
"computeFlavourId": "m1.small",
"vcImageId": "image-VDU2"
}
},
"CP": {
"VDU1_CP1": {
"network": "res_id_ext_vl_1"
},
"VDU1_CP2": {
"network": "res_id_id_ext_vl_2",
"fixed_ips": [{
"subnet": "res_id_subnet_1"
}]
},
"VDU2_CP1": {
"network": "res_id_ext_vl_1",
"fixed_ips": [{
"ip_address": "10.10.0.102"
}]
},
"VDU2_CP2": {
"network": "res_id_id_ext_vl_2",
"fixed_ips": []
}
}
}
}
}
@ -3083,7 +3172,19 @@ _expected_inst_info_S = {
}
],
"metadata": {
"stack_id": STACK_ID
"stack_id": STACK_ID,
"nfv": {
"VDU": {
"VDU1-0": {"vcImageId": "image-VDU1",
"computeFlavourId": "m1.tiny",
"locationConstraints": "zone1"},
"VDU1-1": {"vcImageId": "image-VDU1",
"computeFlavourId": "m1.tiny",
"locationConstraints": "zone1"},
"VDU2-0": {"computeFlavourId": "m1.small"},
"VDU2-VirtualStorage-0": {"vcImageId": "image-VDU2"}
}
}
}
}
@ -3738,6 +3839,10 @@ class TestOpenstack(base.BaseTestCase):
self.assertEqual(expected["virtualStorageResourceInfo"],
result["virtualStorageResourceInfo"])
if "metadata" in expected:
self.assertIn("metadata", result)
self.assertEqual(expected["metadata"], result["metadata"])
# order of vnfcInfo is same as vnfcResourceInfo
if "vnfcInfo" in expected:
self.assertIn("vnfcInfo", result)
@ -3792,7 +3897,8 @@ class TestOpenstack(base.BaseTestCase):
# prepare heat responses
heat_client = mock.Mock()
heat_client.get_resources.return_value = _heat_reses_example
heat_client.get_parameters.return_value = _heat_get_parameters_example
heat_client.get_parameters.return_value = {
'nfv': json.dumps(_heat_parameters)}
heat_client.get_template.return_value = _heat_get_template_example
# execute make_instantiated_vnf_info
@ -3828,7 +3934,8 @@ class TestOpenstack(base.BaseTestCase):
heat_client = mock.Mock()
heat_client.get_resources.return_value = (
_heat_reses_example_change_ext_conn)
heat_client.get_parameters.return_value = _heat_get_parameters_example
heat_client.get_parameters.return_value = {
'nfv': json.dumps(_heat_parameters)}
heat_client.get_template.return_value = _heat_get_template_example
# execute make_instantiated_vnf_info
@ -3877,6 +3984,7 @@ class TestOpenstack(base.BaseTestCase):
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_S, result)
@mock.patch.object(openstack.Openstack, '_get_additional_vdu_id')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_stack_id')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_status')
@mock.patch.object(openstack.heat_utils.HeatClient, 'create_stack')
@ -3886,7 +3994,7 @@ class TestOpenstack(base.BaseTestCase):
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_instantiate(self, mock_template, mock_parameters, mock_resources,
mock_update_stack, mock_create_stack, mock_status,
mock_stack_id):
mock_stack_id, mock_get_vdu_ids):
# prepare
req = objects.InstantiateVnfRequest.from_dict(_instantiate_req_example)
inst = objects.VnfInstanceV2(
@ -3990,13 +4098,14 @@ class TestOpenstack(base.BaseTestCase):
self.driver.terminate(req, inst, grant_req, grant, self.vnfd_1)
self.assertEqual(3, mock_delete_stack.call_count)
@mock.patch.object(openstack.Openstack, '_get_additional_vdu_id')
@mock.patch.object(openstack.heat_utils.HeatClient, 'update_stack')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_resources')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(openstack.heat_utils.HeatClient, 'mark_unhealthy')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_scale(self, mock_template, mock_unhealthy, mock_parameters,
mock_reses, mock_stack):
mock_reses, mock_stack, mock_get_vdu_ids):
# prepare
req_inst = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
@ -4216,6 +4325,7 @@ class TestOpenstack(base.BaseTestCase):
}
)
mock_reses.return_value = _heat_reses_example
mock_create.return_value = STACK_ID
self.driver.heal(req, inst, grant_req, grant, self.vnfd_1)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
@ -4489,6 +4599,7 @@ class TestOpenstack(base.BaseTestCase):
inst, anti_rules, failed_vdu_id, vdu_ids, vdu_dict)
self.assertEqual({'az-1', 'az-3', 'az-4'}, result)
@mock.patch.object(openstack.Openstack, '_get_additional_vdu_id')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_stack_id')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_status')
@mock.patch.object(openstack.heat_utils.HeatClient, 'create_stack')
@ -4498,7 +4609,7 @@ class TestOpenstack(base.BaseTestCase):
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_https_with_instantiate(self, mock_template, mock_parameters,
mock_resources, mock_update_stack, mock_create_stack,
mock_status, mock_stack_id):
mock_status, mock_stack_id, mock_get_vdus_ids):
# prepare
req = objects.InstantiateVnfRequest.from_dict(_instantiate_req_example)
inst = objects.VnfInstanceV2(
@ -4533,6 +4644,7 @@ class TestOpenstack(base.BaseTestCase):
self.driver.instantiate(req, inst, grant_req, grant, self.vnfd_1)
mock_update_stack.assert_called_once()
@mock.patch.object(openstack.Openstack, '_get_additional_vdu_id')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_stack_id')
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_status')
@mock.patch.object(openstack.heat_utils.HeatClient, 'create_stack')
@ -4542,7 +4654,7 @@ class TestOpenstack(base.BaseTestCase):
@mock.patch.object(openstack.heat_utils.HeatClient, 'get_template')
def test_oauth2_mtls_with_instantiate(self, mock_template, mock_parameters,
mock_resources, mock_update_stack, mock_create_stack,
mock_status, mock_stack_id):
mock_status, mock_stack_id, mock_get_vdus_ids):
# prepare
req = objects.InstantiateVnfRequest.from_dict(_instantiate_req_example)
inst = objects.VnfInstanceV2(
@ -4582,3 +4694,58 @@ class TestOpenstack(base.BaseTestCase):
# execute
self.driver.instantiate(req, inst, grant_req, grant, self.vnfd_1)
mock_update_stack.assert_called_once()
def test_get_additional_vdu_id(self):
# prepare
inst = objects.VnfInstanceV2(
id=uuidutils.generate_uuid(),
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo(
flavourId='fake_flavour_id',
vnfState='STOPPED'
)
)
)
grant_req = objects.GrantRequestV1(
addResources=[
objects.ResourceDefinitionV1(
type='COMPUTE',
resourceTemplateId='VDU1'
),
objects.ResourceDefinitionV1(
type='COMPUTE',
resourceTemplateId='VDU2'
),
objects.ResourceDefinitionV1(
type='LINKPORT',
resourceTemplateId='VDU1-CP1'
)
]
)
# execute
result = self.driver._get_additional_vdu_id(grant_req, inst)
self.assertEqual({'VDU1-0', 'VDU2-0'}, result)
inst = objects.VnfInstanceV2(
id=uuidutils.generate_uuid(),
instantiatedVnfInfo=(
objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_update_retry_instantiated_vnfinfo))
)
grant_req = objects.GrantRequestV1(
addResources=[
objects.ResourceDefinitionV1(
type='COMPUTE',
resourceTemplateId='VDU1'
),
objects.ResourceDefinitionV1(
type='COMPUTE',
resourceTemplateId='VDU1'
)
]
)
# execute
result = self.driver._get_additional_vdu_id(grant_req, inst)
self.assertEqual({'VDU1-1', 'VDU1-2'}, result)