Fixed some bugs in individual VNFc management

This patch fixes the following some bugs in individual VNFc
management using HOT.
* "locationConstraints" parameter defined in HOT is not handled
  correctly.
* extManagedVLs are not applied to scale out VNFcs.
* heal after modify vnfdId uses old image.

Closes-Bug: #1994438
Change-Id: Id924831d500368b893a9cff9e9dea10a7366be4d
This commit is contained in:
Ken Fujimoto 2022-10-27 02:26:42 +00:00
parent be6d22b409
commit 2f89ccc8a5
15 changed files with 441 additions and 109 deletions

View File

@ -109,6 +109,20 @@ def get_param_zone(vdu_name, grant_req, grant):
return zone['zoneId']
def get_param_zone_by_vnfc(res_id, grant):
if 'zones' not in grant or 'addResources' not in grant:
return
for res in grant['addResources']:
if res['resourceDefinitionId'] == res_id:
if 'zoneId' not in res:
return
for zone in grant['zones']:
if zone['id'] == res['zoneId']: # must be found
return zone['zoneId']
return
def get_current_capacity(vdu_name, inst):
count = 0
inst_vnfcs = (inst.get('instantiatedVnfInfo', {})
@ -194,14 +208,9 @@ def get_param_fixed_ips_from_inst(cp_name, inst):
return _get_fixed_ips_from_extcp(extcp)
def apply_ext_managed_vls(hot_dict, req, grant):
# see grant first then instantiateVnfRequest
mgd_vls = (grant.get('extManagedVirtualLinks', []) +
req.get('extManagedVirtualLinks', []))
def _apply_ext_managed_vls(hot_dict, mgd_vls):
# NOTE: refer HOT only here, not refer VNFD.
# HOT and VNFD must be consistent.
for mgd_vl in mgd_vls:
vl_name = mgd_vl['vnfVirtualLinkDescId']
network_id = mgd_vl['resourceId']
@ -235,3 +244,27 @@ def apply_ext_managed_vls(hot_dict, req, grant):
for res_name in del_reses:
hot_dict['resources'].pop(res_name)
def apply_ext_managed_vls(hot_dict, req, grant):
# see grant first then instantiateVnfRequest
mgd_vls = (grant.get('extManagedVirtualLinks', []) +
req.get('extManagedVirtualLinks', []))
_apply_ext_managed_vls(hot_dict, mgd_vls)
def apply_ext_managed_vls_from_inst(hot_dict, inst):
mgd_vls = inst['instantiatedVnfInfo'].get('extManagedVirtualLinkInfo')
if mgd_vls:
# convert ExtVirtualLinkInfo to ExtManagedVirtualLinkData.
# necessary members only.
mgd_vls = [
{
'vnfVirtualLinkDescId': mgd_vl['vnfVirtualLinkDescId'],
'resourceId': mgd_vl['networkResource']['resourceId']
}
for mgd_vl in mgd_vls
]
_apply_ext_managed_vls(hot_dict, mgd_vls)

View File

@ -344,30 +344,7 @@ class VnfLcmDriverV2(object):
grant_req.addResources = add_reses
# placementConstraints
affinity_policies = {
'AFFINITY': vnfd.get_affinity_targets(flavour_id),
'ANTI_AFFINITY': vnfd.get_anti_affinity_targets(flavour_id)
}
plc_consts = []
for key, value in affinity_policies.items():
for targets, scope in value:
res_refs = []
for target in targets:
for res in add_reses:
if res.resourceTemplateId == target:
res_ref = objects.ConstraintResourceRefV1(
idType='GRANT',
resourceId=res.id)
res_refs.append(res_ref)
plc_const = objects.PlacementConstraintV1(
affinityOrAntiAffinity=key,
scope=scope.upper(),
resource=res_refs)
plc_consts.append(plc_const)
if plc_consts:
grant_req.placementConstraints = plc_consts
self._make_placementconstraints(grant_req, vnfd, add_reses)
if req.obj_attr_is_set('additionalParams'):
grant_req.additionalParams = req.additionalParams
@ -638,6 +615,10 @@ class VnfLcmDriverV2(object):
aspect_id = req.aspectId
num_steps = req.numberOfSteps
# NOTE: flavourId is not necessary according to the SOL003 spec.
# It is for local_nfvo to handle images.
grant_req.flavourId = flavour_id
vdu_num_inst = vnfd.get_scale_vdu_and_num(flavour_id, aspect_id)
if not vdu_num_inst:
# should not occur. just check for consistency.
@ -645,7 +626,7 @@ class VnfLcmDriverV2(object):
if scale_type == 'SCALE_OUT':
self._make_scale_out_grant_request(grant_req, inst, num_steps,
vdu_num_inst)
vdu_num_inst, vnfd)
else:
self._make_scale_in_grant_request(grant_req, inst, num_steps,
vdu_num_inst)
@ -654,7 +635,7 @@ class VnfLcmDriverV2(object):
grant_req.additionalParams = req.additionalParams
def _make_scale_out_grant_request(self, grant_req, inst, num_steps,
vdu_num_inst):
vdu_num_inst, vnfd):
inst_info = inst.instantiatedVnfInfo
add_reses = []
@ -690,6 +671,36 @@ class VnfLcmDriverV2(object):
if add_reses:
grant_req.addResources = add_reses
# placementConstraints
self._make_placementconstraints(grant_req, vnfd, add_reses)
def _make_placementconstraints(self, grant_req, vnfd, add_reses):
affinity_policies = {
'AFFINITY': vnfd.get_affinity_targets(grant_req.flavourId),
'ANTI_AFFINITY': vnfd.get_anti_affinity_targets(
grant_req.flavourId)
}
plc_consts = []
for key, value in affinity_policies.items():
for targets, scope in value:
res_refs = []
for target in targets:
for res in add_reses:
if res.resourceTemplateId == target:
res_ref = objects.ConstraintResourceRefV1(
idType='GRANT',
resourceId=res.id)
res_refs.append(res_ref)
plc_const = objects.PlacementConstraintV1(
affinityOrAntiAffinity=key,
scope=scope.upper(),
resource=res_refs)
plc_consts.append(plc_const)
if plc_consts:
grant_req.placementConstraints = plc_consts
def _make_scale_in_grant_request(self, grant_req, inst, num_steps,
vdu_num_inst):
inst_info = inst.instantiatedVnfInfo
@ -910,6 +921,10 @@ class VnfLcmDriverV2(object):
def heal_grant(self, grant_req, req, inst, vnfd):
inst_info = inst.instantiatedVnfInfo
# NOTE: flavourId is not necessary according to the SOL003 spec.
# It is for local_nfvo to handle images.
grant_req.flavourId = inst_info.flavourId
is_all = False # default is False
if req.obj_attr_is_set('additionalParams'):
is_all = req.additionalParams.get('all', False)

View File

@ -142,7 +142,7 @@ class StandardUserData(userdata_utils.AbstractUserData):
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
vdu_idxes[vdu_name] = 0
zones = {}
for res in grant_req['addResources']:
if res['type'] != 'COMPUTE':
continue
@ -151,14 +151,17 @@ class StandardUserData(userdata_utils.AbstractUserData):
continue
vdu_idx = vdu_idxes[vdu_name]
vdu_idxes[vdu_name] += 1
zones[add_idx(vdu_name, vdu_idx)] = (
common_script_utils.get_param_zone_by_vnfc(
res['id'], grant))
res = add_idx_to_vdu_template(poped_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)
for vdu_name_idx, vdu_value in vdus.items():
vdu_name = rm_idx(vdu_name_idx)
if 'computeFlavourId' in vdu_value:
vdu_value['computeFlavourId'] = (
common_script_utils.get_param_flavor(
@ -167,9 +170,7 @@ class StandardUserData(userdata_utils.AbstractUserData):
vdu_value['vcImageId'] = common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant)
if 'locationConstraints' in vdu_value:
vdu_value['locationConstraints'] = (
common_script_utils.get_param_zone(
vdu_name, grant_req, grant))
vdu_value['locationConstraints'] = zones[vdu_name_idx]
cps = nfv_dict.get('CP', {})
for cp_name, cp_value in cps.items():
@ -237,6 +238,7 @@ class StandardUserData(userdata_utils.AbstractUserData):
vdu_idxes[vdu_name] = common_script_utils.get_current_capacity(
vdu_name, inst)
zones = {}
for res in grant_req['addResources']:
if res['type'] != 'COMPUTE':
continue
@ -245,14 +247,17 @@ class StandardUserData(userdata_utils.AbstractUserData):
continue
vdu_idx = vdu_idxes[vdu_name]
vdu_idxes[vdu_name] += 1
zones[add_idx(vdu_name, vdu_idx)] = (
common_script_utils.get_param_zone_by_vnfc(
res['id'], grant))
res = add_idx_to_vdu_template(poped_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)
for vdu_name_idx, vdu_value in vdus.items():
vdu_name = rm_idx(vdu_name_idx)
if 'computeFlavourId' in vdu_value:
vdu_value['computeFlavourId'] = (
common_script_utils.get_param_flavor(
@ -261,9 +266,7 @@ class StandardUserData(userdata_utils.AbstractUserData):
vdu_value['vcImageId'] = common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant)
if 'locationConstraints' in vdu_value:
vdu_value['locationConstraints'] = (
common_script_utils.get_param_zone(
vdu_name, grant_req, grant))
vdu_value['locationConstraints'] = zones[vdu_name_idx]
cps = nfv_dict.get('CP', {})
for cp_name, cp_value in cps.items():
@ -289,6 +292,8 @@ class StandardUserData(userdata_utils.AbstractUserData):
fixed_ips.append(ips_i)
cp_value['fixed_ips'] = fixed_ips
common_script_utils.apply_ext_managed_vls_from_inst(top_hot, inst)
fields = {
'template': yaml.safe_dump(top_hot),
'parameters': {'nfv': nfv_dict}
@ -443,9 +448,44 @@ class StandardUserData(userdata_utils.AbstractUserData):
@staticmethod
def heal(req, inst, grant_req, grant, tmp_csar_dir):
# It is not necessary to change parameters at heal basically.
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
flavour_id = inst['instantiatedVnfInfo']['flavourId']
fields = {'parameters': {'nfv': {}}}
hot_dict = vnfd.get_base_hot(flavour_id)
top_hot = hot_dict['template']
# first modify VDU resources
poped_vdu = {}
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
for res in grant_req['removeResources']:
if res['type'] != 'COMPUTE':
continue
for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
if (inst_vnfc['computeResource']['resourceId'] ==
res['resource']['resourceId']):
# must be found
vdu_idx = inst_vnfc['metadata']['vdu_idx']
break
vdu_name = res['resourceTemplateId']
res = add_idx_to_vdu_template(poped_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:
vdu_value['vcImageId'] = common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant)
if 'locationConstraints' in vdu_value:
vdu_value.pop('locationConstraints')
fields = {'parameters': {'nfv': {'VDU': vdus}}}
return fields

View File

@ -138,9 +138,10 @@ class LocalNfvo(object):
def _get_vim_info(self, context, grant_req):
lcmocc = lcmocc_utils.get_lcmocc(context, grant_req.vnfLcmOpOccId)
req = lcmocc.operationParams
if req.obj_attr_is_set('vimConnectionInfo'):
return inst_utils.select_vim_info(req.vimConnectionInfo)
elif grant_req.operation != v2_fields.LcmOperationType.INSTANTIATE:
if grant_req.operation == v2_fields.LcmOperationType.INSTANTIATE:
if req.obj_attr_is_set('vimConnectionInfo'):
return inst_utils.select_vim_info(req.vimConnectionInfo)
else:
# should be found
inst = inst_utils.get_inst(context, grant_req.vnfInstanceId)
return inst_utils.select_vim_info(inst.vimConnectionInfo)
@ -148,21 +149,38 @@ class LocalNfvo(object):
# NOTE: exception is not raised.
return vim_utils.get_default_vim(context)
def _handle_vim_assets(self, grant_req, grant_res, vnfd, sw_image_data,
vim_info):
def _handle_vim_assets(self, context, grant_req, grant_res, vnfd):
vim_info = self._get_vim_info(context, grant_req)
if vim_info is None:
msg = "No vimConnectionInfo to handle glance image"
raise sol_ex.LocalNfvoGrantFailed(sol_detail=msg)
elif vim_info.vimType != 'ETSINFV.OPENSTACK_KEYSTONE.V_3':
return
target_vdus = {res['resourceTemplateId']
for res in grant_req['addResources']}
all_sw_image_data = vnfd.get_sw_image_data(grant_req.flavourId)
sw_image_data = {res_id: sw_data
for res_id, sw_data in all_sw_image_data.items()
if res_id in target_vdus}
vim_sw_images = []
image_names = {}
if grant_req.operation != v2_fields.LcmOperationType.INSTANTIATE:
glance_client = glance_utils.GlanceClient(vim_info)
images = glance_client.list_images(tag=grant_req.vnfInstanceId)
image_names = {image.name: image.id for image in images}
for res_id, sw_data in sw_image_data.items():
if 'file' in sw_data:
if 'file' in sw_data and sw_data['name'] in image_names:
image = image_names[sw_data['name']]
elif 'file' in sw_data:
# if artifact is specified, create glance image.
# it may fail. catch exception and raise 403(not granted)
# if error occur.
if vim_info is None:
msg = "No vimConnectionInfo to create glance image"
raise sol_ex.LocalNfvoGrantFailed(sol_detail=msg)
# if error occurs.
try:
image = self._glance_create_image(vim_info, vnfd, sw_data,
grant_req.vnfInstanceId)
grant_req.vnfInstanceId)
except Exception:
msg = "glance image create failed"
LOG.exception(msg)
@ -180,42 +198,46 @@ class LocalNfvo(object):
softwareImages=vim_sw_images
)
def instantiate_grant(self, context, grant_req, grant_res):
# handle ZoneInfo
def _handle_zoneinfo(self, grant_res):
zone_list = config.CONF.v2_nfvo.test_grant_zone_list
zone_id = None
if len(zone_list) > 0:
zone_infos = []
for zone in zone_list:
zone_info = objects.ZoneInfoV1(
id=uuidutils.generate_uuid(),
zoneId=zone
)
zone_infos.append(zone_info)
grant_res.zones = zone_infos
zone_id = zone_infos[0].id
if len(zone_list) == 0:
return None
zone_infos = []
for zone in zone_list:
zone_info = objects.ZoneInfoV1(
id=uuidutils.generate_uuid(),
zoneId=zone
)
zone_infos.append(zone_info)
grant_res.zones = zone_infos
return zone_infos[0].id
# handle addResources.
def _handle_addresources(self, grant_req, grant_res, zone_id):
# only copy req to res. i.e. grant all.
attr = 'addResources'
if grant_req.obj_attr_is_set(attr):
add_res = []
for res_def in grant_req[attr]:
g_info = objects.GrantInfoV1(
resourceDefinitionId=res_def.id
)
if zone_id is not None and res_def.type == 'COMPUTE':
g_info.zoneId = zone_id
add_res.append(g_info)
grant_res[attr] = add_res
if not grant_req.obj_attr_is_set(attr):
return
add_res = []
for res_def in grant_req[attr]:
g_info = objects.GrantInfoV1(
resourceDefinitionId=res_def.id
)
if zone_id is not None and res_def.type == 'COMPUTE':
g_info.zoneId = zone_id
add_res.append(g_info)
grant_res[attr] = add_res
def instantiate_grant(self, context, grant_req, grant_res):
# handle ZoneInfo
zone_id = self._handle_zoneinfo(grant_res)
# handle addResources
self._handle_addresources(grant_req, grant_res, zone_id)
# handle vimAssets
# if there is an artifact, create glance image.
vnfd = self.get_vnfd(context, grant_req.vnfdId)
sw_image_data = vnfd.get_sw_image_data(grant_req.flavourId)
vim_info = self._get_vim_info(context, grant_req)
self._handle_vim_assets(grant_req, grant_res, vnfd,
sw_image_data, vim_info)
self._handle_vim_assets(context, grant_req, grant_res, vnfd)
def change_vnfpkg_grant(self, context, grant_req, grant_res):
if not grant_req.obj_attr_is_set('addResources'):
@ -223,16 +245,31 @@ class LocalNfvo(object):
# handle vimAssets
# if there is an artifact, create glance image.
target_vdus = {res['resourceTemplateId']
for res in grant_req['addResources']}
vnfd = self.get_vnfd(context, grant_req.dstVnfdId)
all_sw_image_data = vnfd.get_sw_image_data(grant_req.flavourId)
sw_image_data = {res_id: sw_data
for res_id, sw_data in all_sw_image_data.items()
if res_id in target_vdus}
vim_info = self._get_vim_info(context, grant_req)
self._handle_vim_assets(grant_req, grant_res, vnfd,
sw_image_data, vim_info)
self._handle_vim_assets(context, grant_req, grant_res, vnfd)
def scale_grant(self, context, grant_req, grant_res):
if not grant_req.obj_attr_is_set('addResources'):
return
# handle ZoneInfo
zone_id = self._handle_zoneinfo(grant_res)
# handle addResources
self._handle_addresources(grant_req, grant_res, zone_id)
# handle vimAssets
# if there is an artifact, create glance image.
vnfd = self.get_vnfd(context, grant_req.vnfdId)
self._handle_vim_assets(context, grant_req, grant_res, vnfd)
def heal_grant(self, context, grant_req, grant_res):
if not grant_req.obj_attr_is_set('addResources'):
return
# handle vimAssets
# if there is an artifact, create glance image.
vnfd = self.get_vnfd(context, grant_req.vnfdId)
self._handle_vim_assets(context, grant_req, grant_res, vnfd)
def grant(self, context, grant_req):
grant_res = objects.GrantV1(
@ -246,6 +283,10 @@ class LocalNfvo(object):
self.instantiate_grant(context, grant_req, grant_res)
elif grant_req.operation == v2_fields.LcmOperationType.CHANGE_VNFPKG:
self.change_vnfpkg_grant(context, grant_req, grant_res)
elif grant_req.operation == v2_fields.LcmOperationType.SCALE:
self.scale_grant(context, grant_req, grant_res)
elif grant_req.operation == v2_fields.LcmOperationType.HEAL:
self.heal_grant(context, grant_req, grant_res)
endpoint = config.CONF.v2_vnfm.endpoint
grant_res._links = objects.GrantV1_Links(

View File

@ -451,3 +451,111 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
# Delete VNF instance
self._delete_instance(inst_id)
def test_heal_vnfc_after_image_change(self):
"""Test heal operation after image change using StandardUserData
* Note:
This test focuses on checking changed image when Heal operation
run after the vnfdId is changed by modify operation.
* About LCM operations:
This test includes the following operations.
- Create VNF instance
- 1. Instantiate VNF instance
- Show VNF instance / check
- 2. Update VNF instance
- Show VNF instance / check
- 3. Heal operation
- Show VNF instance / check
- Terminate VNF instance
- Delete VNF instance
"""
net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt'])
subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1'])
# Create VNF instance
create_req = paramgen.sample3_create(self.vnfd_id_1)
resp, body = self.create_vnf_instance(create_req)
self.assertEqual(201, resp.status_code)
inst_id = body['id']
# 1. Instantiate VNF instance
instantiate_req = paramgen.sample3_instantiate(
net_ids, subnet_ids, self.auth_url)
instantiate_req['instantiationLevelId'] = 'instantiation_level_2'
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
self.assertEqual(202, resp.status_code)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# Show VNF instance
resp, inst_1 = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
# check number of VDUs and indexes
self.assertEqual({0, 1}, self._get_vdu_indexes(inst_1, 'VDU1'))
self.assertEqual({0}, self._get_vdu_indexes(inst_1, 'VDU2'))
# 2. Update VNF instance
update_req = paramgen.sample3_update_vnf_vnfd_id(self.vnfd_id_2)
resp, body = self.update_vnf_instance(inst_id, update_req)
self.assertEqual(202, resp.status_code)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# Show VNF instance
resp, inst_2 = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
# check number of VDUs and indexes
self.assertEqual({0, 1}, self._get_vdu_indexes(inst_2, 'VDU1'))
self.assertEqual({0}, self._get_vdu_indexes(inst_2, 'VDU2'))
# check vnfdId is changed
self.assertEqual(self.vnfd_id_2, inst_2['vnfdId'])
# 3. Heal operation
heal_req = paramgen.sample3_heal()
# pick up VDU1-1 to heal
vnfc_id = self._get_vnfc_id(inst_2, 'VDU1', 1)
heal_req['vnfcInstanceId'] = [f'VDU1-{vnfc_id}']
resp, body = self.heal_vnf_instance(inst_id, heal_req)
self.assertEqual(202, resp.status_code)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# Show VNF instance
resp, inst_3 = self.show_vnf_instance(inst_id)
self.assertEqual(200, resp.status_code)
# check id of VDU1-1 is changed and other are not.
self.assertEqual(self._get_vnfc_id(inst_2, 'VDU1', 0),
self._get_vnfc_id(inst_3, 'VDU1', 0))
self.assertNotEqual(self._get_vnfc_id(inst_2, 'VDU1', 1),
self._get_vnfc_id(inst_3, 'VDU1', 1))
self.assertEqual(self._get_vnfc_id(inst_2, 'VDU2', 0),
self._get_vnfc_id(inst_3, 'VDU2', 0))
# check image of VDU1-1 is changed and other are not.
self.assertEqual(self._get_vnfc_image(inst_2, 'VDU1', 0),
self._get_vnfc_image(inst_3, 'VDU1', 0))
self.assertNotEqual(self._get_vnfc_image(inst_2, 'VDU1', 1),
self._get_vnfc_image(inst_3, 'VDU1', 1))
self.assertEqual(self._get_vnfc_image(inst_2, 'VDU2', 0),
self._get_vnfc_image(inst_3, 'VDU2', 0))
# Terminate VNF instance
terminate_req = paramgen.sample3_terminate()
resp, body = self.terminate_vnf_instance(inst_id, terminate_req)
self.assertEqual(202, resp.status_code)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# Delete VNF instance
self._delete_instance(inst_id)

View File

@ -1105,6 +1105,15 @@ def sample3_change_ext_conn(net_ids):
}
# sample3_update_vnf_vnfd_id is for test heal after vnfdId changed
# in StandardUserData.
#
def sample3_update_vnf_vnfd_id(vnfd_id):
return {
"vnfdId": vnfd_id
}
# sample4 is for change_vnfpkg test of StandardUserData
#
def sample4_change_vnfpkg(vnfd_id, net_ids, subnet_ids):

View File

@ -37,7 +37,7 @@ terminate_req = paramgen.terminate_vnf_min()
instantiate_req = paramgen.instantiate_vnf_min()
scaleout_req = paramgen.scaleout_vnf_min()
scalein_req = paramgen.scalein_vnf_min()
update_seq = paramgen.update_vnf_min()
update_req = paramgen.update_vnf_min()
# fake vnfc id, should be get from show vnf
VNFC_ID = "VDU1-9300a3cb-bd3b-45e4-9967-095040caf827"
heal_req = paramgen.heal_vnf_vnfc_min(VNFC_ID)
@ -62,8 +62,8 @@ with open("scaleout_req", "w", encoding='utf-8') as f:
with open("scalein_req", "w", encoding='utf-8') as f:
f.write(json.dumps(scalein_req, indent=2))
with open("update_seq", "w", encoding='utf-8') as f:
f.write(json.dumps(update_seq, indent=2))
with open("update_req", "w", encoding='utf-8') as f:
f.write(json.dumps(update_req, indent=2))
with open("heal_req", "w", encoding='utf-8') as f:
f.write(json.dumps(heal_req, indent=2))

View File

@ -37,7 +37,7 @@ terminate_req = paramgen.terminate_vnf_min()
instantiate_req = paramgen.instantiate_vnf_min()
scaleout_req = paramgen.scaleout_vnf_min()
scalein_req = paramgen.scalein_vnf_min()
update_seq = paramgen.update_vnf_min()
update_req = paramgen.update_vnf_min()
# fake vnfc id, should be get from show vnf
VNFC_ID = "VDU1-9300a3cb-bd3b-45e4-9967-095040caf827"
heal_req = paramgen.heal_vnf_vnfc_min(VNFC_ID)
@ -62,8 +62,8 @@ with open("scaleout_req", "w", encoding='utf-8') as f:
with open("scalein_req", "w", encoding='utf-8') as f:
f.write(json.dumps(scalein_req, indent=2))
with open("update_seq", "w", encoding='utf-8') as f:
f.write(json.dumps(update_seq, indent=2))
with open("update_req", "w", encoding='utf-8') as f:
f.write(json.dumps(update_req, indent=2))
with open("heal_req", "w", encoding='utf-8') as f:
f.write(json.dumps(heal_req, indent=2))

View File

@ -6,14 +6,14 @@ parameters:
type: string
image-VDU1:
type: string
zone:
type: string
net1:
type: string
net2:
type: string
net3:
type: string
affinity:
type: string
resources:
VDU1:
@ -31,8 +31,7 @@ resources:
get_resource: VDU1_CP2
- port:
get_resource: VDU1_CP3
scheduler_hints:
group: { get_param: affinity }
availability_zone: { get_param: zone }
# extVL without FixedIP or with numDynamicAddresses
VDU1_CP1:

View File

@ -34,7 +34,7 @@ resources:
- port:
get_resource: VDU2_CP3
scheduler_hints:
group: {get_param: affinity }
group: { get_param: affinity }
VDU2-VirtualStorage:
type: OS::Cinder::Volume

View File

@ -11,10 +11,10 @@ resources:
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
net2: { get_resource: internalVL1 }
net3: { get_resource: internalVL2 }
affinity: { get_resource: nfvi_node_affinity }
VDU2:
type: VDU2.yaml

View File

@ -59,6 +59,7 @@ scale_out_req = paramgen.sample3_scale_out()
scale_in_req = paramgen.sample3_scale_in()
heal_req = paramgen.sample3_heal()
change_ext_conn_req = paramgen.sample3_change_ext_conn(net_ids)
update_req = paramgen.sample3_update_vnf_vnfd_id("replace real vnfd id")
with open("create_req", "w") as f:
f.write(json.dumps(create_req, indent=2))
@ -81,3 +82,6 @@ with open("heal_req", "w") as f:
with open("change_ext_conn_req", "w") as f:
f.write(json.dumps(change_ext_conn_req, indent=2))
with open("update_req", "w") as f:
f.write(json.dumps(update_req, indent=2))

View File

@ -237,6 +237,71 @@ class TestCommontScriptUtils(base.BaseTestCase):
result = common_script_utils.get_param_zone('VDU1', grant_req, grant)
self.assertEqual('nova', result)
def test_get_param_zone_by_vnfc(self):
grant = {
'zones': [
{'id': '717f6ae9-3094-46b6-b070-89ede8337571',
'zoneId': 'az-1'},
{'id': 'ebccc5a7-0ed4-492d-9d9e-d61414817563',
'zoneId': 'az-2'}
],
'addResources': [
{'resourceDefinitionId':
'dd60c89a-29a2-43bc-8cff-a534515523df',
'zoneId': '717f6ae9-3094-46b6-b070-89ede8337571'},
{'resourceDefinitionId':
'3aa7450b-6d5f-4e82-9ad5-35d7e77f1ae9',
'zoneId': 'ebccc5a7-0ed4-492d-9d9e-d61414817563'}
]
}
result = common_script_utils.get_param_zone_by_vnfc(
'dd60c89a-29a2-43bc-8cff-a534515523df', grant)
self.assertEqual('az-1', result)
result = common_script_utils.get_param_zone_by_vnfc(
'3aa7450b-6d5f-4e82-9ad5-35d7e77f1ae9', grant)
self.assertEqual('az-2', result)
def test_get_param_zone_by_vnfc_no_zones(self):
grant = {
'addResources': [
{'resourceDefinitionId':
'dd60c89a-29a2-43bc-8cff-a534515523df',
'zoneId': '717f6ae9-3094-46b6-b070-89ede8337571'}
]
}
result = common_script_utils.get_param_zone_by_vnfc(
'dd60c89a-29a2-43bc-8cff-a534515523df', grant)
self.assertEqual(None, result)
def test_get_param_zone_by_vnfc_no_add_resources(self):
grant = {
'zones': [
{'id': '717f6ae9-3094-46b6-b070-89ede8337571',
'zoneId': 'az-1'}
]
}
result = common_script_utils.get_param_zone_by_vnfc(
'dd60c89a-29a2-43bc-8cff-a534515523df', grant)
self.assertEqual(None, result)
def test_get_param_zone_by_vnfc_no_zone_id(self):
grant = {
'zones': [
{'id': '717f6ae9-3094-46b6-b070-89ede8337571',
'zoneId': 'az-1'}
],
'addResources': [
{'resourceDefinitionId':
'dd60c89a-29a2-43bc-8cff-a534515523df'},
]
}
result = common_script_utils.get_param_zone_by_vnfc(
'dd60c89a-29a2-43bc-8cff-a534515523df', grant)
self.assertEqual(None, result)
def test_get_param_capacity(self):
# test get_current_capacity at the same time
grant_req = {

View File

@ -1083,6 +1083,17 @@ class TestVnfLcmDriverV2(base.BaseTestCase):
for name, ids in value.items():
self.assertEqual(expected_num[key][name], len(ids))
expected_placement_constraints = [{
'affinityOrAntiAffinity': 'ANTI_AFFINITY',
'scope': 'NFVI_NODE',
'resource': []}]
vdu_def_ids = check_reses['COMPUTE']['VDU1']
for def_id in vdu_def_ids:
expected_placement_constraints[0]['resource'].append(
{'idType': 'GRANT', 'resourceId': def_id})
self.assertEqual(expected_placement_constraints,
grant_req['placementConstraints'])
@mock.patch.object(nfvo_client.NfvoClient, 'grant')
def test_scale_grant_scale_in(self, mocked_grant):
# prepare

View File

@ -478,10 +478,11 @@ class TestLocalNfvo(base.BaseTestCase):
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'list_images')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
@mock.patch.object(inst_utils, 'get_inst')
def test_change_vnfpkg_grant(self, mock_inst, mock_image,
mock_lcmocc, mock_dir):
mock_list_images, mock_lcmocc, mock_dir):
grant_req = objects.GrantRequestV1.from_dict(
_change_vnfkg_grant_req_example)
grant_res = objects.GrantV1(
@ -497,6 +498,7 @@ class TestLocalNfvo(base.BaseTestCase):
mock_lcmocc.return_value = objects.VnfLcmOpOccV2(
operation=fields.LcmOperationType.CHANGE_VNFPKG,
operationParams=req)
mock_list_images.return_value = []
mock_image.return_value = objects.GrantV1(
id=uuidutils.generate_uuid()
)
@ -539,10 +541,11 @@ class TestLocalNfvo(base.BaseTestCase):
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'list_images')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
@mock.patch.object(inst_utils, 'get_inst')
def test_change_vnfpkg_grant_no_image(self, mock_inst, mock_image,
mock_lcmocc, mock_dir):
mock_list_images, mock_lcmocc, mock_dir):
grant_req = objects.GrantRequestV1.from_dict(
_change_vnfkg_grant_req_example)
grant_res = objects.GrantV1(
@ -572,6 +575,7 @@ class TestLocalNfvo(base.BaseTestCase):
vimConnectionInfo=req.vimConnectionInfo
)
mock_inst.return_value = inst
mock_list_images.return_value = []
mock_image.return_value = Exception()
self.assertRaises(
sol_ex.LocalNfvoGrantFailed, self.local_nfvo.change_vnfpkg_grant,
@ -579,9 +583,11 @@ class TestLocalNfvo(base.BaseTestCase):
@mock.patch.object(local_nfvo.LocalNfvo, 'get_csar_dir')
@mock.patch.object(lcmocc_utils, 'get_lcmocc')
@mock.patch.object(glance_utils.GlanceClient, 'list_images')
@mock.patch.object(glance_utils.GlanceClient, 'create_image')
@mock.patch.object(inst_utils, 'get_inst')
def test_grant(self, mock_inst, mock_image, mock_lcmocc, mock_dir):
def test_grant(self, mock_inst, mock_image, mock_list_images,
mock_lcmocc, mock_dir):
# instantiate
grant_req = objects.GrantRequestV1.from_dict(_inst_grant_req_example)
cur_dir = os.path.dirname(__file__)
@ -613,6 +619,7 @@ class TestLocalNfvo(base.BaseTestCase):
operation=fields.LcmOperationType.CHANGE_VNFPKG,
operationParams=req
)
mock_list_images.return_value = []
mock_image.return_value = objects.GrantV1(
id=uuidutils.generate_uuid()
)