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:
parent
be6d22b409
commit
2f89ccc8a5
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user