Refactor change_vnfpkg v2 API

This patch refactors the implementation of change_vnfpkg v2 API.

Because the original implementation of change_vnfpkg does not obey
the rules that other operations obey, it makes hard to enhance
the function that related to whole operations such as the HOT format
change. This patch corrects it.

This patch also changes some specifications of the API and fixes
some bugs (described in bug #1981533).

Specification changes:
* image to volume translation (or vice versa) is not supported.
  Note that it did not work property by a bug.
* parameters to the coordinate script are changed.
* property name for images in the definition of AutoScalingGroup is
  changed.
* unnecessary parameters of additionalParams,
  'lcm-operation-coordinate-old-vnf-class' and
  'lcm-operation-coordinate-new-vnf-class' are removed.
* 'lcm-operation-coordinate-old-vnf' and
  'lcm-operation-coordinate-new-vnf' in additionalParams are option
   now.

Detail of bug fiexes are omitted.

Note that the object of this patch is common part and openstack VIM part.
k8s VIM part will be fixed by another patch.

Closes-Bug: #1981533
Change-Id: I9f6d103d66e6904704ca467d68c4ebfbcbd8a1f8
This commit is contained in:
Itsuro Oda 2022-07-08 01:40:22 +00:00
parent b8c1f9daa2
commit acb231d7e1
55 changed files with 827 additions and 2180 deletions

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnfd_utils
@ -23,47 +22,6 @@ def get_vnfd(vnfd_id, csar_dir):
return vnfd
def get_vdu_info(grant, inst, vnfd):
volume_name = ''
volume_size = ''
flavour_id = inst['instantiatedVnfInfo']['flavourId']
vdu_nodes = vnfd.get_vdu_nodes(flavour_id)
storage_nodes = vnfd.get_storage_nodes(flavour_id)
vdu_info_dict = {}
for name, node in vdu_nodes.items():
flavor = get_param_flavor(name, flavour_id, vnfd, grant)
image = get_param_image(name, flavour_id, vnfd, grant)
vdu_storage_names = vnfd.get_vdu_storages(node)
for vdu_storage_name in vdu_storage_names:
if storage_nodes[vdu_storage_name].get(
'properties', {}).get('sw_image_data'):
image = get_param_image(vdu_storage_name, flavour_id, vnfd,
grant)
volume_name = vdu_storage_name
volume_size = storage_nodes[vdu_storage_name].get(
'properties', {}).get(
'virtual_block_storage_data', '').get(
'size_of_storage', ''
)
volume_size = volume_size.rstrip(' GB')
if not volume_size.isdigit():
raise sol_ex.VmRunningFailed(
error_info='The volume size set in VNFD is invalid.')
break
vdu_info_dict[name] = {
"flavor": flavor,
"image": image
}
if volume_name:
vdu_info_dict[name]['volume_info'] = {
"volume_name": volume_name,
"volume_size": volume_size
}
return vdu_info_dict
def init_nfv_dict(hot_template):
get_params = []

View File

@ -131,10 +131,6 @@ class VnfInstanceIsNotInstantiated(SolHttpError409):
message = _("VnfInstance %(inst_id)s isn't instantiated.")
class VnfInstanceIsNotChanged(SolHttpError409):
message = _("VnfInstance %(inst_id)s isn't changed.")
class LccnSubscriptionNotFound(SolHttpError404):
message = _("LccnSubscription %(subsc_id)s not found.")
@ -260,15 +256,6 @@ class ConductorProcessingError(SolException):
message = _("Failure due to conductor processing error.")
class InvalidVolumeSize(SolHttpError400):
message = _("The volume size set in VNFD is invalid.")
class VduIdNotFound(SolHttpError404):
message = _("This vdu_id '%(vdu_id)s' does not exist"
" in current VnfInstance.")
class SshIpNotFoundException(SolHttpError404):
message = _("Ssh ip not found.")

View File

@ -147,6 +147,31 @@ def _make_affected_vnfc(vnfc, change_type, strgs):
return affected_vnfc
def _make_affected_vnfc_modified(vnfc, vnfc_saved):
affected_vnfc = objects.AffectedVnfcV2(
id=vnfc.id,
vduId=vnfc.vduId,
changeType='MODIFIED',
computeResource=vnfc.computeResource
)
affected_vnfc.metadata = vnfc.metadata
# NOTE: cps may not be affected.
if vnfc.obj_attr_is_set('vnfcCpInfo'):
cp_ids = [cp.id for cp in vnfc.vnfcCpInfo]
affected_vnfc.affectedVnfcCpIds = cp_ids
if vnfc.obj_attr_is_set('storageResourceIds'):
added_str_ids = (set(vnfc.storageResourceIds) -
set(vnfc_saved.storageResourceIds))
removed_str_ids = (set(vnfc_saved.storageResourceIds) -
set(vnfc.storageResourceIds))
if added_str_ids:
affected_vnfc.addedStorageResourceIds = list(added_str_ids)
if removed_str_ids:
affected_vnfc.removedStorageResourceIds = list(removed_str_ids)
return affected_vnfc
def _make_affected_vl(vl, change_type):
affected_vl = objects.AffectedVirtualLinkV2(
id=vl.id,
@ -383,15 +408,7 @@ def update_lcmocc(lcmocc, inst_saved, inst):
for strg in inst_info.virtualStorageResourceInfo
if strg.id in added_strgs]
removed_vnfcs, added_vnfcs, common_objs = _calc_diff('vnfcResourceInfo')
updated_vnfcs = []
if lcmocc.operation == fields.LcmOperationType.CHANGE_VNFPKG:
updated_vnfcs = [
obj.id for obj in inst_info.vnfcResourceInfo
if obj.metadata.get('current_vnfd_id') != inst_saved.vnfdId
and obj.id in common_objs and
obj.metadata.get('current_vnfd_id') is not None]
removed_vnfcs, added_vnfcs, common_vnfcs = _calc_diff('vnfcResourceInfo')
affected_vnfcs = []
if removed_vnfcs:
affected_vnfcs += [
@ -405,11 +422,18 @@ def update_lcmocc(lcmocc, inst_saved, inst):
for vnfc in inst_info.vnfcResourceInfo
if vnfc.id in added_vnfcs
]
if lcmocc.operation == fields.LcmOperationType.CHANGE_VNFPKG:
def _get_vnfc(vnfc_id, inst_info):
for vnfc in inst_info.vnfcResourceInfo:
if vnfc.id == vnfc_id:
return vnfc
if updated_vnfcs:
affected_vnfcs += [_make_affected_vnfc(vnfc, 'MODIFIED', added_strgs)
for vnfc in inst_info.vnfcResourceInfo
if vnfc.id in updated_vnfcs]
for obj_id in common_vnfcs:
vnfc = _get_vnfc(obj_id, inst_info)
vnfc_saved = _get_vnfc(obj_id, inst_saved.instantiatedVnfInfo)
if vnfc.metadata != vnfc_saved.metadata:
affected_vnfcs.append(
_make_affected_vnfc_modified(vnfc, vnfc_saved))
removed_vls, added_vls, common_vls = _calc_diff(
'vnfVirtualLinkResourceInfo')

View File

@ -14,7 +14,6 @@
# under the License.
from oslo_log import log as logging
from oslo_utils import uuidutils
from tacker.common import log
from tacker import context as tacker_context
@ -93,7 +92,7 @@ class ConductorV2(object):
inst = inst_utils.get_inst(context, lcmocc.vnfInstanceId)
# NOTE: error cannot happen to here basically.
# if an error occurred lcmocc.opetationState remains STARTING.
# if an error occurred lcmocc.operationState remains STARTING.
# see the log of the tacker-conductor to investigate the cause
# of error.
@ -250,24 +249,8 @@ class ConductorV2(object):
context, lcmocc)
self.vnflcm_driver.post_grant(context, lcmocc, inst, grant_req,
grant, vnfd)
if lcmocc.operation == fields.LcmOperationType.CHANGE_VNFPKG:
inst_lcmocc = lcmocc_utils.get_inst_lcmocc(context, inst)
inst_grant_req = objects.GrantRequestV1(
vnfInstanceId=inst.id,
vnfLcmOpOccId=inst_lcmocc.id,
operation=inst_lcmocc.operation,
isAutomaticInvocation=lcmocc.isAutomaticInvocation
)
inst_grant = objects.GrantV1(
id=uuidutils.generate_uuid(),
vnfInstanceId=inst_grant_req.vnfInstanceId,
vnfLcmOpOccId=inst_grant_req.vnfLcmOpOccId
)
self.vnflcm_driver.rollback(
context, lcmocc, inst, inst_grant_req, inst_grant, vnfd)
else:
self.vnflcm_driver.rollback(context, lcmocc, inst, grant_req,
grant, vnfd)
self.vnflcm_driver.rollback(context, lcmocc, inst, grant_req,
grant, vnfd)
lcmocc.operationState = fields.LcmOperationStateType.ROLLED_BACK
with context.session.begin(subtransactions=True):

View File

@ -68,13 +68,10 @@ class VnfLcmDriverV2(object):
grant_req = objects.GrantRequestV1(
vnfInstanceId=inst.id,
vnfLcmOpOccId=lcmocc.id,
vnfdId=inst.vnfdId,
operation=lcmocc.operation,
isAutomaticInvocation=lcmocc.isAutomaticInvocation
)
if lcmocc.operation == v2fields.LcmOperationType.CHANGE_VNFPKG:
grant_req.vnfdId = lcmocc.operationParams.get('vnfdId')
else:
grant_req.vnfdId = inst.vnfdId
grant_req._links = objects.GrantRequestV1_Links(
vnfLcmOpOcc=objects.Link(
href=lcmocc_utils.lcmocc_href(lcmocc.id, self.endpoint)),
@ -966,67 +963,68 @@ class VnfLcmDriverV2(object):
# only support openstack at the moment
raise sol_ex.SolException(sol_detail='not support vim type')
def change_ext_conn_rollback(self, context, lcmocc, inst, grant_req,
grant, vnfd):
req = lcmocc.operationParams
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
if vim_info.vimType == 'ETSINFV.OPENSTACK_KEYSTONE.V_3':
driver = openstack.Openstack()
driver.change_ext_conn_rollback(req, inst, grant_req, grant, vnfd)
else:
# only support openstack at the moment
raise sol_ex.SolException(sol_detail='not support vim type')
def change_vnfpkg_grant(self, grant_req, req, inst, vnfd):
inst_info = inst.instantiatedVnfInfo
grant_req.flavourId = inst_info.flavourId
if req.additionalParams.get('vdu_params'):
target_vdu_ids = [
vdu_param.get(
'vdu_id') for vdu_param in req.additionalParams.get(
'vdu_params')]
grant_req.dstVnfdId = req.vnfdId
# NOTE: flavourId is not necessary according to the SOL003 spec.
# It is for local_nfvo to handle images.
grant_req.flavourId = inst.instantiatedVnfInfo.flavourId
if req.additionalParams['upgrade_type'] == 'RollingUpdate':
self._change_vnfpkg_grant_rolling_update(
grant_req, req, inst, vnfd)
else:
if inst_info.obj_attr_is_set('vnfcResourceInfo'):
target_vdu_ids = [inst_vnc.vduId for inst_vnc in
inst_info.vnfcResourceInfo]
if req.additionalParams.get('upgrade_type') == 'RollingUpdate':
update_reses = []
add_reses = []
remove_reses = []
if inst_info.obj_attr_is_set('vnfcResourceInfo'):
for inst_vnc in inst_info.vnfcResourceInfo:
if inst_vnc.vduId in target_vdu_ids:
vdu_res_id = uuidutils.generate_uuid()
res_def = objects.ResourceDefinitionV1(
id=vdu_res_id,
type='COMPUTE',
resourceTemplateId=inst_vnc.vduId)
update_reses.append(res_def)
nodes = vnfd.get_vdu_nodes(inst_info.flavourId)
vdu_storage_names = vnfd.get_vdu_storages(
nodes[inst_vnc.vduId])
for vdu_storage_name in vdu_storage_names:
res_def = objects.ResourceDefinitionV1(
id=_make_combination_id(
vdu_storage_name, vdu_res_id),
type='STORAGE',
resourceTemplateId=vdu_storage_name)
add_reses.append(res_def)
if inst_vnc.obj_attr_is_set('storageResourceIds'):
inst_stor_info = (
inst_info.virtualStorageResourceInfo)
for str_info in inst_stor_info:
if str_info.id in inst_vnc.storageResourceIds:
res_def = objects.ResourceDefinitionV1(
id=uuidutils.generate_uuid(),
type='STORAGE',
resourceTemplateId=(
str_info.virtualStorageDescId),
resource=str_info.storageResource)
remove_reses.append(res_def)
if update_reses:
grant_req.updateResources = update_reses
if add_reses:
grant_req.addResources = add_reses
if remove_reses:
grant_req.removeResources = remove_reses
else:
# TODO(YiFeng): Blue-Green type will be supported in Zed release.
# not reach here at the moment
# Only support RollingUpdate at the moment.
pass
def _change_vnfpkg_grant_rolling_update(self, grant_req, req, inst, vnfd):
inst_info = inst.instantiatedVnfInfo
if not inst_info.obj_attr_is_set('vnfcResourceInfo'):
return
if req.additionalParams.get('vdu_params'):
vdu_ids = [vdu_param['vdu_id']
for vdu_param in req.additionalParams['vdu_params']]
inst_vnfcs = [inst_vnfc
for inst_vnfc in inst_info.vnfcResourceInfo
if inst_vnfc.vduId in vdu_ids]
else:
inst_vnfcs = inst_info.vnfcResourceInfo
add_reses = []
rm_reses = []
for inst_vnfc in inst_vnfcs:
rm_vdu_res_id = uuidutils.generate_uuid()
add_vdu_res_id = uuidutils.generate_uuid()
self._set_rm_add_reses(rm_reses, add_reses, 'COMPUTE',
inst_vnfc.vduId, inst_vnfc.computeResource,
rm_vdu_res_id, add_vdu_res_id)
if inst_vnfc.obj_attr_is_set('storageResourceIds'):
for storage_id in inst_vnfc.storageResourceIds:
inst_str = _get_obj_by_id(storage_id,
inst_info.virtualStorageResourceInfo)
str_name = inst_str.virtualStorageDescId
self._set_rm_add_reses(rm_reses, add_reses, 'STORAGE',
str_name, inst_str.storageResource,
_make_combination_id(str_name, rm_vdu_res_id),
_make_combination_id(str_name, add_vdu_res_id))
if add_reses:
grant_req.addResources = add_reses
if rm_reses:
grant_req.removeResources = rm_reses
def _pre_check_for_change_vnfpkg(self, context, req, inst, vnfd):
def _get_file_content(file_path):
if ((urlparse(file_path).scheme == 'file') or
@ -1093,16 +1091,14 @@ class VnfLcmDriverV2(object):
def change_vnfpkg_process(
self, context, lcmocc, inst, grant_req, grant, vnfd):
inst_saved = inst.obj_clone()
req = lcmocc.operationParams
if req.obj_attr_is_set('vimConnectionInfo'):
self._merge_vim_connection_info(inst, req)
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
if vim_info.vimType == 'ETSINFV.OPENSTACK_KEYSTONE.V_3':
driver = openstack.Openstack()
try:
driver.change_vnfpkg(req, inst, grant_req, grant, vnfd)
except Exception as ex:
lcmocc_utils.update_lcmocc(lcmocc, inst_saved, inst)
raise Exception from ex
driver.change_vnfpkg(req, inst, grant_req, grant, vnfd)
elif vim_info.vimType == 'kubernetes': # k8s
target_k8s_files = self._pre_check_for_change_vnfpkg(
context, req, inst, vnfd)
@ -1110,32 +1106,19 @@ class VnfLcmDriverV2(object):
update_req.additionalParams[
'lcm-kubernetes-def-files'] = target_k8s_files
driver = kubernetes.Kubernetes()
try:
driver.change_vnfpkg(update_req, inst, grant_req, grant, vnfd)
except Exception as ex:
lcmocc_utils.update_lcmocc(lcmocc, inst_saved, inst)
raise Exception from ex
driver.change_vnfpkg(update_req, inst, grant_req, grant, vnfd)
else:
# should not occur
raise sol_ex.SolException(sol_detail='not support vim type')
def change_ext_conn_rollback(self, context, lcmocc, inst, grant_req,
grant, vnfd):
req = lcmocc.operationParams
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
if vim_info.vimType == 'ETSINFV.OPENSTACK_KEYSTONE.V_3':
driver = openstack.Openstack()
driver.change_ext_conn_rollback(req, inst, grant_req, grant, vnfd)
else:
# only support openstack at the moment
raise sol_ex.SolException(sol_detail='not support vim type')
inst.vnfdId = grant_req.dstVnfdId
def change_vnfpkg_rollback(
self, context, lcmocc, inst, grant_req, grant, vnfd):
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
req = lcmocc.operationParams
driver = openstack.Openstack()
if vim_info.vimType == 'ETSINFV.OPENSTACK_KEYSTONE.V_3':
driver = openstack.Openstack()
driver.change_vnfpkg_rollback(
req, inst, grant_req, grant, vnfd, lcmocc)
elif vim_info.vimType == 'kubernetes': # k8s

View File

@ -383,6 +383,43 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
return sol_wsgi.SolResponse(202, None, location=location)
def _check_vdu_params(self, inst, vdu_params, vim_type, new_script,
old_script):
inst_vdu_ids = []
if inst.instantiatedVnfInfo.obj_attr_is_set('vnfcResourceInfo'):
inst_vdu_ids = [inst_vnfc.vduId
for inst_vnfc in inst.instantiatedVnfInfo.vnfcResourceInfo]
for vdu_param in vdu_params:
if 'vdu_id' not in vdu_param:
raise sol_ex.SolValidationError(
detail="If you set vdu_params in additionalParams, you"
"must set vdu_id for each element.")
if vdu_param['vdu_id'] not in inst_vdu_ids:
raise sol_ex.SolValidationError(
detail="vdu_id '%s' does not exist." % vdu_param['vdu_id'])
def _check_vnfc_param(attr):
for key in ['cp_name', 'username', 'password']:
if key not in vdu_param[attr]:
raise sol_ex.SolValidationError(
detail=f"If you set {attr} in "
f"vdu_param, you must set"
f" 'cp_name', 'username' and"
f" 'password'")
if vim_type == 'ETSINFV.OPENSTACK_KEYSTONE.V_3' and new_script:
if 'new_vnfc_param' not in vdu_param:
raise sol_ex.SolValidationError(
detail="'new_vnfc_param' must exist in vdu_param")
_check_vnfc_param('new_vnfc_param')
if vim_type == 'ETSINFV.OPENSTACK_KEYSTONE.V_3' and old_script:
if 'old_vnfc_param' not in vdu_param:
raise sol_ex.SolValidationError(
detail="'old_vnfc_param' must exist in vdu_param")
_check_vnfc_param('old_vnfc_param')
@validator.schema(schema.ChangeCurrentVnfPkgRequest_V200, '2.0.0')
@coordinate.lock_vnf_instance('{id}')
def change_vnfpkg(self, request, id, body):
@ -408,24 +445,16 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
upgrade_type = additional_params.get('upgrade_type', '')
if upgrade_type != 'RollingUpdate':
raise sol_ex.NotSupportUpgradeType(upgrade_type=upgrade_type)
if additional_params.get('vdu_params'):
vdu_ids = [vdu.get('vdu_id') for vdu in
additional_params.get('vdu_params')]
if None in vdu_ids:
raise sol_ex.SolValidationError(
detail="If you set vdu_params in additionalParams, you"
"must set vduId for each element.")
for vdu in additional_params.get('vdu_params'):
for attr in ['old_vnfc_param', 'new_vnfc_param']:
if vdu.get(attr):
vdu_keys = vdu.get(attr).keys()
if set(vdu_keys).difference(set(
['cp_name', 'username', 'password'])):
raise sol_ex.SolValidationError(
detail=f"If you set {attr} in "
f"additionalParams, you must set"
f" 'cp_name', 'username' and"
f" 'password'")
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
vdu_params = additional_params.get('vdu_params')
if (vim_info.vimType == 'ETSINFV.OPENSTACK_KEYSTONE.V_3' and
vdu_params is None):
raise sol_ex.SolValidationError(
detail="'vdu_params' must exist in additionalParams")
if vdu_params:
self._check_vdu_params(inst, vdu_params, vim_info.vimType,
additional_params.get('lcm-operation-coordinate-new-vnf'),
additional_params.get('lcm-operation-coordinate-old-vnf'))
lcmocc = self._new_lcmocc(id, v2fields.LcmOperationType.CHANGE_VNFPKG,
body)
@ -461,7 +490,7 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
if 'BASIC' in auth.authType:
basic_req = auth_req.get('paramsBasic')
if basic_req is None:
msg = "ParmasBasic must be specified."
msg = "ParamsBasic must be specified."
raise sol_ex.InvalidSubscription(sol_detail=msg)
auth.paramsBasic = (
objects.SubscriptionAuthentication_ParamsBasic(

View File

@ -282,20 +282,15 @@ class Kubernetes(object):
self, req, inst, grant_req, grant, vnfd,
operation, namespace, new_deploy_reses):
coordinate_vnf = None
coordinate_vnf_class = None
if req.obj_attr_is_set('additionalParams'):
if operation == 'CHANGE_VNFPKG':
coordinate_vnf = req.additionalParams.get(
'lcm-operation-coordinate-new-vnf')
coordinate_vnf_class = req.additionalParams.get(
'lcm-operation-coordinate-new-vnf-class')
else:
coordinate_vnf = req.additionalParams.get(
'lcm-operation-coordinate-old-vnf')
coordinate_vnf_class = req.additionalParams.get(
'lcm-operation-coordinate-old-vnf-class')
if coordinate_vnf and coordinate_vnf_class:
if coordinate_vnf:
tmp_csar_dir = vnfd.make_tmp_csar_dir()
script_dict = {
"request": req.to_dict(),

View File

@ -134,20 +134,14 @@ class HeatClient(object):
raise sol_ex.StackOperationFailed
return body
def get_resource_info(self, nested_stack_id, resource_name):
path = f"stacks/{nested_stack_id}/resources/{resource_name}"
def get_resource_info(self, stack_id, resource_name):
path = f"stacks/{stack_id}/resources/{resource_name}"
resp, body = self.client.do_request(path, "GET",
expected_status=[200, 404])
if resp.status_code == 404:
return None
return body['resource']
def get_resource_list(self, stack_id):
path = f"stacks/{stack_id}/resources"
resp, body = self.client.do_request(path, "GET",
expected_status=[200, 404])
return body
def get_parameters(self, stack_name):
path = f"stacks/{stack_name}"
resp, body = self.client.do_request(path, "GET",
@ -211,34 +205,9 @@ def get_resource_stack_id(heat_res):
return "{}/{}".format(items[-2], items[-1])
def get_parent_nested_id(res):
for link in res.get('links', []):
if link['rel'] == 'nested':
items = link['href'].split('/')
return "{}/{}".format(items[-2], items[-1])
def get_parent_resource(heat_res, heat_reses):
parent = heat_res.get('parent_resource')
if parent:
for res in heat_reses:
if res['resource_name'] == parent:
return res
def get_group_stack_id(heat_reses, vdu_id):
parent_resources = [heat_res for heat_res in heat_reses
if heat_res.get('resource_name') == vdu_id]
if parent_resources:
parent_resource = parent_resources[0].get('parent_resource')
else:
raise sol_ex.VduIdNotFound(vdu_id=vdu_id)
group_resource_name = [heat_res for heat_res in
heat_reses if
heat_res.get('resource_name') ==
parent_resource][0].get('parent_resource')
group_stack_id = [heat_res for heat_res in
heat_reses if
heat_res.get('resource_name') ==
group_resource_name][0].get('physical_resource_id')
return group_stack_id

View File

@ -14,7 +14,6 @@
# under the License.
import copy
import json
import os
import pickle
@ -24,15 +23,12 @@ from dateutil import parser
import eventlet
from oslo_log import log as logging
from oslo_utils import uuidutils
import yaml
from tacker.sol_refactored.common import cinder_utils
from tacker.sol_refactored.common import config
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
from tacker.sol_refactored.infra_drivers.openstack import heat_utils
from tacker.sol_refactored.infra_drivers.openstack import userdata_default
from tacker.sol_refactored.nfvo import glance_utils
from tacker.sol_refactored import objects
from tacker.sol_refactored.objects.v2 import fields as v2fields
@ -90,12 +86,9 @@ class Openstack(object):
else:
heat_client.update_stack(stack_name, fields)
# get stack resource
heat_reses = heat_client.get_resources(stack_name)
# make instantiated_vnf_info
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
heat_reses)
heat_client)
def instantiate_rollback(self, req, inst, grant_req, grant, vnfd):
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
@ -157,12 +150,9 @@ class Openstack(object):
fields = self._update_nfv_dict(heat_client, stack_name, fields)
heat_client.update_stack(stack_name, fields)
# get stack resource
heat_reses = heat_client.get_resources(stack_name)
# make instantiated_vnf_info
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
heat_reses)
heat_client)
def scale_rollback(self, req, inst, grant_req, grant, vnfd):
# NOTE: rollback is supported for scale out only
@ -207,12 +197,9 @@ class Openstack(object):
fields = self._update_nfv_dict(heat_client, stack_name, fields)
heat_client.update_stack(stack_name, fields)
# get stack resource
heat_reses = heat_client.get_resources(stack_name)
# make instantiated_vnf_info
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
heat_reses)
heat_client)
def change_ext_conn_rollback(self, req, inst, grant_req, grant, vnfd):
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
@ -225,9 +212,8 @@ class Openstack(object):
# NOTE: it is necessary to re-create instantiatedVnfInfo because
# ports may be changed.
heat_reses = heat_client.get_resources(stack_name)
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
heat_reses)
heat_client)
def heal(self, req, inst, grant_req, grant, vnfd):
# make HOT
@ -289,267 +275,180 @@ class Openstack(object):
# update stack
heat_client.update_stack(stack_name, fields)
# get stack resource
heat_reses = heat_client.get_resources(stack_name)
# make instantiated_vnf_info
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
heat_client)
def change_vnfpkg(self, req, inst, grant_req, grant, vnfd):
# make HOT
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
LOG.debug("stack fields: %s", fields)
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
heat_client = heat_utils.HeatClient(vim_info)
if req.additionalParams['upgrade_type'] == 'RollingUpdate':
self._change_vnfpkg_rolling_update(req, inst, grant_req, grant,
vnfd, fields, heat_client, False)
else:
# not reach here
pass
# update stack
stack_name = heat_utils.get_stack_name(inst)
fields = self._update_nfv_dict(heat_client, stack_name, fields)
heat_client.update_stack(stack_name, fields)
# make instantiated_vnf_info
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
heat_reses)
heat_client)
def change_vnfpkg(self, req, inst, grant_req, grant, vnfd):
group_vdu_ids = []
if req.additionalParams.get('upgrade_type') == 'RollingUpdate':
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
heat_client = heat_utils.HeatClient(vim_info)
stack_name = heat_utils.get_stack_name(inst)
stack_id = heat_client.get_stack_resource(
stack_name)['stack']["id"]
vdu_infos = self._get_vdu_info(vnfd, grant, inst)
new_res_ids = {}
for vdu_param in req.additionalParams.get('vdu_params'):
vdu_id = vdu_param.get('vdu_id')
new_res_ids[vdu_id] = []
body = heat_client.get_resource_info(
f"{stack_name}/{stack_id}", vdu_id)
if uuidutils.is_uuid_like(
vdu_infos[vdu_id]['image']):
vdu_image_id_flag = True
else:
vdu_image_id_flag = False
# The previous processing is to obtain the VM information under
# the current stack according to vduId, excluding the resources
# under nested. When the status_code is 404, it means that
# there is no VM under the stack, and the VM is created by
# `OS::Heat::AutoScalingGroup` by default.
if body is None:
# handle VM under `OS::Heat::AutoScalingGroup`
# In this case, the VM does not support changing from
# image creation to volume creation, or changing from
# volume creation to image creation. Because it cannot
# change VDU.yaml under nested directory.
heat_reses = heat_client.get_resources(stack_name)
group_stack_id = heat_utils.get_group_stack_id(
heat_reses, vdu_id)
templates = heat_client.get_template(
group_stack_id)
reses = heat_client.get_resource_list(
group_stack_id)['resources']
def _change_vnfpkg_rolling_update(self, req, inst, grant_req, grant,
vnfd, fields, heat_client, is_rollback):
if not grant_req.obj_attr_is_set('removeResources'):
return
# update VM one by one
for res in reses:
templates['resources'][res.get('resource_name')][
'properties']['image'] = vdu_infos[
vdu_id].get('image')
templates['resources'][res.get('resource_name')][
'properties']['flavor'] = vdu_infos[
vdu_id].get('flavor')
fields = {
"stack_id": group_stack_id,
"template": templates
}
try:
heat_client.update_stack(
group_stack_id, fields)
except sol_ex.StackOperationFailed:
self._handle_exception(
res, new_res_ids, vdu_infos,
vdu_id, heat_client, req, inst, vnfd,
stack_name, get_res_flag=True)
self._get_new_res_info(
res.get('resource_name'),
new_res_ids[vdu_id],
heat_utils.get_parent_nested_id(res),
vdu_infos[vdu_id], vdu_id,
heat_client)
vnfc_res_ids = [res_def.resource.resourceId
for res_def in grant_req.removeResources
if res_def.type == 'COMPUTE']
vnfcs = [vnfc
for vnfc in inst.instantiatedVnfInfo.vnfcResourceInfo
if vnfc.computeResource.resourceId in vnfc_res_ids]
# execute coordinate_vnf_script
try:
self._execute_coordinate_vnf_script(
req, inst, grant_req, grant, vnfd,
heat_utils.get_parent_nested_id(res),
heat_client, vdu_param, vim_info,
vdu_image_id_flag)
except (sol_ex.SshIpNotFoundException,
sol_ex.CoordinateVNFExecutionFailed) as ex:
self._handle_exception(
res, new_res_ids, vdu_infos,
vdu_id, heat_client, req, inst, vnfd,
stack_name, ex=ex)
group_vdu_ids.append(vdu_id)
else:
# handle single VM
res = {
"resource_name": stack_name,
"physical_resource_id": stack_id,
}
new_template = vnfd.get_base_hot(
inst.instantiatedVnfInfo.flavourId)['template']
heat_parameter = self._update_vnf_template_and_parameter(
stack_id, vdu_infos, vdu_id, heat_client, new_template)
fields = {
"stack_id": stack_id,
"parameters": {"nfv": heat_parameter.get('nfv')},
"template": yaml.safe_dump(
heat_parameter.get('templates')),
}
try:
heat_client.update_stack(stack_id, fields, wait=True)
except sol_ex.StackOperationFailed:
self._handle_exception(
res, new_res_ids, vdu_infos,
vdu_id, heat_client, req, inst, vnfd,
stack_name, get_res_flag=True)
self._get_new_res_info(
stack_name,
new_res_ids[vdu_id],
f'{stack_name}/{stack_id}',
vdu_infos[vdu_id], vdu_id,
heat_client)
templates = {}
# execute coordinate_vnf_script
try:
self._execute_coordinate_vnf_script(
req, inst, grant_req, grant, vnfd,
f"{stack_name}/{stack_id}",
heat_client, vdu_param, vim_info,
vdu_image_id_flag,
operation='change_vnfpkg')
except (sol_ex.SshIpNotFoundException,
sol_ex.CoordinateVNFExecutionFailed) as ex:
self._handle_exception(
res, new_res_ids, vdu_infos,
vdu_id, heat_client, req, inst, vnfd,
stack_name, ex=ex)
def _get_template(parent_stack_id):
if parent_stack_id not in templates:
templates[parent_stack_id] = heat_client.get_template(
parent_stack_id)
return templates[parent_stack_id]
# Because external parameters are not updated after the image
# of the nested-VM is updated, scale will create the original
# VM again, so the overall update needs to be performed
# at the end.
fields = self._get_entire_stack_fields(
heat_client, stack_id, group_vdu_ids, vdu_infos)
try:
heat_client.update_stack(stack_id, fields)
except sol_ex.StackOperationFailed:
self._handle_exception(
res, new_res_ids, vdu_infos,
vdu_id, heat_client, req, inst, vnfd,
stack_name)
self._update_vnf_instantiated_info(
req, new_res_ids, inst, vnfd,
heat_client, stack_name)
inst.vnfdId = req.vnfdId
vdu_dict = fields['parameters']['nfv']['VDU']
stack_name = heat_utils.get_stack_name(inst)
for vnfc in vnfcs:
if 'parent_stack_id' in vnfc.metadata:
# it means the VM is created by OS::Heat::AutoScalingGroup
parent_stack_id = vnfc.metadata['parent_stack_id']
template = _get_template(parent_stack_id)
parent_name = vnfc.metadata['parent_resource_name']
props = template['resources'][parent_name]['properties']
# replace 'flavor' and 'image-{vdu name}' in properties
props['flavor'] = vdu_dict[vnfc.vduId]['computeFlavourId']
for key in props.keys():
if key.startswith('image-'):
vdu_name = key.replace('image-', '')
props[key] = vdu_dict[vdu_name]['vcImageId']
vdu_fields = {
"stack_id": parent_stack_id,
"template": template
}
LOG.debug("stack fields: %s", vdu_fields)
heat_client.update_stack(parent_stack_id, vdu_fields)
else:
# handle single VM
# pickup 'vcImageId' and 'computeFlavourId'
params = {}
if vdu_dict[vnfc.vduId].get('computeFlavourId'):
params[vnfc.vduId] = {'computeFlavourId':
vdu_dict[vnfc.vduId]['computeFlavourId']}
vdu_names = [vnfc.vduId]
if vnfc.obj_attr_is_set('storageResourceIds'):
storage_infos = (
inst.instantiatedVnfInfo.virtualStorageResourceInfo)
vdu_names += [
storage_info.virtualStorageDescId
for storage_info in storage_infos
if storage_info.id in vnfc.storageResourceIds
]
for vdu_name in vdu_names:
image = vdu_dict.get(vdu_name, {}).get('vcImageId')
if image:
params.setdefault(vdu_name, {})
params[vdu_name]['vcImageId'] = image
update_nfv_dict = {'nfv': {'VDU': params}}
update_fields = {'parameters': update_nfv_dict}
update_fields = self._update_nfv_dict(heat_client, stack_name,
update_fields)
LOG.debug("stack fields: %s", update_fields)
heat_client.update_stack(stack_name, update_fields)
# execute coordinate_vnf_script
self._execute_coordinate_vnf_script(req, vnfd, vnfc, heat_client,
is_rollback)
def _get_ssh_ip(self, stack_id, cp_name, heat_client):
# NOTE: It is assumed that if the user want to use floating_ip,
# he must specify the resource name of 'OS::Neutron::FloatingIP'
# resource as cp_name (ex. VDU1_FloatingIp).
cp_info = heat_client.get_resource_info(stack_id, cp_name)
if cp_info.get('attributes', {}).get('floating_ip_address'):
return cp_info['attributes']['floating_ip_address']
elif cp_info.get('attributes', {}).get('fixed_ips'):
return cp_info['attributes']['fixed_ips'][0].get('ip_address')
def _execute_coordinate_vnf_script(self, req, vnfd, vnfc, heat_client,
is_rollback):
if is_rollback:
script = req.additionalParams.get(
'lcm-operation-coordinate-old-vnf')
else:
# TODO(YiFeng): Blue-Green type will be supported in Zed release.
raise sol_ex.NotSupportUpgradeType(
upgrade_type=req.additionalParams.get('upgrade_type'))
script = req.additionalParams.get(
'lcm-operation-coordinate-new-vnf')
if not script:
return
def change_vnfpkg_rollback(
self, req, inst, grant_req, grant, vnfd, lcmocc):
group_vdu_ids = []
if req.additionalParams.get('upgrade_type') == 'RollingUpdate':
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
heat_client = heat_utils.HeatClient(vim_info)
stack_name = heat_utils.get_stack_name(inst)
stack_id = heat_client.get_stack_resource(
stack_name)['stack']["id"]
vdu_infos = self._get_vdu_info(vnfd, grant, inst)
new_res_ids = {}
templates = {}
affected_vnfcs = [affected_vnfc for affected_vnfc in
lcmocc.resourceChanges.affectedVnfcs if
affected_vnfc.changeType in {'ADDED', 'MODIFIED'}]
for lcmocc_vnf in affected_vnfcs:
if new_res_ids.get(lcmocc_vnf.vduId) is None:
new_res_ids[lcmocc_vnf.vduId] = []
image = vdu_infos[lcmocc_vnf.vduId]['image']
if uuidutils.is_uuid_like(image):
vdu_image_id_flag = True
else:
vdu_image_id_flag = False
if lcmocc_vnf.metadata.get(
'current_vnfd_id') is not inst.vnfdId:
parent_resource_name = lcmocc_vnf.metadata.get(
'parent_resource_name')
if parent_resource_name:
vdu_stack_id = lcmocc_vnf.metadata.get(
'stack_id')
if not templates.get(lcmocc_vnf.vduId):
templates[lcmocc_vnf.vduId] = {}
heat_reses = heat_client.get_resources(stack_name)
group_stack_id = heat_utils.get_group_stack_id(
heat_reses, lcmocc_vnf.vduId)
template = heat_client.get_template(
group_stack_id)
templates[lcmocc_vnf.vduId] = template
template['resources'][parent_resource_name][
'properties']['image'] = vdu_infos[
lcmocc_vnf.vduId].get('image')
template['resources'][parent_resource_name][
'properties']['flavor'] = vdu_infos[
lcmocc_vnf.vduId].get('flavor')
fields = {
"stack_id": group_stack_id,
"template": template
}
heat_client.update_stack(
group_stack_id, fields, wait=True)
self._get_new_res_info(
parent_resource_name,
new_res_ids[lcmocc_vnf.vduId], vdu_stack_id,
vdu_infos[lcmocc_vnf.vduId],
lcmocc_vnf.vduId, heat_client)
vdu_param = [vdu_param for vdu_param in
req.get('additionalParams').get(
'vdu_params')
if vdu_param.get('vdu_id')
== lcmocc_vnf.vduId][0]
self._execute_coordinate_vnf_script(
req, inst, grant_req, grant, vnfd,
vdu_stack_id,
heat_client, vdu_param, vim_info,
vdu_image_id_flag,
operation="change_vnfpkg_rollback")
group_vdu_ids.append(lcmocc_vnf.vduId)
else:
vdu_stack_id = lcmocc_vnf.metadata.get('stack_id')
new_template = vnfd.get_base_hot(
inst.instantiatedVnfInfo.flavourId)['template']
heat_parameter = (
self._update_vnf_template_and_parameter(
stack_id, vdu_infos,
lcmocc_vnf.vduId, heat_client, new_template))
fields = {
"stack_id": stack_id,
"parameters": {"nfv": heat_parameter.get('nfv')},
"template": yaml.safe_dump(
heat_parameter.get('templates')),
}
heat_client.update_stack(stack_id,
fields, wait=True)
self._get_new_res_info(
stack_name, new_res_ids[lcmocc_vnf.vduId],
vdu_stack_id, vdu_infos[lcmocc_vnf.vduId],
lcmocc_vnf.vduId, heat_client)
vdu_param = [vdu_param for vdu_param in
req.get('additionalParams').get(
'vdu_params')
if vdu_param.get('vdu_id')
== lcmocc_vnf.vduId][0]
self._execute_coordinate_vnf_script(
req, inst, grant_req, grant, vnfd, vdu_stack_id,
heat_client, vdu_param, vim_info,
vdu_image_id_flag,
operation="change_vnfpkg_rollback")
fields = self._get_entire_stack_fields(
heat_client, stack_id, group_vdu_ids, vdu_infos)
heat_client.update_stack(stack_id, fields, wait=True)
self._update_vnf_instantiated_info(
req, new_res_ids, inst, vnfd,
heat_client, stack_name, operation='change_vnfpkg_rollback')
for vdu_param in req.additionalParams['vdu_params']:
if vnfc.vduId == vdu_param['vdu_id']:
break
if is_rollback:
vnfc_param = vdu_param['old_vnfc_param']
else:
# TODO(YiFeng): Blue-Green type will be supported in Zed release.
raise sol_ex.NotSupportUpgradeType(
upgrade_type=req.additionalParams.get('upgrade_type'))
vnfc_param = vdu_param['new_vnfc_param']
ssh_ip = self._get_ssh_ip(vnfc.metadata['stack_id'],
vnfc_param['cp_name'], heat_client)
if not ssh_ip:
raise sol_ex.SshIpNotFoundException()
vnfc_param['ssh_ip'] = ssh_ip
vnfc_param['is_rollback'] = is_rollback
tmp_csar_dir = vnfd.make_tmp_csar_dir()
script_path = os.path.join(tmp_csar_dir, script)
out = subprocess.run(["python3", script_path],
input=pickle.dumps(vnfc_param),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
vnfd.remove_tmp_csar_dir(tmp_csar_dir)
if out.returncode != 0:
LOG.error(out)
raise sol_ex.CoordinateVNFExecutionFailed()
def change_vnfpkg_rollback(self, req, inst, grant_req, grant, vnfd,
lcmocc):
fields = userdata_default.DefaultUserData.change_vnfpkg_rollback(
req, inst, grant_req, grant, vnfd.csar_dir)
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
heat_client = heat_utils.HeatClient(vim_info)
if req.additionalParams['upgrade_type'] == 'RollingUpdate':
self._change_vnfpkg_rolling_update(req, inst, grant_req, grant,
vnfd, fields, heat_client, True)
else:
# not reach here
pass
# stack update
stack_name = heat_utils.get_stack_name(inst)
fields = self._update_nfv_dict(heat_client, stack_name, fields)
heat_client.update_stack(stack_name, fields)
# NOTE: it is necessary to re-create instantiatedVnfInfo because
# some resources may be changed.
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
heat_client)
def _make_hot(self, req, inst, grant_req, grant, vnfd):
if grant_req.operation == v2fields.LcmOperationType.INSTANTIATE:
@ -631,60 +530,6 @@ class Openstack(object):
obj.maxAddress = range_data.maxAddress
return obj
def _execute_coordinate_vnf_script(
self, req, inst, grant_req, grant,
vnfd, nested_stack_id, heat_client, vdu_param,
vim_info, vdu_image_id_flag, operation='change_vnfpkg'):
coordinate_vnf = None
coordinate_vnf_class = None
if req.obj_attr_is_set('additionalParams'):
if operation == 'change_vnfpkg':
coordinate_vnf = req.additionalParams.get(
'lcm-operation-coordinate-new-vnf')
coordinate_vnf_class = req.additionalParams.get(
'lcm-operation-coordinate-new-vnf-class')
else:
coordinate_vnf = req.additionalParams.get(
'lcm-operation-coordinate-old-vnf')
coordinate_vnf_class = req.additionalParams.get(
'lcm-operation-coordinate-old-vnf-class')
if coordinate_vnf and coordinate_vnf_class:
if operation == 'change_vnfpkg':
ssh_ip = self._get_ssh_ip(nested_stack_id,
vdu_param.get('new_vnfc_param'),
heat_client)
else:
ssh_ip = self._get_ssh_ip(nested_stack_id,
vdu_param.get('old_vnfc_param'),
heat_client)
if not ssh_ip:
raise sol_ex.SshIpNotFoundException
image, flavor = self._get_current_vdu_image_and_flavor(
nested_stack_id, vdu_param.get('vdu_id'),
heat_client, vim_info, vdu_image_id_flag)
tmp_csar_dir = vnfd.make_tmp_csar_dir()
script_dict = {
"request": req.to_dict(),
"vnf_instance": inst.to_dict(),
"grant_request": grant_req.to_dict(),
"grant_response": grant.to_dict(),
"tmp_csar_dir": tmp_csar_dir,
"vdu_info": {
"ssh_ip": ssh_ip,
"new_image": image,
"new_flavor": flavor,
"vdu_param": vdu_param
}
}
script_path = os.path.join(tmp_csar_dir, coordinate_vnf)
out = subprocess.run(["python3", script_path],
input=pickle.dumps(script_dict),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if out.returncode != 0:
LOG.error(out)
raise sol_ex.CoordinateVNFExecutionFailed
def _proto_data_to_info(self, proto_data):
# make CpProtocolInfo (5.5.3.9b) from CpProtocolData (4.4.1.10b)
proto_info = objects.CpProtocolInfoV2(
@ -776,285 +621,6 @@ class Openstack(object):
return ext_vl
def _get_vdu_info(self, vnfd, grant, inst):
flavour_id = inst.instantiatedVnfInfo.flavourId
vdu_nodes = vnfd.get_vdu_nodes(flavour_id)
storage_nodes = vnfd.get_storage_nodes(flavour_id)
vdu_info_dict = {}
for name, node in vdu_nodes.items():
flavor = self._get_param_flavor(vnfd, name, flavour_id, grant)
image = self._get_param_image(vnfd, name, flavour_id, grant)
vdu_storage_names = vnfd.get_vdu_storages(node)
volume_name = ''
volume_size = ''
for vdu_storage_name in vdu_storage_names:
if storage_nodes[vdu_storage_name].get(
'properties').get('sw_image_data'):
image = self._get_param_image(
vnfd, vdu_storage_name, flavour_id, grant)
volume_name = vdu_storage_name
volume_size = storage_nodes[vdu_storage_name].get(
'properties', {}).get(
'virtual_block_storage_data', '').get(
'size_of_storage', ''
)
volume_size = volume_size.rstrip(' GB')
if not volume_size.isdigit():
raise sol_ex.InvalidVolumeSize
break
vdu_info_dict[name] = {
"flavor": flavor,
"image": image
}
if volume_name:
vdu_info_dict[name]['volume_info'] = {
"volume_name": volume_name,
"volume_size": volume_size
}
return vdu_info_dict
def _get_param_flavor(self, vnfd, vdu_name, flavour_id, grant):
# try to get from grant
if grant.obj_attr_is_set('vimAssets'):
assets = grant.vimAssets
if assets.obj_attr_is_set('computeResourceFlavours'):
flavours = assets.computeResourceFlavours
for flavour in flavours:
if flavour.vnfdVirtualComputeDescId == vdu_name:
return flavour.vimFlavourId
# if specified in VNFD, use it
# NOTE: if not found. parameter is set to None.
# may be error when stack create
return vnfd.get_compute_flavor(flavour_id, vdu_name)
def _get_param_image(self, vnfd, vdu_name, flavour_id, grant):
# try to get from grant
if grant.obj_attr_is_set('vimAssets'):
assets = grant.vimAssets
if assets.obj_attr_is_set('softwareImages'):
images = assets.softwareImages
for image in images:
if image.vnfdSoftwareImageId == vdu_name:
return image.vimSoftwareImageId
# if specified in VNFD, use it
# NOTE: if not found. parameter is set to None.
# may be error when stack create
sw_images = vnfd.get_sw_image(flavour_id)
for name, image in sw_images.items():
if name == vdu_name:
return image
return None
def _get_current_vdu_image_and_flavor(
self, nested_stack_id, resource_name,
heat_client, vim_info, vdu_image_id_flag):
vdu_info = heat_client.get_resource_info(
nested_stack_id, resource_name)
if vdu_info.get('attributes').get('image'):
image = vdu_info.get('attributes').get('image').get('id')
if not vdu_image_id_flag:
glance_client = glance_utils.GlanceClient(vim_info)
image = glance_client.get_image(image).name
else:
volume_ids = [volume.get('id') for volume in vdu_info.get(
'attributes').get('os-extended-volumes:volumes_attached')]
cinder_client = cinder_utils.CinderClient(vim_info)
if vdu_image_id_flag:
image = [cinder_client.get_volume(
volume_id).volume_image_metadata.get('image_id')
for volume_id in volume_ids if cinder_client.get_volume(
volume_id).volume_image_metadata][0]
else:
image = [cinder_client.get_volume(
volume_id).volume_image_metadata.get('image_name')
for volume_id in volume_ids if cinder_client.get_volume(
volume_id).volume_image_metadata][0]
flavor_name = vdu_info.get('attributes').get('flavor').get(
'original_name')
return image, flavor_name
def _get_new_res_info(self, parent_resource_name, vdu_infos,
stack_id, vnfd_info, vdu_id, heat_client):
new_res_infos = {
"stack_id": stack_id,
"parent_resource_name": parent_resource_name
}
nested_reses = heat_client.get_resource_list(
stack_id.split('/')[1])['resources']
for nested_res in nested_reses:
if nested_res.get(
'resource_type') == 'OS::Nova::Server' and nested_res.get(
'resource_name') == vdu_id:
new_res_infos["vdu_id"] = nested_res.get(
'physical_resource_id')
elif nested_res.get(
'resource_type'
) == 'OS::Cinder::Volume' and nested_res.get(
'resource_name') == vnfd_info.get(
'volume_info').get('volume_name'):
new_res_infos['volume_info'] = {
"volume_name": nested_res.get('resource_name'),
"volume_id": nested_res.get('physical_resource_id')
}
vdu_infos.append(new_res_infos)
def _get_ssh_ip(self, nested_stack_id, vnfc_param, heat_client):
cp_name = vnfc_param.get('cp_name')
cp_info = heat_client.get_resource_info(nested_stack_id, cp_name)
if cp_info.get('attributes').get('floating_ip_address'):
ssh_ip = cp_info.get('attributes').get('floating_ip_address')
else:
ssh_ip = cp_info.get('attributes').get('fixed_ips')[0].get(
'ip_address')
return ssh_ip
def _update_vnf_instantiated_info(
self, req, new_res_ids, inst, vnfd, heat_client, stack_name,
operation='change_vnfpkg'):
instantiated_vnf_info = inst.instantiatedVnfInfo
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
heat_reses = heat_client.get_resources(stack_name)
storage_reses = self._get_checked_reses(
vnfd.get_storage_nodes(inst.instantiatedVnfInfo.flavourId),
heat_utils.get_storage_reses(heat_reses))
# handle storage_info
def _res_to_handle(res):
return objects.ResourceHandle(
resourceId=res['physical_resource_id'],
vimLevelResourceType=res['resource_type'],
vimConnectionId=vim_info.vimId)
storage_infos = [
objects.VirtualStorageResourceInfoV2(
id=res_id,
virtualStorageDescId=res['resource_name'],
storageResource=_res_to_handle(res)
)
for res_id, res in storage_reses.items()
]
# handle vnfc_resource_info
for vnfc_res in instantiated_vnf_info.vnfcResourceInfo:
if new_res_ids.get(vnfc_res.vduId):
new_res_info = [vnfc_info for vnfc_info
in new_res_ids.get(vnfc_res.vduId)
if vnfc_info['stack_id']
== vnfc_res.metadata['stack_id']]
if not new_res_info:
continue
new_res_info = new_res_info[0]
current_vnfc = []
if instantiated_vnf_info.obj_attr_is_set('vnfcInfo'):
current_vnfc = [
vnfc for vnfc in instantiated_vnf_info.vnfcInfo
if vnfc.id == _make_combination_id(
vnfc_res.vduId, vnfc_res.id)][0]
vnfc_res.id = new_res_info.get('vdu_id')
vnfc_res.computeResource.resourceId = new_res_info.get(
'vdu_id')
if current_vnfc:
current_vnfc.id = _make_combination_id(
vnfc_res.vduId, vnfc_res.id)
current_vnfc.vnfcResourceInfoId = vnfc_res.id
if operation == 'change_vnfpkg':
vnfc_res.metadata['current_vnfd_id'] = req.vnfdId
else:
vnfc_res.metadata['current_vnfd_id'] = inst.vnfdId
storage_ids = [
storage_id for storage_id, storage_res in
storage_reses.items()
if (vnfc_res.vduId in storage_res.get(
'required_by', []))]
if vnfc_res.metadata.get('parent_resource_name') != stack_name:
storage_ids = [
storage_id for storage_id, storage_res in
storage_reses.items()
if (vnfc_res.vduId in storage_res.get(
'required_by', []) and vnfc_res.metadata.get(
'parent_resource_name') == storage_res.get(
'parent_resource'))]
if storage_ids:
vnfc_res.storageResourceIds = storage_ids
else:
if vnfc_res.obj_attr_is_set('storageResourceIds'):
del vnfc_res.storageResourceIds
if storage_infos:
instantiated_vnf_info.virtualStorageResourceInfo = storage_infos
else:
if instantiated_vnf_info.obj_attr_is_set(
'virtualStorageResourceInfo'):
del instantiated_vnf_info.virtualStorageResourceInfo
def _update_vnf_template_and_parameter(
self, stack_id, vdu_infos, vdu_id, heat_client, new_template):
vdu_info = vdu_infos[vdu_id]
volume_info = vdu_info.get('volume_info', {})
base_templates = heat_client.get_template(stack_id)
old_parameter = heat_client.get_parameters(stack_id)['nfv']
new_parameter = json.loads(copy.deepcopy(old_parameter))
# old VM(created by volume) -> new VM(created by volume)
if volume_info and 'image' not in base_templates[
'resources'][vdu_id]['properties']:
new_parameter['VDU'][vdu_id]['computeFlavourId'] = vdu_info.get(
'flavor')
new_parameter['VDU'][volume_info.get('volume_name')][
'vcImageId'] = vdu_info.get('image')
# old VM(created by volume) -> new VM(created by image)
elif vdu_info.get(
'volume_info') is None and 'image' not in base_templates[
'resources'][vdu_id]['properties']:
# delete vdu's volume definition info
if len(base_templates['resources'][vdu_id]['properties'][
'block_device_mapping_v2']) > 1:
old_volumes = [name for name, value in
base_templates['resources'].items()
if value['type'] == 'OS::Cinder::Volume'
and value['properties']['image']]
for volume in base_templates['resources'][
vdu_id]['properties']['block_device_mapping_v2']:
if volume['volume_id']['get_resource'] in old_volumes:
target_volume_name = volume['volume_id'][
'get_resource']
else:
target_volume_name = base_templates['resources'][
vdu_id]['properties']['block_device_mapping_v2'][0][
'volume_id']['get_resource']
del new_parameter['VDU'][target_volume_name]
new_parameter['VDU'][vdu_id]['computeFlavourId'] = vdu_info.get(
'flavor')
new_parameter['VDU'][vdu_id]['vcImageId'] = vdu_info.get('image')
# old VM(created by image) -> new VM(created by volume)
elif volume_info and 'image' in base_templates[
'resources'][vdu_id]['properties']:
del new_parameter['VDU'][vdu_id]['vcImageId']
new_parameter['VDU'][vdu_id]['computeFlavourId'] = vdu_info.get(
'flavor')
new_parameter['VDU'][volume_info.get('volume_name')] = {
"vcImageId": vdu_infos[vdu_id].get('image')
}
# old VM(created by image) -> new VM(created by image)
else:
new_parameter['VDU'][vdu_id]['computeFlavourId'] = vdu_info.get(
'flavor')
new_parameter['VDU'][vdu_id]['vcImageId'] = vdu_info.get('image')
heat_parameter = {
"templates": new_template,
"nfv": new_parameter
}
return heat_parameter
def _make_ext_vl_info_from_req(self, req, grant, ext_cp_infos):
# make extVirtualLinkInfo
req_ext_vls = []
@ -1322,8 +888,43 @@ class Openstack(object):
return metadata
def _update_vnfc_metadata(self, vnfc_res_infos, storage_infos,
heat_client, nfv_dict):
for vnfc_res_info in vnfc_res_infos:
metadata = vnfc_res_info.metadata
if 'parent_stack_id' in metadata:
# VDU defined by AutoScalingGroup
template = heat_client.get_template(
metadata['parent_stack_id'])
properties = (template['resources']
[metadata['parent_resource_name']]
['properties'])
metadata['flavor'] = properties['flavor']
for k, v in properties.items():
if k.startswith('image-'):
metadata[k] = v
else:
properties = nfv_dict['VDU'][vnfc_res_info.vduId]
metadata['flavor'] = properties['computeFlavourId']
vdu_names = [vnfc_res_info.vduId]
if vnfc_res_info.obj_attr_is_set('storageResourceIds'):
vdu_names += [
storage_info.virtualStorageDescId
for storage_info in storage_infos
if storage_info.id in vnfc_res_info.storageResourceIds
]
for vdu_name in vdu_names:
image = nfv_dict['VDU'].get(vdu_name, {}).get('vcImageId')
if image:
metadata[f'image-{vdu_name}'] = image
def _make_instantiated_vnf_info(self, req, inst, grant_req, grant, vnfd,
heat_reses):
heat_client):
# get heat resources
stack_name = heat_utils.get_stack_name(inst)
heat_reses = heat_client.get_resources(stack_name)
nfv_dict = json.loads(heat_client.get_parameters(stack_name)['nfv'])
op = grant_req.operation
if op == v2fields.LcmOperationType.INSTANTIATE:
flavour_id = req.flavourId
@ -1395,6 +996,9 @@ class Openstack(object):
if cp_infos:
vnfc_res_info.vnfcCpInfo = cp_infos
self._update_vnfc_metadata(vnfc_res_infos, storage_infos,
heat_client, nfv_dict)
vnf_vl_res_infos = [
objects.VnfVirtualLinkResourceInfoV2(
id=res_id,
@ -1539,47 +1143,3 @@ class Openstack(object):
inst_vnf_info.vnfcInfo = vnfc_infos
inst.instantiatedVnfInfo = inst_vnf_info
def _handle_exception(
self, res, new_res_ids, vdu_infos,
vdu_id, heat_client, req, inst, vnfd,
stack_name, ex=None, get_res_flag=False):
if get_res_flag:
if len(res.keys()) == 2:
par_stack_id = '{}/{}'.format(
res.get('resource_name'),
res.get('physical_resource_id'))
else:
par_stack_id = heat_utils.get_parent_nested_id(res)
self._get_new_res_info(
res.get('resource_name'),
new_res_ids[vdu_id],
par_stack_id,
vdu_infos[vdu_id], vdu_id,
heat_client)
self._update_vnf_instantiated_info(
req, new_res_ids, inst,
vnfd, heat_client, stack_name)
if ex:
raise ex
raise sol_ex.StackOperationFailed
def _get_entire_stack_fields(self, heat_client, stack_id,
group_vdu_ids, vdu_infos):
parameter = json.loads(heat_client.get_parameters(stack_id)['nfv'])
for group_vdu_id in group_vdu_ids:
if not parameter['VDU'][group_vdu_id].get('vcImageId'):
volume_info = vdu_infos[
group_vdu_id].get('volume_info')
parameter['VDU'][volume_info.get('volume_name')][
'vcImageId'] = vdu_infos[group_vdu_id].get(
'image')
else:
parameter['VDU'][group_vdu_id][
'vcImageId'] = vdu_infos[group_vdu_id].get(
'image')
fields = {
"stack_id": stack_id,
"parameters": {"nfv": parameter}
}
return fields

View File

@ -249,3 +249,75 @@ class DefaultUserData(userdata_utils.AbstractUserData):
fields = {'parameters': {'nfv': {}}}
return fields
@staticmethod
def change_vnfpkg(req, inst, grant_req, grant, tmp_csar_dir):
vnfd = common_script_utils.get_vnfd(grant_req['dstVnfdId'],
tmp_csar_dir)
flavour_id = inst['instantiatedVnfInfo']['flavourId']
hot_dict = vnfd.get_base_hot(flavour_id)
top_hot = hot_dict['template']
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
vdus = nfv_dict.get('VDU', {})
new_vdus = {}
for vdu_name, vdu_value in vdus.items():
if 'computeFlavourId' in vdu_value:
flavor = common_script_utils.get_param_flavor(
vdu_name, flavour_id, vnfd, grant)
new_vdus.setdefault(vdu_name, {})
new_vdus[vdu_name]['computeFlavourId'] = flavor
if 'vcImageId' in vdu_value:
image = common_script_utils.get_param_image(
vdu_name, flavour_id, vnfd, grant)
new_vdus.setdefault(vdu_name, {})
new_vdus[vdu_name]['vcImageId'] = image
fields = {
'parameters': {'nfv': {'VDU': new_vdus}}
}
return fields
@staticmethod
def change_vnfpkg_rollback(req, inst, grant_req, grant, tmp_csar_dir):
images = {}
flavors = {}
for vnfc in inst.get('instantiatedVnfInfo', {}).get(
'vnfcResourceInfo', []):
vdu_name = vnfc['vduId']
if vdu_name in flavors:
continue
for key, value in vnfc['metadata'].items():
if key == 'flavor':
flavors[vdu_name] = value
elif key.startswith('image-'):
image_vdu = key.replace('image-', '')
images[image_vdu] = value
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']
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
vdus = nfv_dict.get('VDU', {})
new_vdus = {}
for vdu_name, vdu_value in vdus.items():
if 'computeFlavourId' in vdu_value:
new_vdus.setdefault(vdu_name, {})
new_vdus[vdu_name]['computeFlavourId'] = flavors.get(vdu_name)
if 'vcImageId' in vdu_value:
new_vdus.setdefault(vdu_name, {})
new_vdus[vdu_name]['vcImageId'] = images.get(vdu_name)
fields = {
'parameters': {'nfv': {'VDU': new_vdus}}
}
return fields

View File

@ -43,7 +43,7 @@ LOG = logging.getLogger(__name__)
# NOTE:
# It is NFVO implementation used when an external NFVO is not used.
# It implements only functions necessary for vnflcm v2.
# It uses original tacker vnfpkgm v1 for vnf package managemnet
# It uses original tacker vnfpkgm v1 for vnf package management
# and adds grant functions.
@ -138,13 +138,49 @@ class LocalNfvo(object):
def _get_vim_info(self, context, grant_req):
lcmocc = lcmocc_utils.get_lcmocc(context, grant_req.vnfLcmOpOccId)
inst_req = lcmocc.operationParams
if inst_req.obj_attr_is_set('vimConnectionInfo'):
return inst_utils.select_vim_info(inst_req.vimConnectionInfo)
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:
# should be found
inst = inst_utils.get_inst(context, grant_req.vnfInstanceId)
return inst_utils.select_vim_info(inst.vimConnectionInfo)
# 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):
vim_sw_images = []
for res_id, sw_data in sw_image_data.items():
if '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)
try:
image = self._glance_create_image(vim_info, vnfd, sw_data,
grant_req.vnfInstanceId)
except Exception:
msg = "glance image create failed"
LOG.exception(msg)
raise sol_ex.LocalNfvoGrantFailed(sol_detail=msg)
else:
# there is no artifact. suppose image already created.
image = sw_data['name']
vim_sw_image = objects.VimSoftwareImageV1(
vnfdSoftwareImageId=res_id,
vimSoftwareImageId=image)
vim_sw_images.append(vim_sw_image)
if vim_sw_images:
grant_res.vimAssets = objects.GrantV1_VimAssets(
softwareImages=vim_sw_images
)
def instantiate_grant(self, context, grant_req, grant_res):
# handle ZoneInfo
zone_list = config.CONF.v2_nfvo.test_grant_zone_list
@ -178,83 +214,26 @@ class LocalNfvo(object):
# 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_sw_images = []
for res_id, sw_data in sw_image_data.items():
if 'file' in sw_data:
# if artifact is specified, create glance image.
# it may fail. catch exception and raise 403(not granted)
# if error occur.
# get vim_info to access glance
vim_info = self._get_vim_info(context, grant_req)
if vim_info is None:
msg = "No vimConnectionInfo to create glance image"
raise sol_ex.LocalNfvoGrantFailed(sol_detail=msg)
try:
image = self._glance_create_image(vim_info, vnfd, sw_data,
grant_req.vnfInstanceId)
except Exception:
msg = "glance image create failed"
LOG.exception(msg)
raise sol_ex.LocalNfvoGrantFailed(sol_detail=msg)
else:
# there is no artifact. suppose image already created.
image = sw_data['name']
vim_sw_image = objects.VimSoftwareImageV1(
vnfdSoftwareImageId=res_id,
vimSoftwareImageId=image)
vim_sw_images.append(vim_sw_image)
if vim_sw_images:
grant_res.vimAssets = objects.GrantV1_VimAssets(
softwareImages=vim_sw_images
)
vim_info = self._get_vim_info(context, grant_req)
self._handle_vim_assets(grant_req, grant_res, vnfd,
sw_image_data, vim_info)
def change_vnfpkg_grant(self, context, grant_req, grant_res):
attr_list = ['updateResources', 'addResources', 'removeResources']
for attr in attr_list:
if grant_req.obj_attr_is_set(attr):
res_list = []
for res_def in grant_req[attr]:
g_info = objects.GrantInfoV1(res_def.id)
res_list.append(g_info)
grant_res[attr] = res_list
vnfd = self.get_vnfd(context, grant_req.vnfdId)
sw_image_data = vnfd.get_sw_image_data(grant_req.flavourId)
target_vdu_ids = [res['resourceTemplateId'] for
res in grant_req['updateResources']]
vdu_nodes = {key: value for key, value in vnfd.get_vdu_nodes(
grant_req.flavourId).items() if key in target_vdu_ids}
target_storage_nodes = []
for key, value in vdu_nodes.items():
target_storage_nodes.extend(vnfd.get_vdu_storages(value))
if not grant_req.obj_attr_is_set('addResources'):
return
vim_sw_images = []
for res_id, sw_data in sw_image_data.items():
if 'file' in sw_data and (res_id in target_storage_nodes or
res_id in target_vdu_ids):
vim_info = self._get_vim_info(context, grant_req)
if vim_info is None:
msg = "No VimConnectionInfo to create glance image"
LOG.exception(msg)
raise sol_ex.LocalNfvoGrantFailed(sol_detail=msg)
try:
image = self._glance_create_image(
vim_info, vnfd, sw_data, grant_req.vnfInstanceId)
except Exception:
msg = "glance image create failed"
LOG.exception(msg)
raise sol_ex.LocalNfvoGrantFailed(sol_detail=msg)
else:
image = sw_data['name']
vim_sw_image = objects.VimSoftwareImageV1(
vnfdSoftwareImageId=res_id,
vimSoftwareImageId=image)
vim_sw_images.append(vim_sw_image)
if vim_sw_images:
grant_res.vimAssets = objects.GrantV1_VimAssets(
softwareImages=vim_sw_images
)
# 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)
def grant(self, context, grant_req):
grant_res = objects.GrantV1(
@ -263,11 +242,9 @@ class LocalNfvo(object):
vnfLcmOpOccId=grant_req.vnfLcmOpOccId
)
# NOTE: considered instantiate only at the moment.
# terminate is granted with no grant_res constructed.
# NOTE: considered instantiate and change_vnfpkg only at the moment.
if grant_req.operation == v2_fields.LcmOperationType.INSTANTIATE:
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)

View File

@ -205,10 +205,8 @@ def change_vnfpkg_all_params(vnfd_id):
"upgrade_type": "RollingUpdate",
"lcm-operation-coordinate-old-vnf":
"Scripts/coordinate_old_vnf.py",
"lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf",
"lcm-operation-coordinate-new-vnf":
"Scripts/coordinate_new_vnf.py",
"lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf",
"lcm-kubernetes-def-files": [
"Files/new_kubernetes/new_deployment.yaml"],
"vdu_params": [{
@ -243,10 +241,8 @@ def change_vnfpkg_min(vnfd_id):
"upgrade_type": "RollingUpdate",
"lcm-operation-coordinate-old-vnf":
"Scripts/coordinate_old_vnf.py",
"lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf",
"lcm-operation-coordinate-new-vnf":
"Scripts/coordinate_new_vnf.py",
"lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf"
}
}
@ -276,10 +272,8 @@ def change_vnfpkg_error(vnfd_id):
"upgrade_type": "RollingUpdate",
"lcm-operation-coordinate-old-vnf":
"Scripts/coordinate_old_vnf.py",
"lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf",
"lcm-operation-coordinate-new-vnf":
"Scripts/coordinate_new_vnf.py",
"lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf",
"lcm-kubernetes-def-files": [
"Files/new_kubernetes/error_deployment.yaml"]
}

View File

@ -16,6 +16,7 @@
import ddt
import os
import time
import unittest
from tacker.tests.functional.sol_kubernetes_v2 import base_v2
from tacker.tests.functional.sol_kubernetes_v2 import paramgen
@ -50,6 +51,7 @@ class VnfLcmKubernetesErrorHandingTest(base_v2.BaseVnfLcmKubernetesV2Test):
def setUp(self):
super(VnfLcmKubernetesErrorHandingTest, self).setUp()
@unittest.skip("Until refactor CNF v2 API")
def test_change_vnfpkg_failed_in_update_wait_and_rollback(self):
"""Test LCM operations error handing
@ -182,6 +184,7 @@ class VnfLcmKubernetesErrorHandingTest(base_v2.BaseVnfLcmKubernetesV2Test):
usage_state = self.get_vnf_package(self.vnf_pkg_2).get('usageState')
self.assertEqual('NOT_IN_USE', usage_state)
@unittest.skip("Until refactor CNF v2 API")
def test_change_vnfpkg_failed_and_retry(self):
"""Test LCM operations error handing

View File

@ -342,12 +342,16 @@ class GrantV2:
@staticmethod
def make_change_vnfpkg_response_body(
request_body):
request_body, image_id_dict, flavour_id_dict):
request_body = GrantV2.convert_body_to_dict(request_body)
res = GrantV2._make_response_template(request_body)
if 'addResources' in request_body.keys():
res["addResources"] = GrantV2._make_add_resources(
request_body['addResources'])
res["vimAssets"] = GrantV2._make_vim_assets(
request_body['addResources'],
image_id_dict,
flavour_id_dict)
if 'removeResources' in request_body.keys():
res["removeResources"] = GrantV2._make_remove_resources(
request_body['removeResources'])

View File

@ -25,7 +25,7 @@ class VnfLcmWithNfvoSeparator(test_vnflcm_basic_common.CommonVnfLcmTest):
self.basic_lcms_min_common_test(True)
def test_change_vnfpkg(self):
self.change_vnfpkg_from_image_to_volume_common_test(True)
self.change_vnfpkg_from_image_to_image_common_test(True)
def test_retry_rollback_scale_out(self):
self.retry_rollback_scale_out_common_test(True)

View File

@ -73,196 +73,7 @@ class ChangeVnfPkgVnfLcmTest(test_vnflcm_basic_common.CommonVnfLcmTest):
super(ChangeVnfPkgVnfLcmTest, self).setUp()
def test_change_vnfpkg_from_image_to_image(self):
create_req = paramgen.change_vnfpkg_create(self.vnfd_id_1)
resp, body = self.create_vnf_instance(create_req)
expected_inst_attrs = [
'id',
'vnfInstanceName',
'vnfInstanceDescription',
'vnfdId',
'vnfProvider',
'vnfProductName',
'vnfSoftwareVersion',
'vnfdVersion',
# 'vnfConfigurableProperties', # omitted
# 'vimConnectionInfo', # omitted
'instantiationState',
# 'instantiatedVnfInfo', # omitted
'metadata',
# 'extensions', # omitted
'_links'
]
self.assertEqual(201, resp.status_code)
self.check_resp_headers_in_create(resp)
self.check_resp_body(body, expected_inst_attrs)
inst_id = body['id']
net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt'])
subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1'])
instantiate_req = paramgen.change_vnfpkg_instantiate(
net_ids, subnet_ids, self.auth_url)
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp_1, body_1 = self.show_vnf_instance(inst_id)
stack_name = "vnf-{}".format(inst_id)
stack_id = self.heat_client.get_stack_resource(stack_name)['stack'][
'id']
image_id_1 = self.get_current_vdu_image(stack_id, stack_name, 'VDU2')
old_vnfd_id = body_1['vnfdId']
self.assertEqual(200, resp_1.status_code)
self.check_resp_headers_in_get(resp_1)
self.check_resp_body(body_1, expected_inst_attrs)
change_vnfpkg_req = paramgen.change_vnfpkg(self.vnfd_id_2)
resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
resp_2, body_2 = self.show_vnf_instance(inst_id)
image_id_2 = self.get_current_vdu_image(stack_id, stack_name, 'VDU2')
self.assertNotEqual(image_id_1, image_id_2)
self.assertEqual(200, resp_2.status_code)
self.check_resp_headers_in_get(resp_2)
self.check_resp_body(body_2, expected_inst_attrs)
new_vnfd_id = [obj['metadata']['current_vnfd_id'] for obj in body_2[
'instantiatedVnfInfo']['vnfcResourceInfo']][0]
self.assertNotEqual(old_vnfd_id, new_vnfd_id)
terminate_req = paramgen.terminate_vnf_min()
resp, body = self.terminate_vnf_instance(inst_id, terminate_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# wait a bit because there is a bit time lag between lcmocc DB
# update and terminate completion.
time.sleep(10)
resp, body = self.delete_vnf_instance(inst_id)
self.assertEqual(204, resp.status_code)
self.check_resp_headers_in_delete(resp)
def test_change_vnfpkg_from_image_to_volume(self):
self.change_vnfpkg_from_image_to_volume_common_test()
def test_change_vnfpkg_from_volume_to_image(self):
create_req = paramgen.change_vnfpkg_create(self.vnfd_id_1)
resp, body = self.create_vnf_instance(create_req)
expected_inst_attrs = [
'id',
'vnfInstanceName',
'vnfInstanceDescription',
'vnfdId',
'vnfProvider',
'vnfProductName',
'vnfSoftwareVersion',
'vnfdVersion',
# 'vnfConfigurableProperties', # omitted
# 'vimConnectionInfo', # omitted
'instantiationState',
# 'instantiatedVnfInfo', # omitted
'metadata',
# 'extensions', # omitted
'_links'
]
self.assertEqual(201, resp.status_code)
self.check_resp_headers_in_create(resp)
self.check_resp_body(body, expected_inst_attrs)
inst_id = body['id']
net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt'])
subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1'])
instantiate_req = paramgen.change_vnfpkg_instantiate(
net_ids, subnet_ids, self.auth_url, flavor_id='volume')
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
additional_inst_attrs = [
'vimConnectionInfo',
'instantiatedVnfInfo'
]
expected_inst_attrs.extend(additional_inst_attrs)
resp_1, body_1 = self.show_vnf_instance(inst_id)
stack_name = "vnf-{}".format(inst_id)
stack_id = self.heat_client.get_stack_resource(stack_name)['stack'][
'id']
image_id_1 = self.get_current_vdu_image(stack_id, stack_name, 'VDU2')
storageResourceIds_1 = [
obj.get('storageResourceIds') for obj in body_1[
'instantiatedVnfInfo']['vnfcResourceInfo']
if obj['vduId'] == 'VDU2']
resource_ids_1 = [obj['id'] for obj in body_1[
'instantiatedVnfInfo']['vnfcResourceInfo'] if obj[
'vduId'] == 'VDU2'][0]
self.assertIsNotNone(storageResourceIds_1)
self.assertEqual(200, resp_1.status_code)
self.check_resp_headers_in_get(resp_1)
self.check_resp_body(body_1, expected_inst_attrs)
change_vnfpkg_req = paramgen.change_vnfpkg(self.vnfd_id_2)
del change_vnfpkg_req['additionalParams']['vdu_params'][0]
resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
resp_2, body_2 = self.show_vnf_instance(inst_id)
image_id_2 = self.get_current_vdu_image(stack_id, stack_name, 'VDU2')
storageResourceIds_2 = [
obj.get('storageResourceIds') for obj in body_2[
'instantiatedVnfInfo']['vnfcResourceInfo']
if obj['vduId'] == 'VDU2']
resource_ids_2 = [obj['id'] for obj in body_2[
'instantiatedVnfInfo']['vnfcResourceInfo'] if obj[
'vduId'] == 'VDU2'][0]
self.assertIsNone(storageResourceIds_2[0])
self.assertNotEqual(image_id_1, image_id_2)
self.assertNotEqual(resource_ids_1, resource_ids_2)
self.assertEqual(200, resp_2.status_code)
self.check_resp_headers_in_get(resp_2)
self.check_resp_body(body_2, expected_inst_attrs)
terminate_req = paramgen.terminate_vnf_min()
resp, body = self.terminate_vnf_instance(inst_id, terminate_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
lcmocc_id = os.path.basename(resp.headers['Location'])
self.wait_lcmocc_complete(lcmocc_id)
# wait a bit because there is a bit time lag between lcmocc DB
# update and terminate completion.
time.sleep(10)
resp, body = self.delete_vnf_instance(inst_id)
self.assertEqual(204, resp.status_code)
self.check_resp_headers_in_delete(resp)
self.change_vnfpkg_from_image_to_image_common_test()
def test_change_vnfpkg_from_volume_to_volume(self):
create_req = paramgen.change_vnfpkg_create(self.vnfd_id_1)
@ -425,10 +236,7 @@ class ChangeVnfPkgVnfLcmTest(test_vnflcm_basic_common.CommonVnfLcmTest):
self.wait_lcmocc_rolled_back(lcmocc_id)
resp_2, body_2 = self.show_vnf_instance(inst_id)
new_vnfd_id = [
obj['metadata'].get('current_vnfd_id') for obj in body_2[
'instantiatedVnfInfo']['vnfcResourceInfo']
if obj['metadata'].get('current_vnfd_id')][0]
new_vnfd_id = body_2['vnfdId']
self.assertEqual(old_vnfd_id, new_vnfd_id)
self.assertEqual(200, resp_2.status_code)
@ -509,9 +317,6 @@ class ChangeVnfPkgVnfLcmTest(test_vnflcm_basic_common.CommonVnfLcmTest):
change_vnfpkg_req['additionalParams'][
'lcm-operation-coordinate-new-vnf'
] = "./Scripts/error_coordinate_new_vnf.py"
change_vnfpkg_req['additionalParams'][
'lcm-operation-coordinate-new-vnf-class'
] = "ErrorCoordinateNewVnf"
del change_vnfpkg_req['additionalParams']['vdu_params'][0]
resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req)
self.assertEqual(202, resp.status_code)

View File

@ -331,14 +331,17 @@ class BaseSolV2Test(base.BaseTestCase):
)
glance_client = glance_utils.GlanceClient(vim)
if num_vdu == 1:
vdu = 'VDU2' if 'VDU2' in sw_data else 'VDU2-VirtualStorage'
image = glance_client.create_image(
sw_data['VDU2-VirtualStorage']['name'], **create_args)
sw_data[vdu]['name'], **create_args)
return image.id
vdu = 'VDU1' if 'VDU1' in sw_data else 'VDU1-VirtualStorage'
image_1 = glance_client.create_image(
sw_data['VDU1-VirtualStorage']['name'], **create_args)
sw_data[vdu]['name'], **create_args)
vdu = 'VDU2' if 'VDU2' in sw_data else 'VDU2-VirtualStorage'
image_2 = glance_client.create_image(
sw_data['VDU2-VirtualStorage']['name'], **create_args)
sw_data[vdu]['name'], **create_args)
return image_1.id, image_2.id
def glance_delete_image(self, vim_info, image_ids):

View File

@ -904,10 +904,8 @@ def change_vnfpkg(vnfd_id):
"upgrade_type": "RollingUpdate",
"lcm-operation-coordinate-old-vnf":
"./Scripts/coordinate_old_vnf.py",
"lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf",
"lcm-operation-coordinate-new-vnf":
"./Scripts/coordinate_new_vnf.py",
"lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf",
"vdu_params": [{
"vdu_id": "VDU1",
"old_vnfc_param": {

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1-VirtualStorage:
type: string
zone:
type: string
@ -49,7 +49,7 @@ resources:
VDU1-VirtualStorage:
type: OS::Cinder::Volume
properties:
image: { get_param: image }
image: { get_param: image-VDU1-VirtualStorage }
size: 1
volume_type: { get_param: volume_type }

View File

@ -16,7 +16,7 @@ resources:
type: VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
image-VDU1-VirtualStorage: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
net2: { get_param: [ nfv, CP, VDU1_CP2, network ] }

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1:
type: string
net5:
type: string
@ -16,7 +16,7 @@ resources:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
image: { get_param: image }
image: { get_param: image-VDU1 }
name: VDU1
networks:
- port:

View File

@ -16,7 +16,7 @@ resources:
type: VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
net5: { get_resource: internalVL3 }
affinity: { get_resource: nfvi_node_affinity }

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1:
type: string
net5:
type: string
@ -16,7 +16,7 @@ resources:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
image: { get_param: image }
image: { get_param: image-VDU1 }
name: VDU1
networks:
- port:

View File

@ -16,7 +16,7 @@ resources:
type: VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
net5: { get_resource: internalVL3 }
affinity: { get_resource: nfvi_node_affinity }

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1-VirtualStorage:
type: string
zone:
type: string
@ -47,7 +47,7 @@ resources:
VDU1-VirtualStorage:
type: OS::Cinder::Volume
properties:
image: { get_param: image }
image: { get_param: image-VDU1-VirtualStorage }
size: 1
volume_type: { get_resource: VDU1-VolumeType }
VDU1-VolumeType:

View File

@ -16,7 +16,7 @@ resources:
type: VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
image-VDU1-VirtualStorage: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
net2: { get_param: [ nfv, CP, VDU1_CP2, network ] }

View File

@ -16,7 +16,7 @@ resources:
type: base_hot_nested_VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1, vcImageId] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
VDU2:

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1:
type: string
net1:
type: string
@ -15,7 +15,7 @@ resources:
properties:
flavor: { get_param: flavor }
name: VDU1
image: { get_param: image }
image: { get_param: image-VDU1 }
networks:
- port:
get_resource: VDU1_CP1

View File

@ -16,7 +16,7 @@ resources:
type: base_hot_nested_VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId] }
image-VDU1-VirtualStorage: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
volume_type: { get_resource: VDU1-VolumeType }

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1-VirtualStorage:
type: string
net1:
type: string
@ -30,6 +30,6 @@ resources:
VDU1-VirtualStorage:
type: OS::Cinder::Volume
properties:
image: { get_param: image }
image: { get_param: image-VDU1-VirtualStorage }
size: 4
volume_type: { get_param: volume_type }

View File

@ -20,9 +20,7 @@ import time
from oslo_log import log as logging
import paramiko
from tacker.sol_refactored.common import common_script_utils
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnfd_utils
LOG = logging.getLogger(__name__)
CMD_TIMEOUT = 30
@ -32,13 +30,8 @@ SSH_CONNECT_RETRY_COUNT = 4
class SampleNewCoordinateVNFScript(object):
def __init__(self, req, inst, grant_req, grant, csar_dir, vdu_info):
self.req = req
self.inst = inst
self.grant_req = grant_req
self.grant = grant
self.csar_dir = csar_dir
self.vdu_info = vdu_info
def __init__(self, vnfc_param):
self.vnfc_param = vnfc_param
def coordinate_vnf(self):
# check ssh connect and os version
@ -48,11 +41,9 @@ class SampleNewCoordinateVNFScript(object):
Since the zuul's network cannot check this content, so
we comment this part of code. If you want to check them
in your local environment, please uncomment.
# user = self.vdu_info.get('vdu_param').get(
# 'new_vnfc_param').get('username')
# password = self.vdu_info.get('vdu_param').get(
# 'new_vnfc_param').get('password')
# host = self.vdu_info.get("ssh_ip")
# user = self.vnfc_param['username']
# password = self.vnfc_param['password']
# host = self.vnfc_param['ssh_ip']
# commander = self._init_commander(
# user, password, host, retry=SSH_CONNECT_RETRY_COUNT)
# ssh_command = 'cat /etc/os-release | grep PRETTY_NAME'
@ -60,20 +51,7 @@ class SampleNewCoordinateVNFScript(object):
# os_version = result[0].replace('\n', '').split('=')[1]
# LOG.info('The os version of this new VM is %s', os_version)
"""
# check image and flavour updated successfully
vnfd = vnfd_utils.Vnfd(self.req.get('vnfdId'))
vnfd.init_from_csar_dir(self.csar_dir)
vdu_infos = common_script_utils.get_vdu_info(
self.grant, self.inst, vnfd)
vdu_id = self.vdu_info.get('vdu_param').get('vdu_id')
image = vdu_infos.get(vdu_id, {}).get('image')
flavor = vdu_infos.get(vdu_id, {}).get('flavor')
if self.vdu_info.get('new_image') != image or self.vdu_info.get(
'new_flavor') != flavor:
error = "The VM's image or flavour update failed'"
LOG.error(error)
raise sol_ex.VMRunningFailed(error)
pass
def _init_commander(self, user, password, host, retry):
while retry > 0:
@ -119,16 +97,8 @@ class SampleNewCoordinateVNFScript(object):
def main():
operation = "coordinate_vnf"
script_dict = pickle.load(sys.stdin.buffer)
req = script_dict['request']
inst = script_dict['vnf_instance']
grant_req = script_dict['grant_request']
grant = script_dict['grant_response']
csar_dir = script_dict['tmp_csar_dir']
vdu_info = script_dict['vdu_info']
script = SampleNewCoordinateVNFScript(
req, inst, grant_req, grant,
csar_dir, vdu_info)
vnfc_param = pickle.load(sys.stdin.buffer)
script = SampleNewCoordinateVNFScript(vnfc_param)
try:
getattr(script, operation)()
except Exception:

View File

@ -42,10 +42,3 @@ change_vnfpkg_req_from_image_to_image = paramgen.change_vnfpkg(vnfd_id)
with open("change_vnfpkg_req_from_image_to_image", "w", encoding='utf-8') as f:
f.write(json.dumps(change_vnfpkg_req_from_image_to_image, indent=2))
# if your sample is change VM from volume to image
change_vnfpkg_req_from_volume_to_image = paramgen.change_vnfpkg(vnfd_id)
del change_vnfpkg_req_from_volume_to_image['additionalParams']['vdu_params'][0]
with open("change_vnfpkg_req_from_volume", "w", encoding='utf-8') as f:
f.write(json.dumps(change_vnfpkg_req_from_volume_to_image, indent=2))

View File

@ -16,7 +16,7 @@ resources:
type: base_hot_nested_VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
VDU2:

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1:
type: string
net1:
type: string
@ -15,7 +15,7 @@ resources:
properties:
flavor: { get_param: flavor }
name: VDU1
image: { get_param: image }
image: { get_param: image-VDU1 }
networks:
- port:
get_resource: VDU1_CP1

View File

@ -16,7 +16,7 @@ resources:
type: base_hot_nested_VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
image-VDU1-VirtualStorage: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
volume_type: { get_resource: VDU1-VolumeType }

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1-VirtualStorage:
type: string
net1:
type: string
@ -30,6 +30,6 @@ resources:
VDU1-VirtualStorage:
type: OS::Cinder::Volume
properties:
image: { get_param: image }
image: { get_param: image-VDU1-VirtualStorage }
size: 4
volume_type: { get_param: volume_type }

View File

@ -20,9 +20,7 @@ import time
from oslo_log import log as logging
import paramiko
from tacker.sol_refactored.common import common_script_utils
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnfd_utils
LOG = logging.getLogger(__name__)
CMD_TIMEOUT = 30
@ -32,13 +30,8 @@ SSH_CONNECT_RETRY_COUNT = 4
class SampleNewCoordinateVNFScript(object):
def __init__(self, req, inst, grant_req, grant, csar_dir, vdu_info):
self.req = req
self.inst = inst
self.grant_req = grant_req
self.grant = grant
self.csar_dir = csar_dir
self.vdu_info = vdu_info
def __init__(self, vnfc_param):
self.req = vnfc_param
def coordinate_vnf(self):
# check ssh connect and os version
@ -48,11 +41,9 @@ class SampleNewCoordinateVNFScript(object):
Since the zuul's network cannot check this content, so
we comment this part of code. If you want to check them
in your local environment, please uncomment.
user = self.vdu_info.get('vdu_param').get(
'new_vnfc_param').get('username')
password = self.vdu_info.get('vdu_param').get(
'new_vnfc_param').get('password')
host = self.vdu_info.get("ssh_ip")
user = self.vnfc_param['username']
password = self.vnfc_param['password']
host = self.vnfc_param['ssh_ip']
commander = self._init_commander(
user, password, host, retry=SSH_CONNECT_RETRY_COUNT)
ssh_command = 'cat /etc/os-release | grep PRETTY_NAME'
@ -60,20 +51,7 @@ class SampleNewCoordinateVNFScript(object):
os_version = result[0].replace('\n', '').split('=')[1]
LOG.info('The os version of this new VM is %s', os_version)
"""
# check image and flavour updated successfully
vnfd = vnfd_utils.Vnfd(self.req.get('vnfdId'))
vnfd.init_from_csar_dir(self.csar_dir)
vdu_infos = common_script_utils.get_vdu_info(
self.grant, self.inst, vnfd)
vdu_id = self.vdu_info.get('vdu_param').get('vdu_id')
image = vdu_infos.get(vdu_id, {}).get('image')
flavor = vdu_infos.get(vdu_id, {}).get('flavor')
if self.vdu_info.get('new_image') != image or self.vdu_info.get(
'new_flavor') != flavor:
error = "The VM's image or flavour update failed'"
LOG.error(error)
raise sol_ex.VMRunningFailed(error)
pass
def _init_commander(self, user, password, host, retry):
while retry > 0:
@ -119,16 +97,8 @@ class SampleNewCoordinateVNFScript(object):
def main():
operation = "coordinate_vnf"
script_dict = pickle.load(sys.stdin.buffer)
req = script_dict['request']
inst = script_dict['vnf_instance']
grant_req = script_dict['grant_request']
grant = script_dict['grant_response']
csar_dir = script_dict['tmp_csar_dir']
vdu_info = script_dict['vdu_info']
script = SampleNewCoordinateVNFScript(
req, inst, grant_req, grant,
csar_dir, vdu_info)
vnfc_param = pickle.load(sys.stdin.buffer)
script = SampleNewCoordinateVNFScript(vnfc_param)
try:
getattr(script, operation)()
except Exception:

View File

@ -27,13 +27,8 @@ SSH_CONNECT_RETRY_COUNT = 4
class SampleErrorNewCoordinateVNFScript(object):
def __init__(self, req, inst, grant_req, grant, csar_dir, vdu_info):
self.req = req
self.inst = inst
self.grant_req = grant_req
self.grant = grant
self.csar_dir = csar_dir
self.vdu_info = vdu_info
def __init__(self, vnfc_param):
self.vnfc_param = vnfc_param
def coordinate_vnf(self):
raise Exception("ErrorNewCoordinateVNFScript")
@ -41,16 +36,8 @@ class SampleErrorNewCoordinateVNFScript(object):
def main():
operation = "coordinate_vnf"
script_dict = pickle.load(sys.stdin.buffer)
req = script_dict['request']
inst = script_dict['vnf_instance']
grant_req = script_dict['grant_request']
grant = script_dict['grant_response']
csar_dir = script_dict['tmp_csar_dir']
vdu_info = script_dict['vdu_info']
script = SampleErrorNewCoordinateVNFScript(
req, inst, grant_req, grant,
csar_dir, vdu_info)
vnfc_param = pickle.load(sys.stdin.buffer)
script = SampleErrorNewCoordinateVNFScript(vnfc_param)
try:
getattr(script, operation)()
except Exception:

View File

@ -37,18 +37,16 @@ utils.make_zip(".", tmp_dir, vnfd_id, image_path)
shutil.move(os.path.join(tmp_dir, zip_file_name), ".")
shutil.rmtree(tmp_dir)
# if your sample is change VM from image to volume
change_vnfpkg_req_from_image_to_volume = paramgen.change_vnfpkg(vnfd_id)
del change_vnfpkg_req_from_image_to_volume['additionalParams']['vdu_params'][0]
with open("change_vnfpkg_req_from_image_to_volume", "w",
encoding='utf-8') as f:
f.write(json.dumps(change_vnfpkg_req_from_image_to_volume, indent=2))
# if your sample is change VM from volume to volume
change_vnfpkg_req_from_volume_to_volume = paramgen.change_vnfpkg(vnfd_id)
del change_vnfpkg_req_from_volume_to_volume[
'additionalParams']['vdu_params'][0]
with open("change_vnfpkg_req_from_volume", "w", encoding='utf-8') as f:
f.write(json.dumps(change_vnfpkg_req_from_volume_to_volume, indent=2))
change_vnfpkg_req_error_coodinate_vnf = paramgen.change_vnfpkg(vnfd_id)
change_vnfpkg_req_error_coodinate_vnf['additionalParams'][
'lcm-operation-coordinate-new-vnf'
] = "./Scripts/error_coordinate_new_vnf.py"
with open("change_vnfpkg_req_error_coodinate_vnf", "w", encoding='utf-8') as f:
f.write(json.dumps(change_vnfpkg_req_error_coodinate_vnf, indent=2))

View File

@ -16,7 +16,7 @@ resources:
type: base_hot_nested_VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1, vcImageId] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
VDU2:

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1:
type: string
net1:
type: string
@ -15,7 +15,7 @@ resources:
properties:
flavor: { get_param: flavor }
name: VDU1
image: { get_param: image }
image: { get_param: image-VDU1 }
networks:
- port:
get_resource: VDU1_CP1

View File

@ -20,9 +20,7 @@ import time
from oslo_log import log as logging
import paramiko
from tacker.sol_refactored.common import common_script_utils
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnfd_utils
LOG = logging.getLogger(__name__)
CMD_TIMEOUT = 30
@ -32,13 +30,8 @@ SSH_CONNECT_RETRY_COUNT = 4
class SampleNewCoordinateVNFScript(object):
def __init__(self, req, inst, grant_req, grant, csar_dir, vdu_info):
self.req = req
self.inst = inst
self.grant_req = grant_req
self.grant = grant
self.csar_dir = csar_dir
self.vdu_info = vdu_info
def __init__(self, vnfc_param):
self.vnfc_param = vnfc_param
def coordinate_vnf(self):
# check ssh connect and os version
@ -48,11 +41,9 @@ class SampleNewCoordinateVNFScript(object):
Since the zuul's network cannot check this content, so
we comment this part of code. If you want to check them
in your local environment, please uncomment.
# user = self.vdu_info.get('vdu_param').get(
# 'new_vnfc_param').get('username')
# password = self.vdu_info.get('vdu_param').get(
# 'new_vnfc_param').get('password')
# host = self.vdu_info.get("ssh_ip"),
# user = self.vnfc_param['username']
# password = self.vnfc_param['password']
# host = self.vnfc_param['ssh_ip']
# commander = self._init_commander(
# user, password, host, retry=SSH_CONNECT_RETRY_COUNT)
# ssh_command = 'cat /etc/os-release | grep PRETTY_NAME'
@ -60,20 +51,7 @@ class SampleNewCoordinateVNFScript(object):
# os_version = result.get_stdout()[0].replace('\n', '').split('=')
# LOG.info('The os version of this new VM is %s', os_version)
"""
# check image and flavour updated successfully
vnfd = vnfd_utils.Vnfd(self.req.get('vnfdId'))
vnfd.init_from_csar_dir(self.csar_dir)
vdu_infos = common_script_utils.get_vdu_info(
self.grant, self.inst, vnfd)
vdu_id = self.vdu_info.get('vdu_param').get('vdu_id')
image = vdu_infos.get(vdu_id, {}).get('image')
flavor = vdu_infos.get(vdu_id, {}).get('flavor')
if self.vdu_info.get('new_image') != image or self.vdu_info.get(
'new_flavor') != flavor:
error = "The VM's image or flavour update failed'"
LOG.error(error)
raise sol_ex.VMRunningFailed(error)
pass
def _init_commander(self, user, password, host, retry):
while retry > 0:
@ -119,16 +97,8 @@ class SampleNewCoordinateVNFScript(object):
def main():
operation = "coordinate_vnf"
script_dict = pickle.load(sys.stdin.buffer)
req = script_dict['request']
inst = script_dict['vnf_instance']
grant_req = script_dict['grant_request']
grant = script_dict['grant_response']
csar_dir = script_dict['tmp_csar_dir']
vdu_info = script_dict['vdu_info']
script = SampleNewCoordinateVNFScript(
req, inst, grant_req, grant,
csar_dir, vdu_info)
vnfc_param = pickle.load(sys.stdin.buffer)
script = SampleNewCoordinateVNFScript(vnfc_param)
try:
getattr(script, operation)()
except Exception:

View File

@ -16,7 +16,7 @@ resources:
type: base_hot_nested_VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1, vcImageId] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
VDU2:

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1:
type: string
net1:
type: string
@ -15,7 +15,7 @@ resources:
properties:
flavor: { get_param: flavor }
name: VDU1
image: { get_param: image }
image: { get_param: image-VDU1 }
networks:
- port:
get_resource: VDU1_CP1

View File

@ -16,7 +16,7 @@ resources:
type: base_hot_nested_VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
image-VDU1-VirtualStorage: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
volume_type: { get_resource: VDU1-VolumeType }

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1-VirtualStorage:
type: string
net1:
type: string
@ -30,6 +30,6 @@ resources:
VDU1-VirtualStorage:
type: OS::Cinder::Volume
properties:
image: { get_param: image }
image: { get_param: image-VDU1-VirtualStorage }
size: 4
volume_type: { get_param: volume_type }

View File

@ -20,9 +20,7 @@ import time
from oslo_log import log as logging
import paramiko
from tacker.sol_refactored.common import common_script_utils
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import vnfd_utils
LOG = logging.getLogger(__name__)
CMD_TIMEOUT = 30
@ -32,13 +30,8 @@ SSH_CONNECT_RETRY_COUNT = 4
class SampleOldCoordinateVNFScript(object):
def __init__(self, req, inst, grant_req, grant, csar_dir, vdu_info):
self.req = req
self.inst = inst
self.grant_req = grant_req
self.grant = grant
self.csar_dir = csar_dir
self.vdu_info = vdu_info
def __init__(self, vnfc_param):
self.vnfc_param = vnfc_param
def coordinate_vnf(self):
# check ssh connect and os version
@ -48,11 +41,9 @@ class SampleOldCoordinateVNFScript(object):
Since the zuul's network cannot check this content, so
we comment this part of code. If you want to check them
in your local environment, please uncomment.
# user = self.vdu_info.get('vdu_param').get(
# 'old_vnfc_param').get('username')
# password = self.vdu_info.get('vdu_param').get(
# 'old_vnfc_param').get('password')
# host = self.vdu_info.get("ssh_ip"),
# user = self.vnfc_param['username']
# password = self.vnfc_param['password']
# host = self.vnfc_param['ssh_ip']
# commander = self._init_commander(
# user, password, host, retry=SSH_CONNECT_RETRY_COUNT)
# ssh_command = 'cat /etc/os-release | grep PRETTY_NAME'
@ -60,20 +51,7 @@ class SampleOldCoordinateVNFScript(object):
# os_version = result.get_stdout()[0].replace('\n', '').split('=')
# LOG.info('The os version of this new VM is %s', os_version)
"""
# check image and flavour updated successfully
vnfd = vnfd_utils.Vnfd(self.req.get('vnfdId'))
vnfd.init_from_csar_dir(self.csar_dir)
vdu_infos = common_script_utils.get_vdu_info(
self.grant, self.inst, vnfd)
vdu_id = self.vdu_info.get('vdu_param').get('vdu_id')
image = vdu_infos.get(vdu_id, {}).get('image')
flavor = vdu_infos.get(vdu_id, {}).get('flavor')
if self.vdu_info.get('new_image') != image or self.vdu_info.get(
'new_flavor') != flavor:
error = "The VM's image or flavour update failed'"
LOG.error(error)
raise sol_ex.VMRunningFailed(error)
pass
def _init_commander(self, user, password, host, retry):
while retry > 0:
@ -119,16 +97,8 @@ class SampleOldCoordinateVNFScript(object):
def main():
operation = "coordinate_vnf"
script_dict = pickle.load(sys.stdin.buffer)
req = script_dict['request']
inst = script_dict['vnf_instance']
grant_req = script_dict['grant_request']
grant = script_dict['grant_response']
csar_dir = script_dict['tmp_csar_dir']
vdu_info = script_dict['vdu_info']
script = SampleOldCoordinateVNFScript(
req, inst, grant_req, grant,
csar_dir, vdu_info)
vnfc_param = pickle.load(sys.stdin.buffer)
script = SampleOldCoordinateVNFScript(vnfc_param)
try:
getattr(script, operation)()
except Exception:

View File

@ -47,14 +47,6 @@ subnet_ids = utils.get_subnet_ids(['subnet0'])
instantiate_req_from_image_to_image = paramgen.change_vnfpkg_instantiate(
net_ids, subnet_ids, "http://localhost/identity/v3")
# if your sample is change VM from volume to image
instantiate_req_from_volume_to_image = paramgen.change_vnfpkg_instantiate(
net_ids, subnet_ids, "http://localhost/identity/v3", flavor_id='volume')
# if your sample is change VM from image to volume
instantiate_req_from_image_to_volume = paramgen.change_vnfpkg_instantiate(
net_ids, subnet_ids, "http://localhost/identity/v3")
# if your sample is change VM from volume to volume
instantiate_req_from_volume_to_volume = paramgen.change_vnfpkg_instantiate(
net_ids, subnet_ids, "http://localhost/identity/v3", flavor_id='volume')
@ -72,12 +64,6 @@ with open("terminate_req", "w") as f:
with open("instantiate_req_from_image_to_image", "w") as f:
f.write(json.dumps(instantiate_req_from_image_to_image, indent=2))
with open("instantiate_req_from_volume_to_image", "w") as f:
f.write(json.dumps(instantiate_req_from_volume_to_image, indent=2))
with open("instantiate_req_from_image_to_volume", "w") as f:
f.write(json.dumps(instantiate_req_from_image_to_volume, indent=2))
with open("instantiate_req_from_volume_to_volume", "w") as f:
f.write(json.dumps(instantiate_req_from_volume_to_volume, indent=2))

View File

@ -4,7 +4,7 @@ description: 'VDU1 HOT for Sample VNF'
parameters:
flavor:
type: string
image:
image-VDU1:
type: string
net5:
type: string
@ -16,7 +16,7 @@ resources:
type: OS::Nova::Server
properties:
flavor: { get_param: flavor }
image: { get_param: image }
image: { get_param: image-VDU1 }
name: VDU1
networks:
- port:

View File

@ -16,7 +16,7 @@ resources:
type: VDU1.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
image: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
net5: { get_resource: internalVL3 }
affinity: { get_resource: nfvi_node_affinity }

View File

@ -152,7 +152,7 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
response_headers={"Content-Type": "application/json"},
callback=lambda req_headers, req_body:
fake_grant_v2.GrantV2.make_change_vnfpkg_response_body(
req_body))
req_body, glance_image, flavour_vdu_dict))
else:
raise Exception
@ -1612,8 +1612,8 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
resp, body = self.show_subscription(sub_id)
self.assertEqual(404, resp.status_code)
def change_vnfpkg_from_image_to_volume_common_test(self, is_nfvo=False):
"""Test ChangeCurrentVNFPackage from image to volume
def change_vnfpkg_from_image_to_image_common_test(self, is_nfvo=False):
"""Test ChangeCurrentVNFPackage from image to image
* About attributes:
All of the following cardinality attributes are set.
@ -1641,15 +1641,15 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
"samples/test_instantiate_vnf_with_old_image_or_volume")
zip_file_path_1, vnfd_id_1 = self.create_vnf_package(
change_vnfpkg_from_image_to_image_path, nfvo=True)
change_vnfpkg_from_image_to_volume_path = os.path.join(
cur_dir, "samples/test_change_vnf_pkg_with_new_volume")
change_vnfpkg_from_image_to_image_path_2 = os.path.join(
cur_dir, "samples/test_change_vnf_pkg_with_new_image")
image_dir = os.path.join(
cur_dir, "../../etc/samples/etsi/nfv/common/Files/images")
image_file = "cirros-0.5.2-x86_64-disk.img"
image_path = os.path.abspath(os.path.join(image_dir, image_file))
zip_file_path_3, vnfd_id_3 = self.create_vnf_package(
change_vnfpkg_from_image_to_volume_path, image_path=image_path,
nfvo=True)
zip_file_path_2, vnfd_id_2 = self.create_vnf_package(
change_vnfpkg_from_image_to_image_path_2,
image_path=image_path, nfvo=True)
package_dir = os.path.join(
cur_dir,
"samples/test_instantiate_vnf_with_old_image_or_volume")
@ -1657,10 +1657,10 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
"contents/Definitions/change_vnf_pkg_old_image_df_simple.yaml")
change_package_dir = os.path.join(
cur_dir, "samples/test_change_vnf_pkg_with_new_volume")
cur_dir, "samples/test_change_vnf_pkg_with_new_image")
change_vnfd_path = (
"contents/Definitions/"
"change_vnf_pkg_new_volume_df_simple.yaml")
"change_vnf_pkg_new_image_df_simple.yaml")
sw_data = fake_grant_v2.GrantV2.get_sw_data(
change_package_dir, change_vnfd_path)
glance_image = fake_grant_v2.GrantV2.get_sw_image(
@ -1671,13 +1671,13 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
self._register_vnf_package_mock_response(
vnfd_id_1, zip_file_path_1)
create_req = paramgen.change_vnfpkg_create(vnfd_id_1)
change_vnfpkg_req = paramgen.change_vnfpkg(vnfd_id_3)
change_vnfpkg_req = paramgen.change_vnfpkg(vnfd_id_2)
else:
glance_image = None
flavour_vdu_dict = None
zone_name_list = None
create_req = paramgen.change_vnfpkg_create(self.vnfd_id_1)
change_vnfpkg_req = paramgen.change_vnfpkg(self.vnfd_id_3)
change_vnfpkg_req = paramgen.change_vnfpkg(self.vnfd_id_2)
# 1. Create VNF instance
resp, body = self.create_vnf_instance(create_req)
@ -1734,19 +1734,18 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
self.assertEqual(200, resp_1.status_code)
self.check_resp_headers_in_get(resp_1)
self.check_resp_body(body_1, expected_inst_attrs)
resource_ids_1 = [obj['id'] for obj in body_1[
'instantiatedVnfInfo']['vnfcResourceInfo'] if obj[
'vduId'] == 'VDU2'][0]
# 4. Change Current VNF Package
if is_nfvo:
self._register_vnf_package_mock_response(
vnfd_id_3, zip_file_path_3)
image_id = self.glance_create_image(
vnfd_id_2, zip_file_path_2)
g_image_id_1, g_image_id_2 = self.glance_create_image(
instantiate_req.get("vimConnectionInfo").get("vim1"),
image_path, sw_data, inst_id)
self._set_grant_response(is_nfvo, 'CHANGE_VNFPKG')
del change_vnfpkg_req['additionalParams']['vdu_params'][0]
image_path, sw_data, inst_id, num_vdu=2)
glance_image['VDU1'] = g_image_id_1
glance_image['VDU2'] = g_image_id_2
self._set_grant_response(is_nfvo, 'CHANGE_VNFPKG',
glance_image=glance_image, flavour_vdu_dict=flavour_vdu_dict)
resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req)
self.assertEqual(202, resp.status_code)
self.check_resp_headers_in_operation_task(resp)
@ -1757,15 +1756,6 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
# 5. Show VNF instance
resp_2, body_2 = self.show_vnf_instance(inst_id)
image_id_2 = self.get_current_vdu_image(stack_id, stack_name, 'VDU2')
storage_resource_ids = [obj.get('storageResourceIds')
for obj in body_2['instantiatedVnfInfo'][
'vnfcResourceInfo'] if obj[
'vduId'] == 'VDU2']
self.assertIsNotNone(storage_resource_ids)
resource_ids_2 = [obj['id'] for obj in body_2[
'instantiatedVnfInfo']['vnfcResourceInfo'] if obj[
'vduId'] == 'VDU2'][0]
self.assertNotEqual(resource_ids_1, resource_ids_2)
self.assertNotEqual(image_id_1, image_id_2)
self.assertEqual(200, resp_2.status_code)
@ -1794,7 +1784,7 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
if is_nfvo:
self.glance_delete_image(
instantiate_req.get("vimConnectionInfo").get("vim1"),
[image_id])
[g_image_id_1, g_image_id_2])
def retry_rollback_scale_out_common_test(self, is_nfvo=False):
"""Test retry and rollback scale out operations

View File

@ -256,7 +256,10 @@ _inst_info_example_1 = {
"vnfLinkPortId": "res_id_VDU1_CP5_1"
}
],
# "metadata": omitted
"metadata": {
"image-VDU1-VirtualStorage": "image-VDU1"
# other attributes omitted
}
},
{
"id": "res_id_VDU2",
@ -293,7 +296,10 @@ _inst_info_example_1 = {
"vnfLinkPortId": "res_id_VDU2_CP5"
}
],
# "metadata": omitted
"metadata": {
"image-VDU2": "image-VDU2"
# other attributes omitted
}
}
],
"vnfVirtualLinkResourceInfo": [
@ -532,7 +538,10 @@ _inst_info_example_2 = {
"vnfLinkPortId": "res_id_VDU1_CP5_2"
}
],
# "metadata": omitted
"metadata": {
"image-VDU1-VirtualStorage": "image-VDU1"
# other attributes omitted
}
},
{
"id": "res_id_VDU1_1",
@ -572,7 +581,10 @@ _inst_info_example_2 = {
"vnfLinkPortId": "res_id_VDU1_CP5_1"
}
],
# "metadata": omitted
"metadata": {
"image-VDU1-VirtualStorage": "image-VDU1"
# other attributes omitted
}
},
{
"id": "res_id_VDU2",
@ -609,7 +621,10 @@ _inst_info_example_2 = {
"vnfLinkPortId": "res_id_VDU2_CP5"
}
],
# "metadata": omitted
"metadata": {
"image-VDU2": "image-VDU2"
# other attributes omitted
}
}
],
"vnfVirtualLinkResourceInfo": [
@ -905,14 +920,14 @@ _inst_info_example_3 = {
# example_4 is for update_lcmocc test in case of heal. based on example_2.
# * VDU1_1: update server only. VDU1_2: update both server and volume.
# * ports of extMangagedVirtualLink are re-created.
# * ports of extManagedVirtualLink are re-created.
# NOTE: combination of the above sentences can not be happened really.
# it is the data for unit test.
_inst_info_example_4 = {
# "flavourId", "vnfState", "scaleStatus", "maxScaleLevels" are omitted
# "extCpInfo": omitted
"extVirtualLinkInfo": _inst_info_example_2["extVirtualLinkInfo"],
# network resource is not changed but ports are re-receated.
# network resource is not changed but ports are re-created.
# this is for check of SOL003 all=True case.
"extManagedVirtualLinkInfo": [
@ -995,7 +1010,10 @@ _inst_info_example_4 = {
"vnfLinkPortId": "res_id_VDU1_CP5_2_new"
}
],
# "metadata": omitted
"metadata": {
"image-VDU1-VirtualStorage": "image-VDU1"
# other attributes omitted
}
},
{
"id": "res_id_VDU1_1_new",
@ -1035,7 +1053,10 @@ _inst_info_example_4 = {
"vnfLinkPortId": "res_id_VDU1_CP5_1_new"
}
],
# "metadata": omitted
"metadata": {
"image-VDU1-VirtualStorage": "image-VDU1"
# other attributes omitted
}
},
{
"id": "res_id_VDU2",
@ -1072,7 +1093,10 @@ _inst_info_example_4 = {
"vnfLinkPortId": "res_id_VDU2_CP5"
}
],
# "metadata": omitted
"metadata": {
"image-VDU2": "image-VDU2"
# other attributes omitted
}
}
],
"vnfVirtualLinkResourceInfo":
@ -1104,93 +1128,9 @@ _inst_info_example_4 = {
_inst_info_example_5 = {
# "flavourId", "vnfState", "scaleStatus", "maxScaleLevels" are omitted
# "extCpInfo": omitted
"extVirtualLinkInfo": [
{
"id": "bbf0932a-6142-4ea8-93cd-8059dba594a1",
"resourceHandle": {
"resourceId": "3529d333-dbcc-4d93-9b64-210647712569"
},
"extLinkPorts": [
{
"id": "res_id_VDU2_CP1",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU2_CP1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "cp-res_id_VDU2_CP1"
},
{
"id": "res_id_VDU1_CP1_1",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU1_CP1_1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "cp-res_id_VDU1_CP1_1"
}
],
# "currentVnfExtCpData": omitted
},
{
"id": "790949df-c7b3-4926-a559-3895412f1dfe",
"resourceHandle": {
"resourceId": "367e5b3b-34dc-47f2-85b8-c39e3272893a"
},
"extLinkPorts": [
{
"id": "res_id_VDU2_CP2",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU2_CP2",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "cp-res_id_VDU2_CP2"
},
{
"id": "res_id_VDU1_CP2_1",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU1_CP2_1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "cp-res_id_VDU1_CP2_1"
}
],
# "currentVnfExtCpData": omitted
}
],
"extManagedVirtualLinkInfo": [
{
"id": "res_id_internalVL1",
"vnfVirtualLinkDescId": "internalVL1",
"networkResource": {
"resourceId": "res_id_internalVL1"
},
"vnfLinkPorts": [
{
"id": "res_id_VDU2_CP3",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU2_CP3",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "VDU2_CP3-res_id_VDU2",
"cpInstanceType": "VNFC_CP"
},
{
"id": "res_id_VDU1_CP3_1",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU1_CP3_1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "VDU1_CP3-res_id_VDU1_1",
"cpInstanceType": "VNFC_CP"
}
]
}
],
"extVirtualLinkInfo": _inst_info_example_1["extVirtualLinkInfo"],
"extManagedVirtualLinkInfo":
_inst_info_example_1["extManagedVirtualLinkInfo"],
"vnfcResourceInfo": [
{
"id": "res_id_VDU1_1_update",
@ -1200,9 +1140,6 @@ _inst_info_example_5 = {
"resourceId": "res_id_VDU1_1_update",
"vimLevelResourceType": "OS::Nova::Server"
},
"metadata": {
"current_vnfd_id": 'new_vnfd_id'
},
"storageResourceIds": [
"new_res_id_VirtualStorage_1"
],
@ -1233,6 +1170,10 @@ _inst_info_example_5 = {
"vnfLinkPortId": "res_id_VDU1_CP5_1"
}
],
"metadata": {
"image-VDU1-VirtualStorage": "image-VDU1-update"
# other attributes omitted
}
},
{
"id": "res_id_VDU2",
@ -1242,9 +1183,6 @@ _inst_info_example_5 = {
"resourceId": "res_id_VDU2",
"vimLevelResourceType": "OS::Nova::Server"
},
"metadata": {
"current_vnfd_id": 'new_vnfd_id'
},
"vnfcCpInfo": [
{
"id": "VDU2_CP1-res_id_VDU2",
@ -1272,72 +1210,14 @@ _inst_info_example_5 = {
"vnfLinkPortId": "res_id_VDU2_CP5"
}
],
"metadata": {
"image-VDU2": "image-VDU2-update"
# other attributes omitted
}
}
],
"vnfVirtualLinkResourceInfo": [
{
"id": "res_id_internalVL3",
"vnfVirtualLinkDescId": "internalVL3",
"networkResource": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_internalVL3",
"vimLevelResourceType": "OS::Neutron::Net"
},
"vnfLinkPorts": [
{
"id": "res_id_VDU2_CP5",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU2_CP5",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "VDU2_CP5-res_id_VDU2",
"cpInstanceType": "VNFC_CP"
},
{
"id": "res_id_VDU1_CP5_1",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU1_CP5_1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "VDU1_CP5-res_id_VDU1_1",
"cpInstanceType": "VNFC_CP"
}
]
},
{
"id": "res_id_internalVL2",
"vnfVirtualLinkDescId": "internalVL2",
"networkResource": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_internalVL2",
"vimLevelResourceType": "OS::Neutron::Net"
},
"vnfLinkPorts": [
{
"id": "res_id_VDU2_CP4",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU2_CP4",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "VDU2_CP4-res_id_VDU2",
"cpInstanceType": "VNFC_CP"
},
{
"id": "res_id_VDU1_CP4_1",
"resourceHandle": {
"vimConnectionId": "vim_connection_id",
"resourceId": "res_id_VDU1_CP4_1",
"vimLevelResourceType": "OS::Neutron::Port"
},
"cpInstanceId": "VDU1_CP4-res_id_VDU1_1",
"cpInstanceType": "VNFC_CP"
}
]
}
],
"vnfVirtualLinkResourceInfo":
_inst_info_example_1["vnfVirtualLinkResourceInfo"],
"virtualStorageResourceInfo": [
{
"id": "new_res_id_VirtualStorage_1",
@ -1348,7 +1228,7 @@ _inst_info_example_5 = {
"vimLevelResourceType": "OS::Cinder::Volume"
}
}
],
]
}
# expected results
@ -1372,7 +1252,8 @@ _expected_resource_changes_instantiate = {
],
"addedStorageResourceIds": [
"res_id_VirtualStorage_1"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
},
{
"id": "res_id_VDU2",
@ -1389,7 +1270,8 @@ _expected_resource_changes_instantiate = {
"VDU2_CP3-res_id_VDU2",
"VDU2_CP4-res_id_VDU2",
"VDU2_CP5-res_id_VDU2"
]
],
"metadata": {"image-VDU2": "image-VDU2"}
}
],
"affectedVirtualLinks": [
@ -1510,7 +1392,8 @@ _expected_resource_changes_scale_out = {
],
"addedStorageResourceIds": [
"res_id_VirtualStorage_2"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
}
],
"affectedVirtualLinks": [
@ -1608,7 +1491,8 @@ _expected_resource_changes_scale_in = {
],
"removedStorageResourceIds": [
"res_id_VirtualStorage_2"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
}
],
"affectedVirtualLinks": [
@ -1706,7 +1590,8 @@ _expected_resource_changes_terminate = {
],
"removedStorageResourceIds": [
"res_id_VirtualStorage_1"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
},
{
"id": "res_id_VDU2",
@ -1723,7 +1608,8 @@ _expected_resource_changes_terminate = {
"VDU2_CP3-res_id_VDU2",
"VDU2_CP4-res_id_VDU2",
"VDU2_CP5-res_id_VDU2"
]
],
"metadata": {"image-VDU2": "image-VDU2"}
}
],
"affectedVirtualLinks": [
@ -2017,7 +1903,8 @@ _expected_resource_changes_heal = {
"VDU1_CP3-res_id_VDU1_1",
"VDU1_CP4-res_id_VDU1_1",
"VDU1_CP5-res_id_VDU1_1"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
},
{
"id": "res_id_VDU1_1_new",
@ -2034,7 +1921,8 @@ _expected_resource_changes_heal = {
"VDU1_CP3-res_id_VDU1_1_new",
"VDU1_CP4-res_id_VDU1_1_new",
"VDU1_CP5-res_id_VDU1_1_new"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
},
{
"id": "res_id_VDU1_2",
@ -2054,7 +1942,8 @@ _expected_resource_changes_heal = {
],
"removedStorageResourceIds": [
"res_id_VirtualStorage_2"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
},
{
"id": "res_id_VDU1_2_new",
@ -2074,7 +1963,8 @@ _expected_resource_changes_heal = {
],
"addedStorageResourceIds": [
"res_id_VirtualStorage_2_new"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
},
],
"affectedVirtualLinks": [
@ -2130,6 +2020,7 @@ _expected_resource_changes_heal = {
}
]
}
_expected_resource_changes_change_vnfpkg = {
"affectedVnfcs": [
{
@ -2150,7 +2041,8 @@ _expected_resource_changes_change_vnfpkg = {
],
"removedStorageResourceIds": [
"res_id_VirtualStorage_1"
]
],
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1"}
},
{
"id": "res_id_VDU1_1_update",
@ -2171,9 +2063,7 @@ _expected_resource_changes_change_vnfpkg = {
"addedStorageResourceIds": [
"new_res_id_VirtualStorage_1"
],
'metadata': {
'current_vnfd_id': 'new_vnfd_id'
}
"metadata": {"image-VDU1-VirtualStorage": "image-VDU1-update"}
},
{
"id": "res_id_VDU2",
@ -2191,9 +2081,7 @@ _expected_resource_changes_change_vnfpkg = {
"VDU2_CP4-res_id_VDU2",
"VDU2_CP5-res_id_VDU2"
],
'metadata': {
'current_vnfd_id': 'new_vnfd_id'
}
"metadata": {"image-VDU2": "image-VDU2-update"}
}
],
"affectedVirtualStorages": [

View File

@ -709,24 +709,37 @@ _modify_vnfc_info_example = {
# change_vnfpkg example
_change_vnfpkg_example = {
"vnfdId": '61723406-6634-2fc0-060a-0b11104d2667',
"vnfdId": SAMPLE_VNFD_ID,
"additionalParams": {
"upgrade_type": "RollingUpdate",
"lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_old_vnf.py",
"lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf",
"lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_new_vnf.py",
"lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf",
"vdu_params": [{
"vdu_id": "VDU1",
"old_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
"new_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
}]
"vdu_params": [
{
"vdu_id": "VDU1",
"old_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
"new_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
},
{
"vdu_id": "VDU2",
"old_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
"new_vnfc_param": {
"cp_name": "CP1",
"username": "ubuntu",
"password": "ubuntu"},
}
]
}
}
_change_cnf_vnfpkg_example = {
@ -1826,12 +1839,12 @@ class TestVnfLcmDriverV2(base.BaseTestCase):
self.assertEqual(len(expected_res_ids[key][name]), len(ids))
@mock.patch.object(nfvo_client.NfvoClient, 'grant')
def test_change_vnfpkg_grant_update_reses(self, mocked_grant):
def test_change_vnfpkg_grant_rolling_update(self, mocked_grant):
# prepare
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfdId=uuidutils.generate_uuid(),
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
@ -1866,154 +1879,53 @@ class TestVnfLcmDriverV2(base.BaseTestCase):
expected_fixed_items = {
'vnfInstanceId': inst.id,
'vnfLcmOpOccId': lcmocc.id,
'vnfdId': '61723406-6634-2fc0-060a-0b11104d2667',
'vnfdId': inst.vnfdId,
'operation': 'CHANGE_VNFPKG',
'isAutomaticInvocation': False
'isAutomaticInvocation': False,
# change_vnfpkg specific
'dstVnfdId': SAMPLE_VNFD_ID,
'flavourId': inst.instantiatedVnfInfo.flavourId
}
for key, value in expected_fixed_items.items():
self.assertEqual(value, grant_req[key])
update_reses = grant_req['updateResources']
target_vdu_list = [
vdu_param.get(
'vdu_id') for vdu_param in req.additionalParams.get(
'vdu_params')]
for i in range(len(update_reses)):
self.assertEqual('COMPUTE', update_reses[i]['type'])
for target_vdu in target_vdu_list:
self.assertEqual(target_vdu,
update_reses[i]['resourceTemplateId'])
@mock.patch.object(nfvo_client.NfvoClient, 'grant')
def test_change_vnfpkg_grant_add_reses(self, mocked_grant):
# prepare
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED'
)
inst_info = objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_inst_info_example)
inst.instantiatedVnfInfo = inst_info
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
lcmocc = objects.VnfLcmOpOccV2(
# required fields
id=uuidutils.generate_uuid(),
operationState=fields.LcmOperationStateType.PROCESSING,
stateEnteredTime=datetime.utcnow(),
startTime=datetime.utcnow(),
vnfInstanceId=inst.id,
operation=fields.LcmOperationType.CHANGE_VNFPKG,
isAutomaticInvocation=False,
isCancelPending=False,
operationParams=req)
mocked_grant.return_value = objects.GrantV1()
# run change_vnfpkg_grant
grant_req, _ = self.driver.grant(
self.context, lcmocc, inst, self.vnfd_1)
# check grant_req is constructed according to intention
grant_req = grant_req.to_dict()
expected_fixed_items = {
'vnfInstanceId': inst.id,
'vnfLcmOpOccId': lcmocc.id,
'vnfdId': '61723406-6634-2fc0-060a-0b11104d2667',
'operation': 'CHANGE_VNFPKG',
'isAutomaticInvocation': False
# check removeResources
rm_reses = grant_req['removeResources']
check_reses = {
'COMPUTE': {'VDU1': [], 'VDU2': []},
'STORAGE': {'VirtualStorage': []}
}
for key, value in expected_fixed_items.items():
self.assertEqual(value, grant_req[key])
add_reses = grant_req['addResources']
for inst_vnc in inst_info.vnfcResourceInfo:
nodes = self.vnfd_1.get_vdu_nodes(inst_info.flavourId)
vdu_storage_names = self.vnfd_1.get_vdu_storages(
nodes[inst_vnc.vduId])
for i in range(len(add_reses)):
self.assertEqual('STORAGE', add_reses[i]['type'])
for vdu_storage_name in vdu_storage_names:
self.assertEqual(vdu_storage_name,
add_reses[i]['resourceTemplateId'])
@mock.patch.object(nfvo_client.NfvoClient, 'grant')
def test_change_vnfpkg_grant_remove_reses(self, mocked_grant):
# prepare
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED'
)
inst_info = objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_inst_info_example)
inst.instantiatedVnfInfo = inst_info
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
lcmocc = objects.VnfLcmOpOccV2(
# required fields
id=uuidutils.generate_uuid(),
operationState=fields.LcmOperationStateType.PROCESSING,
stateEnteredTime=datetime.utcnow(),
startTime=datetime.utcnow(),
vnfInstanceId=inst.id,
operation=fields.LcmOperationType.CHANGE_VNFPKG,
isAutomaticInvocation=False,
isCancelPending=False,
operationParams=req)
mocked_grant.return_value = objects.GrantV1()
# run change_vnfpkg_grant
grant_req, _ = self.driver.grant(
self.context, lcmocc, inst, self.vnfd_1)
# check grant_req is constructed according to intention
grant_req = grant_req.to_dict()
expected_fixed_items = {
'vnfInstanceId': inst.id,
'vnfLcmOpOccId': lcmocc.id,
'vnfdId': '61723406-6634-2fc0-060a-0b11104d2667',
'operation': 'CHANGE_VNFPKG',
'isAutomaticInvocation': False
}
for key, value in expected_fixed_items.items():
self.assertEqual(value, grant_req[key])
remove_reses = grant_req['removeResources']
inst_stor_info = inst_info.virtualStorageResourceInfo
check_reses = []
for str_info in inst_stor_info:
check_res = {
'resourceId': str_info.storageResource.resourceId,
'vimLevelResourceType':
str_info.storageResource.vimLevelResourceType
expected_res_ids = {
'COMPUTE': {
'VDU1': ['res_id_VDU1_1', 'res_id_VDU1_2'],
'VDU2': ['res_id_VDU2']
},
'STORAGE': {
'VirtualStorage': ['res_id_VirtualStorage_1',
'res_id_VirtualStorage_2']
}
check_reses.append(check_res)
for i in range(len(remove_reses)):
self.assertEqual('STORAGE', remove_reses[i]['type'])
self.assertEqual(str_info.virtualStorageDescId,
remove_reses[i]['resourceTemplateId'])
for j in range(len(check_reses)):
for k in range(len(remove_reses)):
if j == k:
self.assertEqual(
check_reses[j]['resourceId'],
remove_reses[j]['resource']['resourceId'])
self.assertEqual(
check_reses[j]['vimLevelResourceType'],
remove_reses[j]['resource']['vimLevelResourceType'])
}
for res in rm_reses:
check_reses[res['type']][res['resourceTemplateId']].append(
res['resource']['resourceId'])
for key, value in check_reses.items():
for name, ids in value.items():
self.assertEqual(expected_res_ids[key][name], ids)
# check addResources
add_reses = grant_req['addResources']
check_reses = {
'COMPUTE': {'VDU1': [], 'VDU2': []},
'STORAGE': {'VirtualStorage': []},
}
for res in add_reses:
check_reses[res['type']][res['resourceTemplateId']].append(
res['id'])
for key, value in check_reses.items():
for name, ids in value.items():
self.assertEqual(len(expected_res_ids[key][name]), len(ids))
@mock.patch.object(nfvo_client.NfvoClient, 'grant')
def test_cnf_instantiate_grant(self, mocked_grant):
@ -2169,7 +2081,8 @@ class TestVnfLcmDriverV2(base.BaseTestCase):
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_cnf_vnfpkg_example)
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.CHANGE_VNFPKG
operation=fields.LcmOperationType.CHANGE_VNFPKG,
dstVnfdId=_change_cnf_vnfpkg_example['vnfdId']
)
grant = objects.GrantV1()
lcmocc = objects.VnfLcmOpOccV2(

View File

@ -273,7 +273,7 @@ class TestVnflcmV2(db_base.SqlTestCase):
ex = self.assertRaises(sol_ex.InvalidSubscription,
self.controller.subscription_create, request=self.request,
body=body)
self.assertEqual("ParmasBasic must be specified.", ex.detail)
self.assertEqual("ParamsBasic must be specified.", ex.detail)
body = {
"callbackUri": "http://127.0.0.1:6789/notification",

View File

@ -14,19 +14,15 @@
# under the License.
import copy
import json
import os
import requests
import subprocess
from datetime import datetime
from oslo_utils import uuidutils
from unittest import mock
from tacker import context
from tacker.sol_refactored.common import vnfd_utils
from tacker.sol_refactored.infra_drivers.openstack import heat_utils
from tacker.sol_refactored.infra_drivers.openstack import openstack
from tacker.sol_refactored.nfvo import glance_utils
from tacker.sol_refactored import objects
from tacker.sol_refactored.objects.v2 import fields
from tacker.tests import base
@ -857,6 +853,36 @@ _heat_reses_example = (
_heat_reses_example_change_ext_conn = (
_heat_reses_example_base + _heat_reses_example_cps_after)
# heat get_parameters example
_nfv_dict = {
"VDU": {
"VDU1": {"computeFlavourId": "m1.tiny"},
"VDU1-VirtualStorage": {"vcImageId": "image-VDU1"},
"VDU2": {"vcImageId": "image-VDU2", "computeFlavourId": "m1.small"}
}
}
_heat_get_parameters_example = {
'nfv': json.dumps(_nfv_dict)
}
# heat get_template example
_heat_get_template_example = {
"resources": {
"myet4efobvvp": {
"properties": {
"flavor": "m1.tiny",
"image-VDU1-VirtualStorage": "image-VDU1"
}
},
"bemybz4ugeso": {
"properties": {
"flavor": "m1.tiny",
"image-VDU1-VirtualStorage": "image-VDU1"
}
}
}
}
# change vnfpkg before inst info
_inst_info_example = {
"flavourId": "simple",
@ -1571,7 +1597,9 @@ _expected_inst_info = {
"creation_time": "2021-12-10T01:03:49Z",
"parent_stack_id": _stack_id_VDU1_scale,
"parent_resource_name": "myet4efobvvp",
"stack_id": _stack_id_VDU1_2
"stack_id": _stack_id_VDU1_2,
"flavor": "m1.tiny",
"image-VDU1-VirtualStorage": "image-VDU1"
}
},
{
@ -1616,7 +1644,9 @@ _expected_inst_info = {
"creation_time": "2021-12-10T00:41:43Z",
"parent_stack_id": _stack_id_VDU1_scale,
"parent_resource_name": "bemybz4ugeso",
"stack_id": _stack_id_VDU1_1
"stack_id": _stack_id_VDU1_1,
"flavor": "m1.tiny",
"image-VDU1-VirtualStorage": "image-VDU1"
}
},
{
@ -1657,7 +1687,9 @@ _expected_inst_info = {
],
"metadata": {
"creation_time": "2021-12-10T00:40:46Z",
"stack_id": _stack_id
"stack_id": _stack_id,
"flavor": "m1.small",
"image-VDU2": "image-VDU2"
}
}
],
@ -2126,7 +2158,9 @@ _expected_inst_info_change_ext_conn = {
"creation_time": "2021-12-10T01:03:49Z",
"parent_stack_id": _stack_id_VDU1_scale,
"parent_resource_name": "myet4efobvvp",
"stack_id": _stack_id_VDU1_2
"stack_id": _stack_id_VDU1_2,
"flavor": "m1.tiny",
"image-VDU1-VirtualStorage": "image-VDU1"
}
},
{
@ -2171,7 +2205,9 @@ _expected_inst_info_change_ext_conn = {
"creation_time": "2021-12-10T00:41:43Z",
"parent_stack_id": _stack_id_VDU1_scale,
"parent_resource_name": "bemybz4ugeso",
"stack_id": _stack_id_VDU1_1
"stack_id": _stack_id_VDU1_1,
"flavor": "m1.tiny",
"image-VDU1-VirtualStorage": "image-VDU1"
}
},
{
@ -2212,7 +2248,9 @@ _expected_inst_info_change_ext_conn = {
],
"metadata": {
"creation_time": "2021-12-10T00:40:46Z",
"stack_id": _stack_id
"stack_id": _stack_id,
"flavor": "m1.small",
"image-VDU2": "image-VDU2"
}
}
],
@ -2684,6 +2722,7 @@ class TestOpenstack(base.BaseTestCase):
req = objects.InstantiateVnfRequest.from_dict(
_instantiate_req_example)
inst = objects.VnfInstanceV2(
id=uuidutils.generate_uuid(),
vimConnectionInfo=req.vimConnectionInfo
)
grant_req = objects.GrantRequestV1(
@ -2691,9 +2730,15 @@ class TestOpenstack(base.BaseTestCase):
)
grant = objects.GrantV1()
# 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_template.return_value = _heat_get_template_example
# execute make_instantiated_vnf_info
self.driver._make_instantiated_vnf_info(req, inst, grant_req, grant,
self.vnfd_1, _heat_reses_example)
self.vnfd_1, heat_client)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
@ -2709,6 +2754,7 @@ class TestOpenstack(base.BaseTestCase):
_vim_connection_info_example)
}
inst = objects.VnfInstanceV2(
id=uuidutils.generate_uuid(),
instantiatedVnfInfo=inst_info,
vimConnectionInfo=vim_info
)
@ -2717,9 +2763,15 @@ class TestOpenstack(base.BaseTestCase):
)
grant = objects.GrantV1()
# 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_template.return_value = _heat_get_template_example
# execute make_instantiated_vnf_info
self.driver._make_instantiated_vnf_info(req, inst, grant_req, grant,
self.vnfd_1, _heat_reses_example)
self.vnfd_1, heat_client)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
@ -2736,6 +2788,7 @@ class TestOpenstack(base.BaseTestCase):
_vim_connection_info_example)
}
inst = objects.VnfInstanceV2(
id=uuidutils.generate_uuid(),
instantiatedVnfInfo=inst_info,
vimConnectionInfo=vim_info
)
@ -2744,402 +2797,17 @@ class TestOpenstack(base.BaseTestCase):
)
grant = objects.GrantV1()
# prepare heat responses
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_template.return_value = _heat_get_template_example
# execute make_instantiated_vnf_info
self.driver._make_instantiated_vnf_info(req, inst, grant_req, grant,
self.vnfd_1, _heat_reses_example_change_ext_conn)
self.vnfd_1, heat_client)
# check
result = inst.to_dict()["instantiatedVnfInfo"]
self._check_inst_info(_expected_inst_info_change_ext_conn, result)
@mock.patch.object(heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(subprocess, 'run')
@mock.patch.object(glance_utils.GlanceClient, 'get_image')
@mock.patch.object(heat_utils.HeatClient, 'update_stack')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_list')
@mock.patch.object(heat_utils.HeatClient, 'get_template')
@mock.patch.object(heat_utils.HeatClient, 'get_resources')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_info')
@mock.patch.object(heat_utils.HeatClient, 'get_stack_resource')
def test_change_vnfpkg_404(
self, mocked_get_stack_resource, mocked_get_resource_info,
mocked_get_resources, mocked_get_template,
mocked_get_resource_list, mocked_update_stack,
mocked_get_image, mocked_run, mocked_get_parameters):
# prepare
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
inst_info = objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_inst_info_example)
vim_info = {
"vim1": objects.VimConnectionInfo.from_dict(
_vim_connection_info_for_change_vnfpkg)
}
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED'
)
inst.vimConnectionInfo = vim_info
inst.instantiatedVnfInfo = inst_info
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.CHANGE_VNFPKG
)
grant = objects.GrantV1()
stack_body = {'stack': {'id': uuidutils.generate_uuid(),
'name': 'test'}}
stack_body_2 = {'stack': {
'stack_name':
'vnf-d8962b72-6dac-4eb5-a8c4-8c7a2abaefb7-VDU1_scale_group'}}
mocked_get_stack_resource.side_effect = [stack_body, stack_body_2]
body_2 = {"attributes": {"floating_ip_address": "192.168.0.1"}}
body_3 = {"attributes": {
"image": {"id": "image-1.0.0-x86_64-disk"},
"flavor": {"original_name": "m1.tiny"}
}
}
mocked_get_resource_info.side_effect = [None,
body_2, body_3]
mocked_get_resources.side_effect = [mock_resource['resources'],
_heat_reses_example]
mocked_get_template.return_value = mock_resource_template
mocked_get_resource_list.side_effect = [mock_resource_list,
mock_resource_list_2]
mocked_update_stack.return_value = mock.Mock()
resp_image = requests.Response()
resp_image.name = "image-1.0.0-x86_64-disk"
mocked_get_image.return_value = resp_image
out = requests.Response()
out.returncode = 0
mocked_run.return_value = out
parameter = {
'nfv': '{"VDU":{"VDU1":{"vcImageId":""},'
'"VDU2":{"vcImageId":""},'
'"VirtualStorage":{"vcImageId":""}}}'
}
mocked_get_parameters.return_value = parameter
# execute change_vnfpkg
self.driver.change_vnfpkg(req, inst, grant_req, grant,
self.vnfd_1)
# check
for vnfc_res in inst.instantiatedVnfInfo.vnfcResourceInfo:
if vnfc_res.vduId == "VDU1":
self.assertEqual(vnfc_res.id,
'e79ebeaf-1b26-4ff9-9895-f4c78a8a39a6')
self.assertEqual(vnfc_res.computeResource.resourceId,
'e79ebeaf-1b26-4ff9-9895-f4c78a8a39a6')
self.assertIn('current_vnfd_id', vnfc_res.metadata)
@mock.patch.object(heat_utils.HeatClient, 'get_resources')
@mock.patch.object(subprocess, 'run')
@mock.patch.object(glance_utils.GlanceClient, 'get_image')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_list')
@mock.patch.object(heat_utils.HeatClient, 'update_stack')
@mock.patch.object(heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(heat_utils.HeatClient, 'get_template')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_info')
@mock.patch.object(heat_utils.HeatClient, 'get_stack_resource')
def test_change_vnfpkg_200(
self, mocked_get_stack_resource, mocked_get_resource_info,
mocked_get_template, mocked_get_parameters,
mocked_update_stack, mocked_get_resource_list, mocked_get_image,
mocked_run, mocked_get_resources):
# prepare
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example_2)
inst_info = objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_inst_info_example)
vim_info = {
"vim1": objects.VimConnectionInfo.from_dict(
_vim_connection_info_for_change_vnfpkg)
}
inst = objects.VnfInstanceV2(
# required fields
id="d7aeba20-1b00-4bff-b050-6b42a262c84d",
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED'
)
inst.vimConnectionInfo = vim_info
inst.instantiatedVnfInfo = inst_info
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.CHANGE_VNFPKG
)
grant = objects.GrantV1()
stack_body = {'stack': {'id': "d7aeba20-1b00-4bff-b050-6b42a262c84d",
'name': 'test'}}
stack_body_2 = {'stack': {
'stack_name':
'vnf-d8962b72-6dac-4eb5-a8c4-8c7a2abaefb7-VDU1_scale_group'}}
mocked_get_stack_resource.side_effect = [stack_body, stack_body_2]
body = {"resource": "resource"}
body_2 = {"attributes": {"floating_ip_address": "192.168.0.1"}}
body_3 = {"attributes": {
"image": {"id": "image-1.0.0-x86_64-disk"},
"flavor": {"original_name": "m1.tiny"}
}
}
mocked_get_resource_info.side_effect = [body['resource'], body_2,
body_3]
mocked_get_resources.side_effect = [mock_resource['resources'],
_heat_reses_example]
mocked_get_template.return_value = mock_resource_template_2
mocked_get_resource_list.return_value = mock_resource_list_3
mocked_update_stack.return_value = mock.Mock()
resp_image = requests.Response()
resp_image.name = "image-1.0.0-x86_64-disk"
mocked_get_image.return_value = resp_image
out = requests.Response()
out.returncode = 0
mocked_run.return_value = out
parameter = {
'nfv': '{"VDU":{"VDU1":{"vcImageId":""},'
'"VDU2":{"vcImageId":""},'
'"VirtualStorage":{"vcImageId":""}}}'
}
mocked_get_parameters.return_value = parameter
# execute change_vnfpkg
self.driver.change_vnfpkg(req, inst, grant_req, grant,
self.vnfd_1)
# check
for vnfc_res in inst.instantiatedVnfInfo.vnfcResourceInfo:
if vnfc_res.vduId == "VDU2":
self.assertEqual(vnfc_res.id,
'res_id_VDU2_1')
self.assertEqual(vnfc_res.computeResource.resourceId,
'res_id_VDU2_1')
self.assertIn('current_vnfd_id', vnfc_res.metadata)
@mock.patch.object(heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(subprocess, 'run')
@mock.patch.object(glance_utils.GlanceClient, 'get_image')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_info')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_list')
@mock.patch.object(heat_utils.HeatClient, 'update_stack')
@mock.patch.object(heat_utils.HeatClient, 'get_template')
@mock.patch.object(heat_utils.HeatClient, 'get_resources')
@mock.patch.object(heat_utils.HeatClient, 'get_stack_resource')
def test_change_vnfpkg_rollback(
self, mocked_get_stack_resource, mocked_get_resources,
mocked_get_template, mocked_update_stack,
mocked_get_resource_list, mocked_get_resource_info,
mocked_get_image, mocked_run, mocked_get_parameters):
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example)
inst_info = objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_inst_info_example)
vim_info = {
"vim1": objects.VimConnectionInfo.from_dict(
_vim_connection_info_for_change_vnfpkg)
}
inst = objects.VnfInstanceV2(
# required fields
id=uuidutils.generate_uuid(),
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED'
)
inst.vimConnectionInfo = vim_info
inst.instantiatedVnfInfo = inst_info
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.CHANGE_VNFPKG
)
grant = objects.GrantV1()
affected_vnfcs = objects.AffectedVnfcV2(
id=uuidutils.generate_uuid(),
vduId='VDU1',
vnfdId=SAMPLE_VNFD_ID,
changeType='ADDED',
metadata={
"creation_time": "2021-12-10T01:03:49Z",
"stack_id": "vnf-d8962b72-6dac-4eb5-a8c4-8c7a2abaefb7-"
"VDU1_scale_group-2zmsxtwtsj7n-"
"fkwryhyv6qbr-qoemdwxw7o5c/"
"d7aeba20-1b00-4bff-b050-6b42a262c84d",
"parent_resource_name": "fkwryhyv6qbr"
}
)
resource_change = objects.VnfLcmOpOccV2_ResourceChanges(
affectedVnfcs=[affected_vnfcs]
)
lcmocc = objects.VnfLcmOpOccV2(
# required fields
id=uuidutils.generate_uuid(),
operationState=fields.LcmOperationStateType.FAILED_TEMP,
stateEnteredTime=datetime.utcnow(),
startTime=datetime.utcnow(),
vnfInstanceId=inst.id,
operation=fields.LcmOperationType.CHANGE_VNFPKG,
resourceChanges=resource_change,
isAutomaticInvocation=False,
isCancelPending=False,
operationParams=req)
stack_body = {'stack': {'id': uuidutils.generate_uuid(),
'name': 'test'}}
stack_body_2 = {'stack': {
'stack_name':
'vnf-d8962b72-6dac-4eb5-a8c4-8c7a2abaefb7-VDU1_scale_group'}}
mocked_get_stack_resource.side_effect = [stack_body, stack_body_2]
body = {"attributes": {"floating_ip_address": "192.168.0.1"}}
body_2 = {"attributes": {
"image": {"id": "image-1.0.0-x86_64-disk"},
"flavor": {"original_name": "m1.tiny"}
}
}
mocked_get_resource_info.side_effect = [body, body_2]
mocked_get_resources.side_effect = [mock_resource['resources'],
_heat_reses_example]
mocked_get_template.return_value = mock_resource_template
mocked_get_resource_list.return_value = mock_resource_list_2
mocked_update_stack.return_value = mock.Mock()
resp_image = requests.Response()
resp_image.name = "image-1.0.0-x86_64-disk"
mocked_get_image.return_value = resp_image
out = requests.Response()
out.returncode = 0
mocked_run.return_value = out
parameter = {
'nfv': '{"VDU":{"VDU1":{"vcImageId":""},'
'"VDU2":{"vcImageId":""},'
'"VirtualStorage":{"vcImageId":""}}}'
}
mocked_get_parameters.return_value = parameter
self.driver.change_vnfpkg_rollback(req, inst, grant_req, grant,
self.vnfd_1, lcmocc)
# check
for vnfc_res in inst.instantiatedVnfInfo.vnfcResourceInfo:
if vnfc_res.vduId == "VDU1":
self.assertEqual(vnfc_res.id,
'e79ebeaf-1b26-4ff9-9895-f4c78a8a39a6')
self.assertEqual(vnfc_res.computeResource.resourceId,
'e79ebeaf-1b26-4ff9-9895-f4c78a8a39a6')
self.assertIn('current_vnfd_id', vnfc_res.metadata)
@mock.patch.object(heat_utils.HeatClient, 'get_resources')
@mock.patch.object(subprocess, 'run')
@mock.patch.object(glance_utils.GlanceClient, 'get_image')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_info')
@mock.patch.object(heat_utils.HeatClient, 'get_resource_list')
@mock.patch.object(heat_utils.HeatClient, 'update_stack')
@mock.patch.object(heat_utils.HeatClient, 'get_parameters')
@mock.patch.object(heat_utils.HeatClient, 'get_template')
@mock.patch.object(heat_utils.HeatClient, 'get_stack_resource')
def test_change_vnfpkg_rollback_same(
self, mocked_get_stack_resource, mocked_get_template,
mocked_get_parameters, mocked_update_stack,
mocked_get_resource_list, mocked_get_resource_info,
mocked_get_image, mocked_run, mocked_get_resources):
req = objects.ChangeCurrentVnfPkgRequest.from_dict(
_change_vnfpkg_example_2)
inst_info = objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict(
_inst_info_example)
vim_info = {
"vim1": objects.VimConnectionInfo.from_dict(
_vim_connection_info_for_change_vnfpkg)
}
inst = objects.VnfInstanceV2(
# required fields
id="d7aeba20-1b00-4bff-b050-6b42a262c84d",
vnfdId=SAMPLE_VNFD_ID,
vnfProvider='provider',
vnfProductName='product name',
vnfSoftwareVersion='software version',
vnfdVersion='vnfd version',
instantiationState='INSTANTIATED'
)
inst.vimConnectionInfo = vim_info
inst.instantiatedVnfInfo = inst_info
grant_req = objects.GrantRequestV1(
operation=fields.LcmOperationType.CHANGE_VNFPKG
)
grant = objects.GrantV1()
affected_vnfcs = objects.AffectedVnfcV2(
id=uuidutils.generate_uuid(),
vduId='VDU2',
vnfdId=SAMPLE_VNFD_ID,
changeType='MODIFIED',
metadata={
"creation_time": "2021-12-10T01:03:49Z",
"stack_id": 'vnf-d7aeba20-1b00-4bff-b050-6b42a262c84d/'
'd7aeba20-1b00-4bff-b050-6b42a262c84d'
}
)
resource_change = objects.VnfLcmOpOccV2_ResourceChanges(
affectedVnfcs=[affected_vnfcs]
)
lcmocc = objects.VnfLcmOpOccV2(
# required fields
id=uuidutils.generate_uuid(),
operationState=fields.LcmOperationStateType.FAILED_TEMP,
stateEnteredTime=datetime.utcnow(),
startTime=datetime.utcnow(),
vnfInstanceId=inst.id,
operation=fields.LcmOperationType.CHANGE_VNFPKG,
resourceChanges=resource_change,
isAutomaticInvocation=False,
isCancelPending=False,
operationParams=req)
stack_body = {'stack': {'id': 'd7aeba20-1b00-4bff-b050-6b42a262c84d',
'name': 'test'}}
stack_body_2 = {'stack': {
'stack_name':
'vnf-d7aeba20-1b00-4bff-b050-6b42a262c84d-VDU1_scale_group'}}
mocked_get_stack_resource.side_effect = [stack_body, stack_body_2]
body = {"attributes": {"floating_ip_address": "192.168.0.1"}}
body_2 = {"attributes": {
"image": {
"id": "image-1.0.0-x86_64-disk"},
"flavor": {"original_name": "m1.tiny"}
}
}
mocked_get_resource_info.side_effect = [body, body_2]
mocked_get_resources.side_effect = [mock_resource['resources'],
_heat_reses_example]
mocked_get_template.return_value = mock_resource_template_3
mocked_get_resource_list.return_value = mock_resource_list_3
mocked_update_stack.return_value = mock.Mock()
resp_image = requests.Response()
resp_image.name = "image-1.0.0-x86_64-disk"
mocked_get_image.return_value = resp_image
out = requests.Response()
out.returncode = 0
mocked_run.return_value = out
parameter = {
'nfv': '{"VDU":{"VDU1":{"vcImageId":""},'
'"VDU2":{"vcImageId":""},'
'"VirtualStorage":{"vcImageId":""}}}'
}
mocked_get_parameters.return_value = parameter
self.driver.change_vnfpkg_rollback(req, inst, grant_req, grant,
self.vnfd_1, lcmocc)
# check
for vnfc_res in inst.instantiatedVnfInfo.vnfcResourceInfo:
if vnfc_res.vduId == "VDU2":
self.assertEqual(vnfc_res.id,
'res_id_VDU2_1')
self.assertEqual(vnfc_res.computeResource.resourceId,
'res_id_VDU2_1')
self.assertIn('current_vnfd_id', vnfc_res.metadata)