Merge "Support individual VNFc management using HOT"
This commit is contained in:
commit
213f5f59ba
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Support individual VNFC management using OpenStack Heat.
|
||||||
|
New sample BaseHOT, corresponding UserData script,
|
||||||
|
and utility functions are added to UserData class
|
||||||
|
for v2 VNF Lifecycle management API.
|
|
@ -94,7 +94,7 @@ class HeatClient(object):
|
||||||
LOG.info("%s %s done.", operation, stack_name)
|
LOG.info("%s %s done.", operation, stack_name)
|
||||||
raise loopingcall.LoopingCallDone()
|
raise loopingcall.LoopingCallDone()
|
||||||
elif status in failed_status:
|
elif status in failed_status:
|
||||||
LOG.error("% %s failed.", operation, stack_name)
|
LOG.error("%s %s failed.", operation, stack_name)
|
||||||
sol_title = "%s failed" % operation
|
sol_title = "%s failed" % operation
|
||||||
raise sol_ex.StackOperationFailed(sol_title=sol_title,
|
raise sol_ex.StackOperationFailed(sol_title=sol_title,
|
||||||
sol_detail=status_reason)
|
sol_detail=status_reason)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import json
|
||||||
import os
|
import os
|
||||||
import pickle
|
import pickle
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import yaml
|
||||||
|
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
import eventlet
|
import eventlet
|
||||||
|
@ -67,6 +68,19 @@ def _make_combination_id(a, b):
|
||||||
return '{}-{}'.format(a, b)
|
return '{}-{}'.format(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_vdu_idx(vdu_with_idx):
|
||||||
|
part = vdu_with_idx.rpartition('-')
|
||||||
|
if part[1] == '':
|
||||||
|
return None
|
||||||
|
return int(part[2])
|
||||||
|
|
||||||
|
|
||||||
|
def _vdu_with_idx(vdu, vdu_idx):
|
||||||
|
if vdu_idx is None:
|
||||||
|
return vdu
|
||||||
|
return f'{vdu}-{vdu_idx}'
|
||||||
|
|
||||||
|
|
||||||
class Openstack(object):
|
class Openstack(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -75,7 +89,6 @@ class Openstack(object):
|
||||||
def instantiate(self, req, inst, grant_req, grant, vnfd):
|
def instantiate(self, req, inst, grant_req, grant, vnfd):
|
||||||
# make HOT
|
# make HOT
|
||||||
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
|
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
|
||||||
LOG.debug("stack fields: %s", fields)
|
|
||||||
|
|
||||||
# create or update stack
|
# create or update stack
|
||||||
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
|
@ -113,21 +126,27 @@ class Openstack(object):
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
heat_client.delete_stack(stack_name)
|
heat_client.delete_stack(stack_name)
|
||||||
|
|
||||||
def _update_nfv_dict(self, heat_client, stack_name, fields):
|
def _update_fields(self, heat_client, stack_name, fields):
|
||||||
parameters = heat_client.get_parameters(stack_name)
|
if 'nfv' in fields.get('parameters', {}):
|
||||||
LOG.debug("ORIG parameters: %s", parameters)
|
parameters = heat_client.get_parameters(stack_name)
|
||||||
# NOTE: parameters['nfv'] is string
|
LOG.debug("ORIG parameters: %s", parameters)
|
||||||
orig_nfv_dict = json.loads(parameters.get('nfv', '{}'))
|
# NOTE: parameters['nfv'] is string
|
||||||
if 'nfv' in fields['parameters']:
|
orig_nfv_dict = json.loads(parameters.get('nfv', '{}'))
|
||||||
fields['parameters']['nfv'] = inst_utils.json_merge_patch(
|
fields['parameters']['nfv'] = inst_utils.json_merge_patch(
|
||||||
orig_nfv_dict, fields['parameters']['nfv'])
|
orig_nfv_dict, fields['parameters']['nfv'])
|
||||||
LOG.debug("NEW parameters: %s", fields['parameters'])
|
|
||||||
|
if 'template' in fields:
|
||||||
|
orig_template = heat_client.get_template(stack_name)
|
||||||
|
template = inst_utils.json_merge_patch(
|
||||||
|
orig_template, yaml.safe_load(fields['template']))
|
||||||
|
fields['template'] = yaml.safe_dump(template)
|
||||||
|
|
||||||
|
LOG.debug("NEW fields: %s", fields)
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def scale(self, req, inst, grant_req, grant, vnfd):
|
def scale(self, req, inst, grant_req, grant, vnfd):
|
||||||
# make HOT
|
# make HOT
|
||||||
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
|
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)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
heat_client = heat_utils.HeatClient(vim_info)
|
heat_client = heat_utils.HeatClient(vim_info)
|
||||||
|
@ -139,17 +158,19 @@ class Openstack(object):
|
||||||
if res_def.type == 'COMPUTE']
|
if res_def.type == 'COMPUTE']
|
||||||
for vnfc in inst.instantiatedVnfInfo.vnfcResourceInfo:
|
for vnfc in inst.instantiatedVnfInfo.vnfcResourceInfo:
|
||||||
if vnfc.computeResource.resourceId in vnfc_res_ids:
|
if vnfc.computeResource.resourceId in vnfc_res_ids:
|
||||||
if 'parent_stack_id' not in vnfc.metadata:
|
if 'parent_stack_id' in vnfc.metadata:
|
||||||
|
# AutoScalingGroup
|
||||||
|
heat_client.mark_unhealthy(
|
||||||
|
vnfc.metadata['parent_stack_id'],
|
||||||
|
vnfc.metadata['parent_resource_name'])
|
||||||
|
elif 'vdu_idx' not in vnfc.metadata:
|
||||||
# It means definition of VDU in the BaseHOT
|
# It means definition of VDU in the BaseHOT
|
||||||
# is inappropriate.
|
# is inappropriate.
|
||||||
raise sol_ex.UnexpectedParentResourceDefinition()
|
raise sol_ex.UnexpectedParentResourceDefinition()
|
||||||
heat_client.mark_unhealthy(
|
|
||||||
vnfc.metadata['parent_stack_id'],
|
|
||||||
vnfc.metadata['parent_resource_name'])
|
|
||||||
|
|
||||||
# update stack
|
# update stack
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
fields = self._update_nfv_dict(heat_client, stack_name, fields)
|
fields = self._update_fields(heat_client, stack_name, fields)
|
||||||
heat_client.update_stack(stack_name, fields)
|
heat_client.update_stack(stack_name, fields)
|
||||||
|
|
||||||
# make instantiated_vnf_info
|
# make instantiated_vnf_info
|
||||||
|
@ -158,6 +179,10 @@ class Openstack(object):
|
||||||
|
|
||||||
def scale_rollback(self, req, inst, grant_req, grant, vnfd):
|
def scale_rollback(self, req, inst, grant_req, grant, vnfd):
|
||||||
# NOTE: rollback is supported for scale out only
|
# NOTE: rollback is supported for scale out only
|
||||||
|
# make HOT
|
||||||
|
fields = self._make_hot(req, inst, grant_req, grant, vnfd,
|
||||||
|
is_rollback=True)
|
||||||
|
|
||||||
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
heat_client = heat_utils.HeatClient(vim_info)
|
heat_client = heat_utils.HeatClient(vim_info)
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
|
@ -169,19 +194,18 @@ class Openstack(object):
|
||||||
for res in heat_utils.get_server_reses(heat_reses):
|
for res in heat_utils.get_server_reses(heat_reses):
|
||||||
if res['physical_resource_id'] not in vnfc_ids:
|
if res['physical_resource_id'] not in vnfc_ids:
|
||||||
metadata = self._make_vnfc_metadata(res, heat_reses)
|
metadata = self._make_vnfc_metadata(res, heat_reses)
|
||||||
if 'parent_stack_id' not in metadata:
|
if 'parent_stack_id' in metadata:
|
||||||
|
# AutoScalingGroup
|
||||||
|
heat_client.mark_unhealthy(
|
||||||
|
metadata['parent_stack_id'],
|
||||||
|
metadata['parent_resource_name'])
|
||||||
|
elif 'vdu_idx' not in metadata:
|
||||||
# It means definition of VDU in the BaseHOT
|
# It means definition of VDU in the BaseHOT
|
||||||
# is inappropriate.
|
# is inappropriate.
|
||||||
raise sol_ex.UnexpectedParentResourceDefinition()
|
raise sol_ex.UnexpectedParentResourceDefinition()
|
||||||
heat_client.mark_unhealthy(
|
|
||||||
metadata['parent_stack_id'],
|
|
||||||
metadata['parent_resource_name'])
|
|
||||||
|
|
||||||
# update (put back) 'desired_capacity' parameter
|
# update (put back) 'desired_capacity' parameter
|
||||||
fields = self._update_nfv_dict(heat_client, stack_name,
|
fields = self._update_fields(heat_client, stack_name, fields)
|
||||||
userdata_default.DefaultUserData.scale_rollback(
|
|
||||||
req, inst, grant_req, grant, vnfd.csar_dir))
|
|
||||||
|
|
||||||
heat_client.update_stack(stack_name, fields)
|
heat_client.update_stack(stack_name, fields)
|
||||||
|
|
||||||
# NOTE: instantiatedVnfInfo is not necessary to update since it
|
# NOTE: instantiatedVnfInfo is not necessary to update since it
|
||||||
|
@ -190,13 +214,12 @@ class Openstack(object):
|
||||||
def change_ext_conn(self, req, inst, grant_req, grant, vnfd):
|
def change_ext_conn(self, req, inst, grant_req, grant, vnfd):
|
||||||
# make HOT
|
# make HOT
|
||||||
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
|
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
|
||||||
LOG.debug("stack fields: %s", fields)
|
|
||||||
|
|
||||||
# update stack
|
# update stack
|
||||||
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
heat_client = heat_utils.HeatClient(vim_info)
|
heat_client = heat_utils.HeatClient(vim_info)
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
fields = self._update_nfv_dict(heat_client, stack_name, fields)
|
fields = self._update_fields(heat_client, stack_name, fields)
|
||||||
heat_client.update_stack(stack_name, fields)
|
heat_client.update_stack(stack_name, fields)
|
||||||
|
|
||||||
# make instantiated_vnf_info
|
# make instantiated_vnf_info
|
||||||
|
@ -204,31 +227,33 @@ class Openstack(object):
|
||||||
heat_client)
|
heat_client)
|
||||||
|
|
||||||
def change_ext_conn_rollback(self, req, inst, grant_req, grant, vnfd):
|
def change_ext_conn_rollback(self, req, inst, grant_req, grant, vnfd):
|
||||||
|
# make HOT
|
||||||
|
fields = self._make_hot(req, inst, grant_req, grant, vnfd,
|
||||||
|
is_rollback=True)
|
||||||
|
|
||||||
|
# update stack
|
||||||
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
heat_client = heat_utils.HeatClient(vim_info)
|
heat_client = heat_utils.HeatClient(vim_info)
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
fields = self._update_nfv_dict(heat_client, stack_name,
|
fields = self._update_fields(heat_client, stack_name, fields)
|
||||||
userdata_default.DefaultUserData.change_ext_conn_rollback(
|
|
||||||
req, inst, grant_req, grant, vnfd.csar_dir))
|
|
||||||
heat_client.update_stack(stack_name, fields)
|
heat_client.update_stack(stack_name, fields)
|
||||||
|
|
||||||
# NOTE: it is necessary to re-create instantiatedVnfInfo because
|
# NOTE: it is necessary to re-create instantiatedVnfInfo because
|
||||||
# ports may be changed.
|
# ports may be changed.
|
||||||
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
|
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
|
||||||
heat_client)
|
heat_client, is_rollback=True)
|
||||||
|
|
||||||
def heal(self, req, inst, grant_req, grant, vnfd):
|
def heal(self, req, inst, grant_req, grant, vnfd):
|
||||||
# make HOT
|
# make HOT
|
||||||
# NOTE: _make_hot() is called as other operations, but it returns
|
# NOTE: _make_hot() is called as other operations, but it returns
|
||||||
# empty 'nfv' dict by default. Therefore _update_nfv_dict() returns
|
# empty 'nfv' dict by default. Therefore _update_fields() returns
|
||||||
# current heat parameters as is.
|
# current heat parameters as is.
|
||||||
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
|
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)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
heat_client = heat_utils.HeatClient(vim_info)
|
heat_client = heat_utils.HeatClient(vim_info)
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
fields = self._update_nfv_dict(heat_client, stack_name, fields)
|
fields = self._update_fields(heat_client, stack_name, fields)
|
||||||
|
|
||||||
# "re_create" is set to True only when SOL003 heal(without
|
# "re_create" is set to True only when SOL003 heal(without
|
||||||
# vnfcInstanceId) and "all=True" in additionalParams.
|
# vnfcInstanceId) and "all=True" in additionalParams.
|
||||||
|
@ -284,7 +309,6 @@ class Openstack(object):
|
||||||
def change_vnfpkg(self, req, inst, grant_req, grant, vnfd):
|
def change_vnfpkg(self, req, inst, grant_req, grant, vnfd):
|
||||||
# make HOT
|
# make HOT
|
||||||
fields = self._make_hot(req, inst, grant_req, grant, vnfd)
|
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)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
heat_client = heat_utils.HeatClient(vim_info)
|
heat_client = heat_utils.HeatClient(vim_info)
|
||||||
|
@ -298,13 +322,35 @@ class Openstack(object):
|
||||||
|
|
||||||
# update stack
|
# update stack
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
fields = self._update_nfv_dict(heat_client, stack_name, fields)
|
fields = self._update_fields(heat_client, stack_name, fields)
|
||||||
heat_client.update_stack(stack_name, fields)
|
heat_client.update_stack(stack_name, fields)
|
||||||
|
|
||||||
# make instantiated_vnf_info
|
# make instantiated_vnf_info
|
||||||
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
|
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
|
||||||
heat_client)
|
heat_client)
|
||||||
|
|
||||||
|
def _get_flavor_from_vdu_dict(self, vnfc, vdu_dict):
|
||||||
|
vdu_name = _vdu_with_idx(vnfc.vduId, vnfc.metadata.get('vdu_idx'))
|
||||||
|
return vdu_dict.get(vdu_name, {}).get('computeFlavourId')
|
||||||
|
|
||||||
|
def _get_images_from_vdu_dict(self, vnfc, storage_infos, vdu_dict):
|
||||||
|
vdu_idx = vnfc.metadata.get('vdu_idx')
|
||||||
|
vdu_name = _vdu_with_idx(vnfc.vduId, vdu_idx)
|
||||||
|
vdu_names = [vdu_name]
|
||||||
|
if vnfc.obj_attr_is_set('storageResourceIds'):
|
||||||
|
vdu_names += [
|
||||||
|
_vdu_with_idx(storage_info.virtualStorageDescId, vdu_idx)
|
||||||
|
for storage_info in storage_infos
|
||||||
|
if storage_info.id in vnfc.storageResourceIds
|
||||||
|
]
|
||||||
|
images = {}
|
||||||
|
for vdu_name in vdu_names:
|
||||||
|
image = vdu_dict.get(vdu_name, {}).get('vcImageId')
|
||||||
|
if image:
|
||||||
|
images[vdu_name] = image
|
||||||
|
|
||||||
|
return images
|
||||||
|
|
||||||
def _change_vnfpkg_rolling_update(self, req, inst, grant_req, grant,
|
def _change_vnfpkg_rolling_update(self, req, inst, grant_req, grant,
|
||||||
vnfd, fields, heat_client, is_rollback):
|
vnfd, fields, heat_client, is_rollback):
|
||||||
if not grant_req.obj_attr_is_set('removeResources'):
|
if not grant_req.obj_attr_is_set('removeResources'):
|
||||||
|
@ -348,30 +394,25 @@ class Openstack(object):
|
||||||
LOG.debug("stack fields: %s", vdu_fields)
|
LOG.debug("stack fields: %s", vdu_fields)
|
||||||
heat_client.update_stack(parent_stack_id, vdu_fields)
|
heat_client.update_stack(parent_stack_id, vdu_fields)
|
||||||
else:
|
else:
|
||||||
# handle single VM
|
# pickup 'vcImageId' and 'computeFlavourId' from vdu_dict
|
||||||
# pickup 'vcImageId' and 'computeFlavourId'
|
vdu_name = _vdu_with_idx(vnfc.vduId,
|
||||||
|
vnfc.metadata.get('vdu_idx'))
|
||||||
params = {}
|
params = {}
|
||||||
if vdu_dict[vnfc.vduId].get('computeFlavourId'):
|
flavor = self._get_flavor_from_vdu_dict(vnfc, vdu_dict)
|
||||||
params[vnfc.vduId] = {'computeFlavourId':
|
if flavor:
|
||||||
vdu_dict[vnfc.vduId]['computeFlavourId']}
|
params[vdu_name] = {'computeFlavourId': flavor}
|
||||||
vdu_names = [vnfc.vduId]
|
storage_infos = (
|
||||||
if vnfc.obj_attr_is_set('storageResourceIds'):
|
inst.instantiatedVnfInfo.virtualStorageResourceInfo
|
||||||
storage_infos = (
|
if vnfc.obj_attr_is_set('storageResourceIds') else [])
|
||||||
inst.instantiatedVnfInfo.virtualStorageResourceInfo)
|
images = self._get_images_from_vdu_dict(vnfc,
|
||||||
vdu_names += [
|
storage_infos, vdu_dict)
|
||||||
storage_info.virtualStorageDescId
|
for vdu_name, image in images.items():
|
||||||
for storage_info in storage_infos
|
params.setdefault(vdu_name, {})
|
||||||
if storage_info.id in vnfc.storageResourceIds
|
params[vdu_name]['vcImageId'] = image
|
||||||
]
|
|
||||||
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_nfv_dict = {'nfv': {'VDU': params}}
|
||||||
update_fields = {'parameters': update_nfv_dict}
|
update_fields = {'parameters': update_nfv_dict}
|
||||||
|
|
||||||
update_fields = self._update_nfv_dict(heat_client, stack_name,
|
update_fields = self._update_fields(heat_client, stack_name,
|
||||||
update_fields)
|
update_fields)
|
||||||
LOG.debug("stack fields: %s", update_fields)
|
LOG.debug("stack fields: %s", update_fields)
|
||||||
heat_client.update_stack(stack_name, update_fields)
|
heat_client.update_stack(stack_name, update_fields)
|
||||||
|
@ -429,8 +470,9 @@ class Openstack(object):
|
||||||
|
|
||||||
def change_vnfpkg_rollback(self, req, inst, grant_req, grant, vnfd,
|
def change_vnfpkg_rollback(self, req, inst, grant_req, grant, vnfd,
|
||||||
lcmocc):
|
lcmocc):
|
||||||
fields = userdata_default.DefaultUserData.change_vnfpkg_rollback(
|
# make HOT
|
||||||
req, inst, grant_req, grant, vnfd.csar_dir)
|
fields = self._make_hot(req, inst, grant_req, grant, vnfd,
|
||||||
|
is_rollback=True)
|
||||||
|
|
||||||
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
vim_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||||
heat_client = heat_utils.HeatClient(vim_info)
|
heat_client = heat_utils.HeatClient(vim_info)
|
||||||
|
@ -444,15 +486,15 @@ class Openstack(object):
|
||||||
|
|
||||||
# stack update
|
# stack update
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
fields = self._update_nfv_dict(heat_client, stack_name, fields)
|
fields = self._update_fields(heat_client, stack_name, fields)
|
||||||
heat_client.update_stack(stack_name, fields)
|
heat_client.update_stack(stack_name, fields)
|
||||||
|
|
||||||
# NOTE: it is necessary to re-create instantiatedVnfInfo because
|
# NOTE: it is necessary to re-create instantiatedVnfInfo because
|
||||||
# some resources may be changed.
|
# some resources may be changed.
|
||||||
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
|
self._make_instantiated_vnf_info(req, inst, grant_req, grant, vnfd,
|
||||||
heat_client)
|
heat_client, is_rollback=True)
|
||||||
|
|
||||||
def _make_hot(self, req, inst, grant_req, grant, vnfd):
|
def _make_hot(self, req, inst, grant_req, grant, vnfd, is_rollback=False):
|
||||||
if grant_req.operation == v2fields.LcmOperationType.INSTANTIATE:
|
if grant_req.operation == v2fields.LcmOperationType.INSTANTIATE:
|
||||||
flavour_id = req.flavourId
|
flavour_id = req.flavourId
|
||||||
else:
|
else:
|
||||||
|
@ -470,10 +512,12 @@ class Openstack(object):
|
||||||
'lcm-operation-user-data-class')
|
'lcm-operation-user-data-class')
|
||||||
|
|
||||||
if userdata is None and userdata_class is None:
|
if userdata is None and userdata_class is None:
|
||||||
LOG.debug("Processing default userdata %s", grant_req.operation)
|
operation = grant_req.operation.lower()
|
||||||
|
if is_rollback:
|
||||||
|
operation = operation + '_rollback'
|
||||||
|
LOG.debug("Processing default userdata %s", operation)
|
||||||
# NOTE: objects used here are dict compat.
|
# NOTE: objects used here are dict compat.
|
||||||
method = getattr(userdata_default.DefaultUserData,
|
method = getattr(userdata_default.DefaultUserData, operation)
|
||||||
grant_req.operation.lower())
|
|
||||||
fields = method(req, inst, grant_req, grant, vnfd.csar_dir)
|
fields = method(req, inst, grant_req, grant, vnfd.csar_dir)
|
||||||
elif userdata is None or userdata_class is None:
|
elif userdata is None or userdata_class is None:
|
||||||
# Both must be specified.
|
# Both must be specified.
|
||||||
|
@ -488,7 +532,8 @@ class Openstack(object):
|
||||||
'vnf_instance': inst.to_dict(),
|
'vnf_instance': inst.to_dict(),
|
||||||
'grant_request': grant_req.to_dict(),
|
'grant_request': grant_req.to_dict(),
|
||||||
'grant_response': grant.to_dict(),
|
'grant_response': grant.to_dict(),
|
||||||
'tmp_csar_dir': tmp_csar_dir
|
'tmp_csar_dir': tmp_csar_dir,
|
||||||
|
'is_rollback': is_rollback
|
||||||
}
|
}
|
||||||
script_path = os.path.join(
|
script_path = os.path.join(
|
||||||
os.path.dirname(__file__), "userdata_main.py")
|
os.path.dirname(__file__), "userdata_main.py")
|
||||||
|
@ -510,6 +555,8 @@ class Openstack(object):
|
||||||
fields['timeout_mins'] = (
|
fields['timeout_mins'] = (
|
||||||
CONF.v2_vnfm.openstack_vim_stack_create_timeout)
|
CONF.v2_vnfm.openstack_vim_stack_create_timeout)
|
||||||
|
|
||||||
|
LOG.debug("stack fields: %s", fields)
|
||||||
|
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def _get_checked_reses(self, nodes, reses):
|
def _get_checked_reses(self, nodes, reses):
|
||||||
|
@ -895,9 +942,16 @@ class Openstack(object):
|
||||||
}
|
}
|
||||||
parent_res = heat_utils.get_parent_resource(server_res, heat_reses)
|
parent_res = heat_utils.get_parent_resource(server_res, heat_reses)
|
||||||
if parent_res:
|
if parent_res:
|
||||||
metadata['parent_stack_id'] = (
|
parent_parent_res = heat_utils.get_parent_resource(parent_res,
|
||||||
heat_utils.get_resource_stack_id(parent_res))
|
heat_reses)
|
||||||
metadata['parent_resource_name'] = parent_res['resource_name']
|
if (parent_parent_res and
|
||||||
|
parent_parent_res['resource_type'] ==
|
||||||
|
'OS::Heat::AutoScalingGroup'):
|
||||||
|
metadata['parent_stack_id'] = (
|
||||||
|
heat_utils.get_resource_stack_id(parent_res))
|
||||||
|
metadata['parent_resource_name'] = parent_res['resource_name']
|
||||||
|
else:
|
||||||
|
metadata['vdu_idx'] = _get_vdu_idx(parent_res['resource_name'])
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
|
@ -917,22 +971,16 @@ class Openstack(object):
|
||||||
if k.startswith('image-'):
|
if k.startswith('image-'):
|
||||||
metadata[k] = v
|
metadata[k] = v
|
||||||
else:
|
else:
|
||||||
properties = nfv_dict['VDU'][vnfc_res_info.vduId]
|
# assume it is found
|
||||||
metadata['flavor'] = properties['computeFlavourId']
|
metadata['flavor'] = self._get_flavor_from_vdu_dict(
|
||||||
vdu_names = [vnfc_res_info.vduId]
|
vnfc_res_info, nfv_dict['VDU'])
|
||||||
if vnfc_res_info.obj_attr_is_set('storageResourceIds'):
|
images = self._get_images_from_vdu_dict(vnfc_res_info,
|
||||||
vdu_names += [
|
storage_infos, nfv_dict['VDU'])
|
||||||
storage_info.virtualStorageDescId
|
for vdu_name, image in images.items():
|
||||||
for storage_info in storage_infos
|
metadata[f'image-{vdu_name}'] = image
|
||||||
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,
|
def _make_instantiated_vnf_info(self, req, inst, grant_req, grant, vnfd,
|
||||||
heat_client):
|
heat_client, is_rollback=False):
|
||||||
# get heat resources
|
# get heat resources
|
||||||
stack_name = heat_utils.get_stack_name(inst)
|
stack_name = heat_utils.get_stack_name(inst)
|
||||||
heat_reses = heat_client.get_resources(stack_name)
|
heat_reses = heat_client.get_resources(stack_name)
|
||||||
|
@ -1029,7 +1077,8 @@ class Openstack(object):
|
||||||
flavour_id, req, grant)
|
flavour_id, req, grant)
|
||||||
else:
|
else:
|
||||||
old_inst_vnf_info = inst.instantiatedVnfInfo
|
old_inst_vnf_info = inst.instantiatedVnfInfo
|
||||||
if op == v2fields.LcmOperationType.CHANGE_EXT_CONN:
|
if (op == v2fields.LcmOperationType.CHANGE_EXT_CONN and
|
||||||
|
not is_rollback):
|
||||||
ext_vl_infos = self._make_ext_vl_info_from_req_and_inst(
|
ext_vl_infos = self._make_ext_vl_info_from_req_and_inst(
|
||||||
req, grant, old_inst_vnf_info, ext_cp_infos)
|
req, grant, old_inst_vnf_info, ext_cp_infos)
|
||||||
else:
|
else:
|
||||||
|
@ -1107,7 +1156,9 @@ class Openstack(object):
|
||||||
# grant request.
|
# grant request.
|
||||||
|
|
||||||
def _get_key(vnfc):
|
def _get_key(vnfc):
|
||||||
return parser.isoparse(vnfc.metadata['creation_time'])
|
vdu_idx = vnfc.metadata.get('vdu_idx', 0)
|
||||||
|
creation_time = parser.isoparse(vnfc.metadata['creation_time'])
|
||||||
|
return (vdu_idx, creation_time)
|
||||||
|
|
||||||
sorted_vnfc_res_infos = sorted(vnfc_res_infos, key=_get_key,
|
sorted_vnfc_res_infos = sorted(vnfc_res_infos, key=_get_key,
|
||||||
reverse=True)
|
reverse=True)
|
||||||
|
|
|
@ -39,7 +39,10 @@ def main():
|
||||||
module = importlib.import_module(class_module)
|
module = importlib.import_module(class_module)
|
||||||
klass = getattr(module, userdata_class)
|
klass = getattr(module, userdata_class)
|
||||||
|
|
||||||
method = getattr(klass, grant_req['operation'].lower())
|
operation = grant_req['operation'].lower()
|
||||||
|
if script_dict['is_rollback']:
|
||||||
|
operation = operation + '_rollback'
|
||||||
|
method = getattr(klass, operation)
|
||||||
stack_dict = method(req, inst, grant_req, grant, tmp_csar_dir)
|
stack_dict = method(req, inst, grant_req, grant, tmp_csar_dir)
|
||||||
|
|
||||||
pickle.dump(stack_dict, sys.stdout.buffer)
|
pickle.dump(stack_dict, sys.stdout.buffer)
|
||||||
|
|
|
@ -0,0 +1,544 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from tacker.sol_refactored.common import common_script_utils
|
||||||
|
from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
|
||||||
|
from tacker.sol_refactored.infra_drivers.openstack import userdata_utils
|
||||||
|
|
||||||
|
|
||||||
|
def add_idx(name, index):
|
||||||
|
return f'{name}-{index}'
|
||||||
|
|
||||||
|
|
||||||
|
def rm_idx(name_idx):
|
||||||
|
return name_idx.rpartition('-')[0]
|
||||||
|
|
||||||
|
|
||||||
|
def add_idx_to_vdu_template(vdu_template, vdu_idx):
|
||||||
|
"""Add index to the third element of get_param
|
||||||
|
|
||||||
|
ex. input VDU template:
|
||||||
|
---
|
||||||
|
VDU1:
|
||||||
|
type: VDU1.yaml
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
|
||||||
|
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
|
||||||
|
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
|
||||||
|
---
|
||||||
|
|
||||||
|
output VDU template:
|
||||||
|
---
|
||||||
|
VDU1:
|
||||||
|
type: VDU1.yaml
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: [ nfv, VDU, VDU1-1, computeFlavourId ] }
|
||||||
|
image-VDU1: { get_param: [ nfv, VDU, VDU1-1, vcImageId ] }
|
||||||
|
net1: { get_param: [ nfv, CP, VDU1_CP1-1, network ] }
|
||||||
|
---
|
||||||
|
"""
|
||||||
|
res = copy.deepcopy(vdu_template)
|
||||||
|
for prop_value in res.get('properties', {}).values():
|
||||||
|
get_param = prop_value.get('get_param')
|
||||||
|
if (get_param is not None and
|
||||||
|
isinstance(get_param, list) and len(get_param) >= 4):
|
||||||
|
get_param[2] = add_idx(get_param[2], vdu_idx)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class StandardUserData(userdata_utils.AbstractUserData):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def instantiate(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||||
|
flavour_id = req['flavourId']
|
||||||
|
|
||||||
|
hot_dict = vnfd.get_base_hot(flavour_id)
|
||||||
|
top_hot = hot_dict['template']
|
||||||
|
|
||||||
|
# first modify VDU resources
|
||||||
|
poped_vdu = {}
|
||||||
|
vdu_idxes = {}
|
||||||
|
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
|
||||||
|
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
|
||||||
|
vdu_idxes[vdu_name] = 0
|
||||||
|
|
||||||
|
for res in grant_req['addResources']:
|
||||||
|
if res['type'] != 'COMPUTE':
|
||||||
|
continue
|
||||||
|
vdu_name = res['resourceTemplateId']
|
||||||
|
if vdu_name not in poped_vdu:
|
||||||
|
continue
|
||||||
|
vdu_idx = vdu_idxes[vdu_name]
|
||||||
|
vdu_idxes[vdu_name] += 1
|
||||||
|
res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx)
|
||||||
|
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
|
||||||
|
|
||||||
|
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
|
||||||
|
|
||||||
|
vdus = nfv_dict.get('VDU', {})
|
||||||
|
for vdu_name, vdu_value in vdus.items():
|
||||||
|
vdu_name = rm_idx(vdu_name)
|
||||||
|
if 'computeFlavourId' in vdu_value:
|
||||||
|
vdu_value['computeFlavourId'] = (
|
||||||
|
common_script_utils.get_param_flavor(
|
||||||
|
vdu_name, flavour_id, vnfd, grant))
|
||||||
|
if 'vcImageId' in vdu_value:
|
||||||
|
vdu_value['vcImageId'] = common_script_utils.get_param_image(
|
||||||
|
vdu_name, flavour_id, vnfd, grant)
|
||||||
|
if 'locationConstraints' in vdu_value:
|
||||||
|
vdu_value['locationConstraints'] = (
|
||||||
|
common_script_utils.get_param_zone(
|
||||||
|
vdu_name, grant_req, grant))
|
||||||
|
|
||||||
|
cps = nfv_dict.get('CP', {})
|
||||||
|
for cp_name, cp_value in cps.items():
|
||||||
|
cp_name = rm_idx(cp_name)
|
||||||
|
if 'network' in cp_value:
|
||||||
|
cp_value['network'] = common_script_utils.get_param_network(
|
||||||
|
cp_name, grant, req)
|
||||||
|
if 'fixed_ips' in cp_value:
|
||||||
|
ext_fixed_ips = common_script_utils.get_param_fixed_ips(
|
||||||
|
cp_name, grant, req)
|
||||||
|
fixed_ips = []
|
||||||
|
for i in range(len(ext_fixed_ips)):
|
||||||
|
if i not in cp_value['fixed_ips']:
|
||||||
|
break
|
||||||
|
ips_i = cp_value['fixed_ips'][i]
|
||||||
|
if 'subnet' in ips_i:
|
||||||
|
ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
|
||||||
|
if 'ip_address' in ips_i:
|
||||||
|
ips_i['ip_address'] = ext_fixed_ips[i].get(
|
||||||
|
'ip_address')
|
||||||
|
fixed_ips.append(ips_i)
|
||||||
|
cp_value['fixed_ips'] = fixed_ips
|
||||||
|
|
||||||
|
common_script_utils.apply_ext_managed_vls(top_hot, req, grant)
|
||||||
|
|
||||||
|
if 'nfv' in req.get('additionalParams', {}):
|
||||||
|
nfv_dict = inst_utils.json_merge_patch(nfv_dict,
|
||||||
|
req['additionalParams']['nfv'])
|
||||||
|
if 'nfv' in grant.get('additionalParams', {}):
|
||||||
|
nfv_dict = inst_utils.json_merge_patch(nfv_dict,
|
||||||
|
grant['additionalParams']['nfv'])
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'template': yaml.safe_dump(top_hot),
|
||||||
|
'parameters': {'nfv': nfv_dict},
|
||||||
|
'files': {}
|
||||||
|
}
|
||||||
|
for key, value in hot_dict.get('files', {}).items():
|
||||||
|
fields['files'][key] = yaml.safe_dump(value)
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def scale(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
if req['type'] == 'SCALE_OUT':
|
||||||
|
return StandardUserData._scale_out(req, inst, grant_req, grant,
|
||||||
|
tmp_csar_dir)
|
||||||
|
else:
|
||||||
|
return StandardUserData._scale_in(req, inst, grant_req, grant,
|
||||||
|
tmp_csar_dir)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _scale_out(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||||
|
flavour_id = inst['instantiatedVnfInfo']['flavourId']
|
||||||
|
|
||||||
|
hot_dict = vnfd.get_base_hot(flavour_id)
|
||||||
|
top_hot = hot_dict['template']
|
||||||
|
|
||||||
|
# first modify VDU resources
|
||||||
|
poped_vdu = {}
|
||||||
|
vdu_idxes = {}
|
||||||
|
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
|
||||||
|
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
|
||||||
|
vdu_idxes[vdu_name] = common_script_utils.get_current_capacity(
|
||||||
|
vdu_name, inst)
|
||||||
|
|
||||||
|
for res in grant_req['addResources']:
|
||||||
|
if res['type'] != 'COMPUTE':
|
||||||
|
continue
|
||||||
|
vdu_name = res['resourceTemplateId']
|
||||||
|
if vdu_name not in poped_vdu:
|
||||||
|
continue
|
||||||
|
vdu_idx = vdu_idxes[vdu_name]
|
||||||
|
vdu_idxes[vdu_name] += 1
|
||||||
|
res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx)
|
||||||
|
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
|
||||||
|
|
||||||
|
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
|
||||||
|
|
||||||
|
vdus = nfv_dict.get('VDU', {})
|
||||||
|
for vdu_name, vdu_value in vdus.items():
|
||||||
|
vdu_name = rm_idx(vdu_name)
|
||||||
|
if 'computeFlavourId' in vdu_value:
|
||||||
|
vdu_value['computeFlavourId'] = (
|
||||||
|
common_script_utils.get_param_flavor(
|
||||||
|
vdu_name, flavour_id, vnfd, grant))
|
||||||
|
if 'vcImageId' in vdu_value:
|
||||||
|
vdu_value['vcImageId'] = common_script_utils.get_param_image(
|
||||||
|
vdu_name, flavour_id, vnfd, grant)
|
||||||
|
if 'locationConstraints' in vdu_value:
|
||||||
|
vdu_value['locationConstraints'] = (
|
||||||
|
common_script_utils.get_param_zone(
|
||||||
|
vdu_name, grant_req, grant))
|
||||||
|
|
||||||
|
cps = nfv_dict.get('CP', {})
|
||||||
|
for cp_name, cp_value in cps.items():
|
||||||
|
cp_name = rm_idx(cp_name)
|
||||||
|
if 'network' in cp_value:
|
||||||
|
cp_value['network'] = (
|
||||||
|
common_script_utils.get_param_network_from_inst(
|
||||||
|
cp_name, inst))
|
||||||
|
if 'fixed_ips' in cp_value:
|
||||||
|
ext_fixed_ips = (
|
||||||
|
common_script_utils.get_param_fixed_ips_from_inst(
|
||||||
|
cp_name, inst))
|
||||||
|
fixed_ips = []
|
||||||
|
for i in range(len(ext_fixed_ips)):
|
||||||
|
if i not in cp_value['fixed_ips']:
|
||||||
|
break
|
||||||
|
ips_i = cp_value['fixed_ips'][i]
|
||||||
|
if 'subnet' in ips_i:
|
||||||
|
ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
|
||||||
|
if 'ip_address' in ips_i:
|
||||||
|
ips_i['ip_address'] = ext_fixed_ips[i].get(
|
||||||
|
'ip_address')
|
||||||
|
fixed_ips.append(ips_i)
|
||||||
|
cp_value['fixed_ips'] = fixed_ips
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'template': yaml.safe_dump(top_hot),
|
||||||
|
'parameters': {'nfv': nfv_dict}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _scale_in(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||||
|
flavour_id = inst['instantiatedVnfInfo']['flavourId']
|
||||||
|
|
||||||
|
vdu_nodes = vnfd.get_vdu_nodes(flavour_id)
|
||||||
|
template = {'resources': {}}
|
||||||
|
vdus = {}
|
||||||
|
cps = {}
|
||||||
|
for res in grant_req['removeResources']:
|
||||||
|
if res['type'] != 'COMPUTE':
|
||||||
|
continue
|
||||||
|
for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
|
||||||
|
if (inst_vnfc['computeResource']['resourceId'] ==
|
||||||
|
res['resource']['resourceId']):
|
||||||
|
# must be found
|
||||||
|
vdu_idx = inst_vnfc['metadata']['vdu_idx']
|
||||||
|
break
|
||||||
|
vdu_name = res['resourceTemplateId']
|
||||||
|
template['resources'][add_idx(vdu_name, vdu_idx)] = None
|
||||||
|
vdus[add_idx(vdu_name, vdu_idx)] = None
|
||||||
|
|
||||||
|
for str_name in vnfd.get_vdu_storages(vdu_nodes[vdu_name]):
|
||||||
|
# may overspec, but no problem
|
||||||
|
vdus[add_idx(str_name, vdu_idx)] = None
|
||||||
|
|
||||||
|
for cp_name in vnfd.get_vdu_cps(flavour_id, vdu_name):
|
||||||
|
# may overspec, but no problem
|
||||||
|
cps[add_idx(cp_name, vdu_idx)] = None
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'template': yaml.safe_dump(template),
|
||||||
|
'parameters': {'nfv': {'VDU': vdus, 'CP': cps}}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def scale_rollback(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||||
|
flavour_id = inst['instantiatedVnfInfo']['flavourId']
|
||||||
|
|
||||||
|
vdu_nodes = vnfd.get_vdu_nodes(flavour_id)
|
||||||
|
vdu_idxes = {}
|
||||||
|
for vdu_name in vdu_nodes.keys():
|
||||||
|
vdu_idxes[vdu_name] = common_script_utils.get_current_capacity(
|
||||||
|
vdu_name, inst)
|
||||||
|
|
||||||
|
template = {'resources': {}}
|
||||||
|
vdus = {}
|
||||||
|
cps = {}
|
||||||
|
for res in grant_req['addResources']:
|
||||||
|
if res['type'] != 'COMPUTE':
|
||||||
|
continue
|
||||||
|
vdu_name = res['resourceTemplateId']
|
||||||
|
vdu_idx = vdu_idxes[vdu_name]
|
||||||
|
vdu_idxes[vdu_name] += 1
|
||||||
|
template['resources'][add_idx(vdu_name, vdu_idx)] = None
|
||||||
|
vdus[add_idx(vdu_name, vdu_idx)] = None
|
||||||
|
|
||||||
|
for str_name in vnfd.get_vdu_storages(vdu_nodes[vdu_name]):
|
||||||
|
# may overspec, but no problem
|
||||||
|
vdus[add_idx(str_name, vdu_idx)] = None
|
||||||
|
|
||||||
|
for cp_name in vnfd.get_vdu_cps(flavour_id, vdu_name):
|
||||||
|
# may overspec, but no problem
|
||||||
|
cps[add_idx(cp_name, vdu_idx)] = None
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'template': yaml.safe_dump(template),
|
||||||
|
'parameters': {'nfv': {'VDU': vdus, 'CP': cps}}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def change_ext_conn(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
# change_ext_conn is interested in 'CP' only.
|
||||||
|
# This method returns only 'CP' part in the 'nfv' dict from
|
||||||
|
# ChangeExtVnfConnectivityRequest.
|
||||||
|
# It is applied to json merge patch against the existing 'nfv'
|
||||||
|
# dict by the caller.
|
||||||
|
# NOTE: complete 'nfv' dict can not be made at the moment
|
||||||
|
# since InstantiateVnfRequest is necessary to make it.
|
||||||
|
|
||||||
|
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||||
|
flavour_id = inst['instantiatedVnfInfo']['flavourId']
|
||||||
|
|
||||||
|
hot_dict = vnfd.get_base_hot(flavour_id)
|
||||||
|
top_hot = hot_dict['template']
|
||||||
|
|
||||||
|
# first modify VDU resources
|
||||||
|
poped_vdu = {}
|
||||||
|
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
|
||||||
|
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
|
||||||
|
|
||||||
|
for inst_vnfc in inst['instantiatedVnfInfo'].get(
|
||||||
|
'vnfcResourceInfo', []):
|
||||||
|
vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
|
||||||
|
if vdu_idx is None:
|
||||||
|
continue
|
||||||
|
vdu_name = inst_vnfc['vduId']
|
||||||
|
res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx)
|
||||||
|
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
|
||||||
|
|
||||||
|
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
|
||||||
|
|
||||||
|
cps = nfv_dict.get('CP', {})
|
||||||
|
new_cps = {}
|
||||||
|
for cp_name_idx, cp_value in cps.items():
|
||||||
|
cp_name = rm_idx(cp_name_idx)
|
||||||
|
if 'network' in cp_value:
|
||||||
|
network = common_script_utils.get_param_network(
|
||||||
|
cp_name, grant, req)
|
||||||
|
if network is None:
|
||||||
|
continue
|
||||||
|
new_cps.setdefault(cp_name_idx, {})
|
||||||
|
new_cps[cp_name_idx]['network'] = network
|
||||||
|
if 'fixed_ips' in cp_value:
|
||||||
|
ext_fixed_ips = common_script_utils.get_param_fixed_ips(
|
||||||
|
cp_name, grant, req)
|
||||||
|
fixed_ips = []
|
||||||
|
for i in range(len(ext_fixed_ips)):
|
||||||
|
if i not in cp_value['fixed_ips']:
|
||||||
|
break
|
||||||
|
ips_i = cp_value['fixed_ips'][i]
|
||||||
|
if 'subnet' in ips_i:
|
||||||
|
ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
|
||||||
|
if 'ip_address' in ips_i:
|
||||||
|
ips_i['ip_address'] = ext_fixed_ips[i].get(
|
||||||
|
'ip_address')
|
||||||
|
fixed_ips.append(ips_i)
|
||||||
|
new_cps.setdefault(cp_name_idx, {})
|
||||||
|
new_cps[cp_name_idx]['fixed_ips'] = fixed_ips
|
||||||
|
|
||||||
|
fields = {'parameters': {'nfv': {'CP': new_cps}}}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def change_ext_conn_rollback(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||||
|
flavour_id = inst['instantiatedVnfInfo']['flavourId']
|
||||||
|
|
||||||
|
hot_dict = vnfd.get_base_hot(flavour_id)
|
||||||
|
top_hot = hot_dict['template']
|
||||||
|
|
||||||
|
# first modify VDU resources
|
||||||
|
poped_vdu = {}
|
||||||
|
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
|
||||||
|
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
|
||||||
|
|
||||||
|
for inst_vnfc in inst['instantiatedVnfInfo'].get(
|
||||||
|
'vnfcResourceInfo', []):
|
||||||
|
vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
|
||||||
|
if vdu_idx is None:
|
||||||
|
continue
|
||||||
|
vdu_name = inst_vnfc['vduId']
|
||||||
|
res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx)
|
||||||
|
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
|
||||||
|
|
||||||
|
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
|
||||||
|
|
||||||
|
cps = nfv_dict.get('CP', {})
|
||||||
|
new_cps = {}
|
||||||
|
for cp_name_idx, cp_value in cps.items():
|
||||||
|
cp_name = rm_idx(cp_name_idx)
|
||||||
|
if 'network' in cp_value:
|
||||||
|
network = common_script_utils.get_param_network_from_inst(
|
||||||
|
cp_name, inst)
|
||||||
|
if network is None:
|
||||||
|
continue
|
||||||
|
new_cps.setdefault(cp_name_idx, {})
|
||||||
|
new_cps[cp_name_idx]['network'] = network
|
||||||
|
if 'fixed_ips' in cp_value:
|
||||||
|
ext_fixed_ips = (
|
||||||
|
common_script_utils.get_param_fixed_ips_from_inst(
|
||||||
|
cp_name, inst))
|
||||||
|
fixed_ips = []
|
||||||
|
for i in range(len(ext_fixed_ips)):
|
||||||
|
if i not in cp_value['fixed_ips']:
|
||||||
|
break
|
||||||
|
ips_i = cp_value['fixed_ips'][i]
|
||||||
|
if 'subnet' in ips_i:
|
||||||
|
ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
|
||||||
|
if 'ip_address' in ips_i:
|
||||||
|
ips_i['ip_address'] = ext_fixed_ips[i].get(
|
||||||
|
'ip_address')
|
||||||
|
fixed_ips.append(ips_i)
|
||||||
|
new_cps.setdefault(cp_name_idx, {})
|
||||||
|
new_cps[cp_name_idx]['fixed_ips'] = fixed_ips
|
||||||
|
|
||||||
|
fields = {'parameters': {'nfv': {'CP': new_cps}}}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def heal(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
# It is not necessary to change parameters at heal basically.
|
||||||
|
|
||||||
|
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']
|
||||||
|
|
||||||
|
# first modify VDU resources
|
||||||
|
poped_vdu = {}
|
||||||
|
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
|
||||||
|
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
|
||||||
|
|
||||||
|
for res in grant_req['removeResources']:
|
||||||
|
if res['type'] != 'COMPUTE':
|
||||||
|
continue
|
||||||
|
for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
|
||||||
|
if (inst_vnfc['computeResource']['resourceId'] ==
|
||||||
|
res['resource']['resourceId']):
|
||||||
|
# must be found
|
||||||
|
vdu_idx = inst_vnfc['metadata']['vdu_idx']
|
||||||
|
break
|
||||||
|
vdu_name = res['resourceTemplateId']
|
||||||
|
res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx)
|
||||||
|
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
|
||||||
|
|
||||||
|
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
|
||||||
|
|
||||||
|
vdus = nfv_dict.get('VDU', {})
|
||||||
|
for vdu_name, vdu_value in vdus.items():
|
||||||
|
vdu_name = rm_idx(vdu_name)
|
||||||
|
if 'computeFlavourId' in vdu_value:
|
||||||
|
vdu_value['computeFlavourId'] = (
|
||||||
|
common_script_utils.get_param_flavor(
|
||||||
|
vdu_name, flavour_id, vnfd, grant))
|
||||||
|
if 'vcImageId' in vdu_value:
|
||||||
|
vdu_value['vcImageId'] = common_script_utils.get_param_image(
|
||||||
|
vdu_name, flavour_id, vnfd, grant)
|
||||||
|
if 'locationConstraints' in vdu_value:
|
||||||
|
vdu_value.pop('locationConstraints')
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'parameters': {'nfv': {'VDU': vdus}}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def change_vnfpkg_rollback(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||||
|
flavour_id = inst['instantiatedVnfInfo']['flavourId']
|
||||||
|
|
||||||
|
hot_dict = vnfd.get_base_hot(flavour_id)
|
||||||
|
top_hot = hot_dict['template']
|
||||||
|
|
||||||
|
# first modify VDU resources
|
||||||
|
poped_vdu = {}
|
||||||
|
for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
|
||||||
|
poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
|
||||||
|
|
||||||
|
for res in grant_req['removeResources']:
|
||||||
|
if res['type'] != 'COMPUTE':
|
||||||
|
continue
|
||||||
|
for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
|
||||||
|
if (inst_vnfc['computeResource']['resourceId'] ==
|
||||||
|
res['resource']['resourceId']):
|
||||||
|
# must be found
|
||||||
|
vdu_idx = inst_vnfc['metadata']['vdu_idx']
|
||||||
|
break
|
||||||
|
vdu_name = res['resourceTemplateId']
|
||||||
|
res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx)
|
||||||
|
top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
|
||||||
|
|
||||||
|
nfv_dict = common_script_utils.init_nfv_dict(top_hot)
|
||||||
|
|
||||||
|
images = {}
|
||||||
|
flavors = {}
|
||||||
|
for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
|
||||||
|
vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
|
||||||
|
if vdu_idx is None:
|
||||||
|
continue
|
||||||
|
vdu_name = inst_vnfc['vduId']
|
||||||
|
if vdu_name in flavors:
|
||||||
|
continue
|
||||||
|
for key, value in inst_vnfc['metadata'].items():
|
||||||
|
if key == 'flavor':
|
||||||
|
flavors[add_idx(vdu_name, vdu_idx)] = value
|
||||||
|
elif key.startswith('image-'):
|
||||||
|
image_vdu = key.replace('image-', '')
|
||||||
|
images[image_vdu] = value
|
||||||
|
|
||||||
|
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
|
|
@ -44,12 +44,32 @@ class AbstractUserData(metaclass=abc.ABCMeta):
|
||||||
def scale(req, inst, grant_req, grant, tmp_csar_dir):
|
def scale(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
raise sol_ex.UserDataClassNotImplemented()
|
raise sol_ex.UserDataClassNotImplemented()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def scale_rollback(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
raise sol_ex.UserDataClassNotImplemented()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def change_ext_conn(req, inst, grant_req, grant, tmp_csar_dir):
|
def change_ext_conn(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
raise sol_ex.UserDataClassNotImplemented()
|
raise sol_ex.UserDataClassNotImplemented()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def change_ext_conn_rollback(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
raise sol_ex.UserDataClassNotImplemented()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def heal(req, inst, grant_req, grant, tmp_csar_dir):
|
def heal(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
raise sol_ex.UserDataClassNotImplemented()
|
raise sol_ex.UserDataClassNotImplemented()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def change_vnfpkg(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
raise sol_ex.UserDataClassNotImplemented()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def change_vnfpkg_rollback(req, inst, grant_req, grant, tmp_csar_dir):
|
||||||
|
raise sol_ex.UserDataClassNotImplemented()
|
||||||
|
|
|
@ -0,0 +1,433 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from tacker.tests.functional.sol_v2_common import paramgen
|
||||||
|
from tacker.tests.functional.sol_v2_common import test_vnflcm_basic_common
|
||||||
|
|
||||||
|
|
||||||
|
class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(IndividualVnfcMgmtTest, cls).setUpClass()
|
||||||
|
cur_dir = os.path.dirname(__file__)
|
||||||
|
# tacker/tests/functional/sol_v2(here)
|
||||||
|
# /etc
|
||||||
|
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))
|
||||||
|
|
||||||
|
# tacker/tests/functional/sol_v2(here)
|
||||||
|
# /sol_refactored
|
||||||
|
userdata_dir = os.path.join(
|
||||||
|
cur_dir, "../../../sol_refactored/infra_drivers/openstack")
|
||||||
|
userdata_file = "userdata_standard.py"
|
||||||
|
userdata_path = os.path.abspath(
|
||||||
|
os.path.join(userdata_dir, userdata_file))
|
||||||
|
|
||||||
|
# main vnf package for StandardUserData test
|
||||||
|
pkg_path_1 = os.path.join(cur_dir,
|
||||||
|
"../sol_v2_common/samples/userdata_standard")
|
||||||
|
cls.vnf_pkg_1, cls.vnfd_id_1 = cls.create_vnf_package(
|
||||||
|
pkg_path_1, image_path=image_path, userdata_path=userdata_path)
|
||||||
|
|
||||||
|
# for change_vnfpkg test
|
||||||
|
pkg_path_2 = os.path.join(cur_dir,
|
||||||
|
"../sol_v2_common/samples/userdata_standard_change_vnfpkg")
|
||||||
|
cls.vnf_pkg_2, cls.vnfd_id_2 = cls.create_vnf_package(
|
||||||
|
pkg_path_2, image_path=image_path, userdata_path=userdata_path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
super(IndividualVnfcMgmtTest, cls).tearDownClass()
|
||||||
|
cls.delete_vnf_package(cls.vnf_pkg_1)
|
||||||
|
cls.delete_vnf_package(cls.vnf_pkg_2)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
def _put_fail_file(self, operation):
|
||||||
|
with open(f'/tmp/{operation}', 'w'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _rm_fail_file(self, operation):
|
||||||
|
os.remove(f'/tmp/{operation}')
|
||||||
|
|
||||||
|
def _get_vdu_indexes(self, inst, vdu):
|
||||||
|
return {
|
||||||
|
vnfc['metadata'].get('vdu_idx')
|
||||||
|
for vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']
|
||||||
|
if vnfc['vduId'] == vdu
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_vnfc_by_vdu_index(self, inst, vdu, index):
|
||||||
|
for vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
|
||||||
|
if (vnfc['vduId'] == vdu and
|
||||||
|
vnfc['metadata'].get('vdu_idx') == index):
|
||||||
|
return vnfc
|
||||||
|
|
||||||
|
def _get_vnfc_id(self, inst, vdu, index):
|
||||||
|
vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index)
|
||||||
|
return vnfc['id']
|
||||||
|
|
||||||
|
def _get_vnfc_cp_net_id(self, inst, vdu, index, cp):
|
||||||
|
vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index)
|
||||||
|
for cp_info in vnfc['vnfcCpInfo']:
|
||||||
|
if cp_info['cpdId'] == cp:
|
||||||
|
# must be found
|
||||||
|
ext_cp_id = cp_info['vnfExtCpId']
|
||||||
|
break
|
||||||
|
for ext_vl in inst['instantiatedVnfInfo']['extVirtualLinkInfo']:
|
||||||
|
for port in ext_vl['extLinkPorts']:
|
||||||
|
if port['cpInstanceId'] == ext_cp_id:
|
||||||
|
# must be found
|
||||||
|
return ext_vl['resourceHandle']['resourceId']
|
||||||
|
|
||||||
|
def _get_vnfc_image(self, inst, vdu, index):
|
||||||
|
vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index)
|
||||||
|
for key, value in vnfc['metadata'].items():
|
||||||
|
if key.startswith('image-'):
|
||||||
|
# must be found
|
||||||
|
return value
|
||||||
|
|
||||||
|
def _delete_instance(self, inst_id):
|
||||||
|
for _ in range(3):
|
||||||
|
resp, body = self.delete_vnf_instance(inst_id)
|
||||||
|
if resp.status_code == 204: # OK
|
||||||
|
return
|
||||||
|
elif resp.status_code == 409:
|
||||||
|
# may happen. there is a bit time between lcmocc become
|
||||||
|
# COMPLETED and lock of terminate is freed.
|
||||||
|
time.sleep(3)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
self.assertTrue(False)
|
||||||
|
|
||||||
|
def test_basic_operations(self):
|
||||||
|
"""Test basic operations using StandardUserData
|
||||||
|
|
||||||
|
* Note:
|
||||||
|
This test focuses whether StandardUserData works well.
|
||||||
|
This test does not check overall items of APIs at all.
|
||||||
|
|
||||||
|
* About LCM operations:
|
||||||
|
This test includes the following operations.
|
||||||
|
- Create VNF instance
|
||||||
|
- 1. Instantiate VNF instance
|
||||||
|
- Show VNF instance / check
|
||||||
|
- 2. Scale out operation
|
||||||
|
- Show VNF instance / check
|
||||||
|
- 3. Heal operation
|
||||||
|
- Show VNF instance / check
|
||||||
|
- 4. Scale in operation
|
||||||
|
- Show VNF instance / check
|
||||||
|
- 5. Change_ext_conn operation
|
||||||
|
- Show VNF instance / check
|
||||||
|
- 6. Change_vnfpkg operation
|
||||||
|
- Show VNF instance / check
|
||||||
|
- Terminate VNF instance
|
||||||
|
- Delete VNF instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt'])
|
||||||
|
subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1'])
|
||||||
|
|
||||||
|
# Create VNF instance
|
||||||
|
create_req = paramgen.sample3_create(self.vnfd_id_1)
|
||||||
|
resp, body = self.create_vnf_instance(create_req)
|
||||||
|
self.assertEqual(201, resp.status_code)
|
||||||
|
inst_id = body['id']
|
||||||
|
|
||||||
|
# 1. Instantiate VNF instance
|
||||||
|
instantiate_req = paramgen.sample3_instantiate(
|
||||||
|
net_ids, subnet_ids, self.auth_url)
|
||||||
|
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_1 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check number of VDUs and indexes
|
||||||
|
self.assertEqual({0}, self._get_vdu_indexes(inst_1, 'VDU1'))
|
||||||
|
self.assertEqual({0}, self._get_vdu_indexes(inst_1, 'VDU2'))
|
||||||
|
|
||||||
|
# 2. Scale out operation
|
||||||
|
scale_out_req = paramgen.sample3_scale_out()
|
||||||
|
resp, body = self.scale_vnf_instance(inst_id, scale_out_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_2 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check number of VDUs and indexes
|
||||||
|
self.assertEqual({0, 1, 2}, self._get_vdu_indexes(inst_2, 'VDU1'))
|
||||||
|
self.assertEqual({0}, self._get_vdu_indexes(inst_2, 'VDU2'))
|
||||||
|
|
||||||
|
# 3. Heal operation
|
||||||
|
heal_req = paramgen.sample3_heal()
|
||||||
|
# pick up VDU1-1 to heal
|
||||||
|
vnfc_id = self._get_vnfc_id(inst_2, 'VDU1', 1)
|
||||||
|
heal_req['vnfcInstanceId'] = [f'VDU1-{vnfc_id}']
|
||||||
|
resp, body = self.heal_vnf_instance(inst_id, heal_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_3 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check id of VDU1-1 is changed and other are not.
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_2, 'VDU1', 0),
|
||||||
|
self._get_vnfc_id(inst_3, 'VDU1', 0))
|
||||||
|
self.assertNotEqual(self._get_vnfc_id(inst_2, 'VDU1', 1),
|
||||||
|
self._get_vnfc_id(inst_3, 'VDU1', 1))
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_2, 'VDU1', 2),
|
||||||
|
self._get_vnfc_id(inst_3, 'VDU1', 2))
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_2, 'VDU2', 0),
|
||||||
|
self._get_vnfc_id(inst_3, 'VDU2', 0))
|
||||||
|
|
||||||
|
# 4. Scale in operation
|
||||||
|
scale_in_req = paramgen.sample3_scale_in()
|
||||||
|
resp, body = self.scale_vnf_instance(inst_id, scale_in_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_4 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check VDU1-2 is removed. other are not changed.
|
||||||
|
self.assertEqual({0, 1}, self._get_vdu_indexes(inst_4, 'VDU1'))
|
||||||
|
self.assertEqual({0}, self._get_vdu_indexes(inst_4, 'VDU2'))
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_3, 'VDU1', 0),
|
||||||
|
self._get_vnfc_id(inst_4, 'VDU1', 0))
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_3, 'VDU1', 1),
|
||||||
|
self._get_vnfc_id(inst_4, 'VDU1', 1))
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_3, 'VDU2', 0),
|
||||||
|
self._get_vnfc_id(inst_4, 'VDU2', 0))
|
||||||
|
|
||||||
|
# 5. Change_ext_conn operation
|
||||||
|
change_ext_conn_req = paramgen.sample3_change_ext_conn(net_ids)
|
||||||
|
resp, body = self.change_ext_conn(inst_id, change_ext_conn_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_5 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check VDU1_CP1 is changed to net0 from net1. other are not changed.
|
||||||
|
self.assertEqual(net_ids['net1'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_4, 'VDU1', 0, 'VDU1_CP1'))
|
||||||
|
self.assertEqual(net_ids['net1'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_4, 'VDU1', 1, 'VDU1_CP1'))
|
||||||
|
self.assertEqual(net_ids['net1'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_4, 'VDU2', 0, 'VDU2_CP1'))
|
||||||
|
self.assertEqual(net_ids['net0'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_5, 'VDU1', 0, 'VDU1_CP1'))
|
||||||
|
self.assertEqual(net_ids['net0'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_5, 'VDU1', 1, 'VDU1_CP1'))
|
||||||
|
self.assertEqual(net_ids['net1'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_5, 'VDU2', 0, 'VDU2_CP1'))
|
||||||
|
|
||||||
|
# 6. Change_vnfpkg operation
|
||||||
|
change_vnfpkg_req = paramgen.sample4_change_vnfpkg(self.vnfd_id_2)
|
||||||
|
resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_6 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check vnfdId is changed
|
||||||
|
self.assertEqual(self.vnfd_id_2, inst_6['vnfdId'])
|
||||||
|
# check images are changed
|
||||||
|
self.assertNotEqual(self._get_vnfc_image(inst_5, 'VDU1', 0),
|
||||||
|
self._get_vnfc_image(inst_6, 'VDU1', 0))
|
||||||
|
self.assertNotEqual(self._get_vnfc_image(inst_5, 'VDU1', 1),
|
||||||
|
self._get_vnfc_image(inst_6, 'VDU1', 1))
|
||||||
|
self.assertNotEqual(self._get_vnfc_image(inst_5, 'VDU2', 0),
|
||||||
|
self._get_vnfc_image(inst_6, 'VDU2', 0))
|
||||||
|
|
||||||
|
# Terminate VNF instance
|
||||||
|
terminate_req = paramgen.sample4_terminate()
|
||||||
|
resp, body = self.terminate_vnf_instance(inst_id, terminate_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Delete VNF instance
|
||||||
|
self._delete_instance(inst_id)
|
||||||
|
|
||||||
|
def test_rollback_operations(self):
|
||||||
|
"""Test rollback operations using StandardUserData
|
||||||
|
|
||||||
|
* Note:
|
||||||
|
This test focuses whether StandardUserData works well.
|
||||||
|
This test does not check overall items of APIs at all.
|
||||||
|
|
||||||
|
* About LCM operations:
|
||||||
|
This test includes the following operations.
|
||||||
|
- Create VNF instance
|
||||||
|
- Instantiate VNF instance
|
||||||
|
- Show VNF instance
|
||||||
|
- 1. Scale out operation => FAILED_TEMP
|
||||||
|
- Rollback
|
||||||
|
- Show VNF instance / check
|
||||||
|
- 2. Change_ext_conn operation => FAILED_TEMP
|
||||||
|
- Rollback
|
||||||
|
- Show VNF instance / check
|
||||||
|
- 3. Change_vnfpkg operation => FAILED_TEMP
|
||||||
|
- Rollback
|
||||||
|
- Show VNF instance / check
|
||||||
|
- Terminate VNF instance
|
||||||
|
- Delete VNF instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt'])
|
||||||
|
subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1'])
|
||||||
|
|
||||||
|
# Create VNF instance
|
||||||
|
create_req = paramgen.sample3_create(self.vnfd_id_1)
|
||||||
|
resp, body = self.create_vnf_instance(create_req)
|
||||||
|
self.assertEqual(201, resp.status_code)
|
||||||
|
inst_id = body['id']
|
||||||
|
|
||||||
|
# Instantiate VNF instance
|
||||||
|
instantiate_req = paramgen.sample3_instantiate(
|
||||||
|
net_ids, subnet_ids, self.auth_url)
|
||||||
|
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_0 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# 1. Scale out operation
|
||||||
|
self._put_fail_file('scale_end')
|
||||||
|
scale_out_req = paramgen.sample3_scale_out()
|
||||||
|
resp, body = self.scale_vnf_instance(inst_id, scale_out_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_failed_temp(lcmocc_id)
|
||||||
|
self._rm_fail_file('scale_end')
|
||||||
|
|
||||||
|
# Rollback
|
||||||
|
resp, body = self.rollback_lcmocc(lcmocc_id)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
self.wait_lcmocc_rolled_back(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_1 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check number of vnfc and its id are not changed.
|
||||||
|
self.assertEqual(self._get_vdu_indexes(inst_0, 'VDU1'),
|
||||||
|
self._get_vdu_indexes(inst_1, 'VDU1'))
|
||||||
|
self.assertEqual(self._get_vdu_indexes(inst_0, 'VDU2'),
|
||||||
|
self._get_vdu_indexes(inst_1, 'VDU2'))
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_0, 'VDU1', 0),
|
||||||
|
self._get_vnfc_id(inst_1, 'VDU1', 0))
|
||||||
|
self.assertEqual(self._get_vnfc_id(inst_0, 'VDU2', 0),
|
||||||
|
self._get_vnfc_id(inst_1, 'VDU2', 0))
|
||||||
|
|
||||||
|
# 2. Change_ext_conn operation
|
||||||
|
self._put_fail_file('change_external_connectivity_end')
|
||||||
|
change_ext_conn_req = paramgen.sample3_change_ext_conn(net_ids)
|
||||||
|
resp, body = self.change_ext_conn(inst_id, change_ext_conn_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_failed_temp(lcmocc_id)
|
||||||
|
self._rm_fail_file('change_external_connectivity_end')
|
||||||
|
|
||||||
|
# Rollback
|
||||||
|
resp, body = self.rollback_lcmocc(lcmocc_id)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
self.wait_lcmocc_rolled_back(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_2 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check network of extVL cps are not changed. (i.e. net1)
|
||||||
|
self.assertEqual(net_ids['net1'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_2, 'VDU1', 0, 'VDU1_CP1'))
|
||||||
|
self.assertEqual(net_ids['net1'],
|
||||||
|
self._get_vnfc_cp_net_id(inst_2, 'VDU2', 0, 'VDU2_CP1'))
|
||||||
|
|
||||||
|
# 3. Change_vnfpkg operation
|
||||||
|
self._put_fail_file('change_vnfpkg')
|
||||||
|
change_vnfpkg_req = paramgen.sample4_change_vnfpkg(self.vnfd_id_2)
|
||||||
|
resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_failed_temp(lcmocc_id)
|
||||||
|
self._rm_fail_file('change_vnfpkg')
|
||||||
|
|
||||||
|
# Rollback
|
||||||
|
resp, body = self.rollback_lcmocc(lcmocc_id)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
self.wait_lcmocc_rolled_back(lcmocc_id)
|
||||||
|
|
||||||
|
# Show VNF instance
|
||||||
|
resp, inst_3 = self.show_vnf_instance(inst_id)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# check vnfdId is not changed
|
||||||
|
self.assertEqual(self.vnfd_id_1, inst_3['vnfdId'])
|
||||||
|
# check images are not changed
|
||||||
|
self.assertEqual(self._get_vnfc_image(inst_2, 'VDU1', 0),
|
||||||
|
self._get_vnfc_image(inst_3, 'VDU1', 0))
|
||||||
|
self.assertEqual(self._get_vnfc_image(inst_2, 'VDU2', 0),
|
||||||
|
self._get_vnfc_image(inst_3, 'VDU2', 0))
|
||||||
|
|
||||||
|
# Terminate VNF instance
|
||||||
|
terminate_req = paramgen.sample3_terminate()
|
||||||
|
resp, body = self.terminate_vnf_instance(inst_id, terminate_req)
|
||||||
|
self.assertEqual(202, resp.status_code)
|
||||||
|
|
||||||
|
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||||
|
self.wait_lcmocc_complete(lcmocc_id)
|
||||||
|
|
||||||
|
# Delete VNF instance
|
||||||
|
self._delete_instance(inst_id)
|
|
@ -107,11 +107,12 @@ class BaseSolV2Test(base.BaseTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_vnf_package(cls, sample_path, user_data={},
|
def create_vnf_package(cls, sample_path, user_data={},
|
||||||
image_path=None, nfvo=False):
|
image_path=None, nfvo=False, userdata_path=None):
|
||||||
vnfd_id = uuidutils.generate_uuid()
|
vnfd_id = uuidutils.generate_uuid()
|
||||||
tmp_dir = tempfile.mkdtemp()
|
tmp_dir = tempfile.mkdtemp()
|
||||||
|
|
||||||
utils.make_zip(sample_path, tmp_dir, vnfd_id, image_path)
|
utils.make_zip(sample_path, tmp_dir, vnfd_id, image_path,
|
||||||
|
userdata_path)
|
||||||
|
|
||||||
zip_file_name = os.path.basename(os.path.abspath(sample_path)) + ".zip"
|
zip_file_name = os.path.basename(os.path.abspath(sample_path)) + ".zip"
|
||||||
zip_file_path = os.path.join(tmp_dir, zip_file_name)
|
zip_file_path = os.path.join(tmp_dir, zip_file_name)
|
||||||
|
|
|
@ -933,3 +933,197 @@ def change_vnfpkg(vnfd_id):
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# sample3 is used for tests of StandardUserData
|
||||||
|
#
|
||||||
|
def sample3_create(vnfd_id):
|
||||||
|
return {
|
||||||
|
"vnfdId": vnfd_id,
|
||||||
|
"vnfInstanceName": "sample3",
|
||||||
|
"vnfInstanceDescription": "test for StandardUserData"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sample3_terminate():
|
||||||
|
return {
|
||||||
|
"terminationType": "FORCEFUL"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sample3_instantiate(net_ids, subnet_ids, auth_url):
|
||||||
|
ext_vl_1 = {
|
||||||
|
"id": uuidutils.generate_uuid(),
|
||||||
|
"resourceId": net_ids['net1'],
|
||||||
|
"extCps": [
|
||||||
|
{
|
||||||
|
"cpdId": "VDU1_CP1",
|
||||||
|
"cpConfig": {
|
||||||
|
"VDU1_CP2_1": {
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET",
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"numDynamicAddresses": 1}]}}]}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cpdId": "VDU2_CP1",
|
||||||
|
"cpConfig": {
|
||||||
|
"VDU2_CP2_1": {
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET",
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"numDynamicAddresses": 1,
|
||||||
|
"subnetId": subnet_ids['subnet1']}]}}]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"flavourId": "simple",
|
||||||
|
"instantiationLevelId": "instantiation_level_1",
|
||||||
|
"extVirtualLinks": [ext_vl_1],
|
||||||
|
"extManagedVirtualLinks": [
|
||||||
|
{
|
||||||
|
"id": uuidutils.generate_uuid(),
|
||||||
|
"vnfVirtualLinkDescId": "internalVL1",
|
||||||
|
"resourceId": net_ids['net_mgmt']
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"vimConnectionInfo": {
|
||||||
|
"vim1": {
|
||||||
|
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
|
||||||
|
"vimId": uuidutils.generate_uuid(),
|
||||||
|
"interfaceInfo": {"endpoint": auth_url},
|
||||||
|
"accessInfo": {
|
||||||
|
"username": "nfv_user",
|
||||||
|
"region": "RegionOne",
|
||||||
|
"password": "devstack",
|
||||||
|
"project": "nfv",
|
||||||
|
"projectDomain": "Default",
|
||||||
|
"userDomain": "Default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalParams": {
|
||||||
|
"lcm-operation-user-data": "./UserData/userdata_standard.py",
|
||||||
|
"lcm-operation-user-data-class": "StandardUserData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sample3_scale_out():
|
||||||
|
return {
|
||||||
|
"type": "SCALE_OUT",
|
||||||
|
"aspectId": "VDU1_scale",
|
||||||
|
"numberOfSteps": 2,
|
||||||
|
"additionalParams": {
|
||||||
|
"lcm-operation-user-data": "./UserData/userdata_standard.py",
|
||||||
|
"lcm-operation-user-data-class": "StandardUserData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sample3_scale_in():
|
||||||
|
return {
|
||||||
|
"type": "SCALE_IN",
|
||||||
|
"aspectId": "VDU1_scale",
|
||||||
|
"numberOfSteps": 1,
|
||||||
|
"additionalParams": {
|
||||||
|
"lcm-operation-user-data": "./UserData/userdata_standard.py",
|
||||||
|
"lcm-operation-user-data-class": "StandardUserData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sample3_heal():
|
||||||
|
return {
|
||||||
|
"vnfcInstanceId": [], # should be filled
|
||||||
|
"additionalParams": {
|
||||||
|
"lcm-operation-user-data": "./UserData/userdata_standard.py",
|
||||||
|
"lcm-operation-user-data-class": "StandardUserData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sample3_change_ext_conn(net_ids):
|
||||||
|
return {
|
||||||
|
"extVirtualLinks": [
|
||||||
|
{
|
||||||
|
"id": uuidutils.generate_uuid(),
|
||||||
|
"resourceId": net_ids['net0'],
|
||||||
|
"extCps": [
|
||||||
|
{
|
||||||
|
"cpdId": "VDU1_CP1",
|
||||||
|
"cpConfig": {
|
||||||
|
"VDU1_CP2_1": {
|
||||||
|
"cpProtocolData": [{
|
||||||
|
"layerProtocol": "IP_OVER_ETHERNET",
|
||||||
|
"ipOverEthernet": {
|
||||||
|
"ipAddresses": [{
|
||||||
|
"type": "IPV4",
|
||||||
|
"numDynamicAddresses": 1}]}}]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalParams": {
|
||||||
|
"lcm-operation-user-data": "./UserData/userdata_standard.py",
|
||||||
|
"lcm-operation-user-data-class": "StandardUserData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# sample4 is for change_vnfpkg test of StandardUserData
|
||||||
|
#
|
||||||
|
def sample4_change_vnfpkg(vnfd_id):
|
||||||
|
return {
|
||||||
|
"vnfdId": vnfd_id,
|
||||||
|
"additionalParams": {
|
||||||
|
"upgrade_type": "RollingUpdate",
|
||||||
|
"lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_vnf.py",
|
||||||
|
"lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_vnf.py",
|
||||||
|
"vdu_params": [
|
||||||
|
{
|
||||||
|
"vdu_id": "VDU1",
|
||||||
|
"old_vnfc_param": {
|
||||||
|
"cp_name": "VDU1_CP1",
|
||||||
|
"username": "ubuntu",
|
||||||
|
"password": "ubuntu"
|
||||||
|
},
|
||||||
|
"new_vnfc_param": {
|
||||||
|
"cp_name": "VDU1_CP1",
|
||||||
|
"username": "ubuntu",
|
||||||
|
"password": "ubuntu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vdu_id": "VDU2",
|
||||||
|
"old_vnfc_param": {
|
||||||
|
"cp_name": "VDU2_CP1",
|
||||||
|
"username": "ubuntu",
|
||||||
|
"password": "ubuntu"
|
||||||
|
},
|
||||||
|
"new_vnfc_param": {
|
||||||
|
"cp_name": "VDU2_CP1",
|
||||||
|
"username": "ubuntu",
|
||||||
|
"password": "ubuntu"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lcm-operation-user-data": "./UserData/userdata_standard.py",
|
||||||
|
"lcm-operation-user-data-class": "StandardUserData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sample4_terminate():
|
||||||
|
return {
|
||||||
|
"terminationType": "FORCEFUL"
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'VDU1 HOT for Sample VNF'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
flavor:
|
||||||
|
type: string
|
||||||
|
image-VDU1:
|
||||||
|
type: string
|
||||||
|
net1:
|
||||||
|
type: string
|
||||||
|
net2:
|
||||||
|
type: string
|
||||||
|
net3:
|
||||||
|
type: string
|
||||||
|
affinity:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: flavor }
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: image-VDU1 }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: VDU1_CP1
|
||||||
|
# replace the following line to Port ID when extmanagedVLs' Ports are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
- port:
|
||||||
|
get_resource: VDU1_CP2
|
||||||
|
- port:
|
||||||
|
get_resource: VDU1_CP3
|
||||||
|
scheduler_hints:
|
||||||
|
group: { get_param: affinity }
|
||||||
|
|
||||||
|
# extVL without FixedIP or with numDynamicAddresses
|
||||||
|
VDU1_CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net1 }
|
||||||
|
|
||||||
|
# CPs of internal VLs are deleted when extmanagedVLs and port are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
VDU1_CP2:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net2 }
|
||||||
|
|
||||||
|
VDU1_CP3:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net3 }
|
|
@ -0,0 +1,69 @@
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'VDU2 HOT for Sample VNF'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
flavor:
|
||||||
|
type: string
|
||||||
|
image-VDU2-VirtualStorage:
|
||||||
|
type: string
|
||||||
|
net1:
|
||||||
|
type: string
|
||||||
|
net2:
|
||||||
|
type: string
|
||||||
|
net3:
|
||||||
|
type: string
|
||||||
|
subnet1:
|
||||||
|
type: string
|
||||||
|
affinity:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU2:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: flavor }
|
||||||
|
name: VDU2
|
||||||
|
block_device_mapping_v2: [{"volume_id": { get_resource: VDU2-VirtualStorage }}]
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: VDU2_CP1
|
||||||
|
# replace the following line to Port ID when extmanagedVLs' Ports are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
- port:
|
||||||
|
get_resource: VDU2_CP2
|
||||||
|
- port:
|
||||||
|
get_resource: VDU2_CP3
|
||||||
|
scheduler_hints:
|
||||||
|
group: {get_param: affinity }
|
||||||
|
|
||||||
|
VDU2-VirtualStorage:
|
||||||
|
type: OS::Cinder::Volume
|
||||||
|
properties:
|
||||||
|
image: { get_param: image-VDU2-VirtualStorage }
|
||||||
|
size: 1
|
||||||
|
volume_type: { get_resource: multi }
|
||||||
|
multi:
|
||||||
|
type: OS::Cinder::VolumeType
|
||||||
|
properties:
|
||||||
|
name: VDU2-multi
|
||||||
|
metadata: { multiattach: "<is> True" }
|
||||||
|
|
||||||
|
# extVL with numDynamicAddresses and subnet
|
||||||
|
VDU2_CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net1 }
|
||||||
|
fixed_ips:
|
||||||
|
- subnet: { get_param: subnet1 }
|
||||||
|
|
||||||
|
# CPs of internal VLs are deleted when extmanagedVLs and port are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
VDU2_CP2:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net2 }
|
||||||
|
|
||||||
|
VDU2_CP3:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net3 }
|
|
@ -0,0 +1,57 @@
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Simple Base HOT for Sample VNF'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: VDU1.yaml
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
|
||||||
|
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
|
||||||
|
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
|
||||||
|
net2: { get_resource: internalVL1 }
|
||||||
|
net3: { get_resource: internalVL2 }
|
||||||
|
affinity: { get_resource: nfvi_node_affinity }
|
||||||
|
|
||||||
|
VDU2:
|
||||||
|
type: VDU2.yaml
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: [ nfv, VDU, VDU2, computeFlavourId ] }
|
||||||
|
image-VDU2-VirtualStorage: { get_param: [ nfv, VDU, VDU2-VirtualStorage, vcImageId ] }
|
||||||
|
net1: { get_param: [ nfv, CP, VDU2_CP1, network ] }
|
||||||
|
subnet1: { get_param: [nfv, CP, VDU2_CP1, fixed_ips, 0, subnet ]}
|
||||||
|
net2: { get_resource: internalVL1 }
|
||||||
|
net3: { get_resource: internalVL2 }
|
||||||
|
affinity: { get_resource: nfvi_node_affinity }
|
||||||
|
|
||||||
|
# delete the following lines when extmanagedVLs are specified in instantiatevnfrequest
|
||||||
|
internalVL1:
|
||||||
|
type: OS::Neutron::Net
|
||||||
|
internalVL2:
|
||||||
|
type: OS::Neutron::Net
|
||||||
|
|
||||||
|
internalVL1_subnet:
|
||||||
|
type: OS::Neutron::Subnet
|
||||||
|
properties:
|
||||||
|
ip_version: 4
|
||||||
|
network:
|
||||||
|
get_resource: internalVL1
|
||||||
|
cidr: 192.168.3.0/24
|
||||||
|
internalVL2_subnet:
|
||||||
|
type: OS::Neutron::Subnet
|
||||||
|
properties:
|
||||||
|
ip_version: 4
|
||||||
|
network:
|
||||||
|
get_resource: internalVL2
|
||||||
|
cidr: 192.168.4.0/24
|
||||||
|
|
||||||
|
nfvi_node_affinity:
|
||||||
|
type: OS::Nova::ServerGroup
|
||||||
|
properties:
|
||||||
|
name: nfvi_node_affinity
|
||||||
|
policies: [ 'affinity' ]
|
||||||
|
|
||||||
|
outputs: {}
|
|
@ -0,0 +1,357 @@
|
||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: Simple deployment flavour for Sample VNF
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
- v2_sample3_types.yaml
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
inputs:
|
||||||
|
descriptor_id:
|
||||||
|
type: string
|
||||||
|
descriptor_version:
|
||||||
|
type: string
|
||||||
|
provider:
|
||||||
|
type: string
|
||||||
|
product_name:
|
||||||
|
type: string
|
||||||
|
software_version:
|
||||||
|
type: string
|
||||||
|
vnfm_info:
|
||||||
|
type: list
|
||||||
|
entry_schema:
|
||||||
|
type: string
|
||||||
|
flavour_id:
|
||||||
|
type: string
|
||||||
|
flavour_description:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
substitution_mappings:
|
||||||
|
node_type: company.provider.VNF
|
||||||
|
properties:
|
||||||
|
flavour_id: simple
|
||||||
|
requirements:
|
||||||
|
virtual_link_external1_1: [ VDU1_CP1, virtual_link ]
|
||||||
|
virtual_link_external1_2: [ VDU2_CP1, virtual_link ]
|
||||||
|
|
||||||
|
node_templates:
|
||||||
|
VNF:
|
||||||
|
type: company.provider.VNF
|
||||||
|
properties:
|
||||||
|
flavour_description: A simple flavour
|
||||||
|
interfaces:
|
||||||
|
Vnflcm:
|
||||||
|
instantiate_start:
|
||||||
|
implementation: sample-script
|
||||||
|
instantiate_end:
|
||||||
|
implementation: sample-script
|
||||||
|
terminate_start:
|
||||||
|
implementation: sample-script
|
||||||
|
terminate_end:
|
||||||
|
implementation: sample-script
|
||||||
|
scale_start:
|
||||||
|
implementation: sample-script
|
||||||
|
scale_end:
|
||||||
|
implementation: sample-script
|
||||||
|
heal_start:
|
||||||
|
implementation: sample-script
|
||||||
|
heal_end:
|
||||||
|
implementation: sample-script
|
||||||
|
change_external_connectivity_start:
|
||||||
|
implementation: sample-script
|
||||||
|
change_external_connectivity_end:
|
||||||
|
implementation: sample-script
|
||||||
|
modify_information_start:
|
||||||
|
implementation: sample-script
|
||||||
|
modify_information_end:
|
||||||
|
implementation: sample-script
|
||||||
|
artifacts:
|
||||||
|
sample-script:
|
||||||
|
description: Sample script
|
||||||
|
type: tosca.artifacts.Implementation.Python
|
||||||
|
file: ../Scripts/sample_script.py
|
||||||
|
|
||||||
|
VDU1:
|
||||||
|
type: tosca.nodes.nfv.Vdu.Compute
|
||||||
|
properties:
|
||||||
|
name: VDU1
|
||||||
|
description: VDU1 compute node
|
||||||
|
vdu_profile:
|
||||||
|
min_number_of_instances: 1
|
||||||
|
max_number_of_instances: 3
|
||||||
|
sw_image_data:
|
||||||
|
name: cirros-0.5.2-x86_64-disk
|
||||||
|
version: '0.5.2'
|
||||||
|
checksum:
|
||||||
|
algorithm: sha-256
|
||||||
|
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||||
|
container_format: bare
|
||||||
|
disk_format: qcow2
|
||||||
|
min_disk: 0 GB
|
||||||
|
min_ram: 256 MB
|
||||||
|
size: 12 GB
|
||||||
|
capabilities:
|
||||||
|
virtual_compute:
|
||||||
|
properties:
|
||||||
|
requested_additional_capabilities:
|
||||||
|
properties:
|
||||||
|
requested_additional_capability_name: m1.tiny
|
||||||
|
support_mandatory: true
|
||||||
|
target_performance_parameters:
|
||||||
|
entry_schema: test
|
||||||
|
virtual_memory:
|
||||||
|
virtual_mem_size: 512 MB
|
||||||
|
virtual_cpu:
|
||||||
|
num_virtual_cpu: 1
|
||||||
|
virtual_local_storage:
|
||||||
|
- size_of_storage: 3 GB
|
||||||
|
|
||||||
|
VDU2:
|
||||||
|
type: tosca.nodes.nfv.Vdu.Compute
|
||||||
|
properties:
|
||||||
|
name: VDU2
|
||||||
|
description: VDU2 compute node
|
||||||
|
vdu_profile:
|
||||||
|
min_number_of_instances: 1
|
||||||
|
max_number_of_instances: 1
|
||||||
|
capabilities:
|
||||||
|
virtual_compute:
|
||||||
|
properties:
|
||||||
|
requested_additional_capabilities:
|
||||||
|
properties:
|
||||||
|
requested_additional_capability_name: m1.tiny
|
||||||
|
support_mandatory: true
|
||||||
|
target_performance_parameters:
|
||||||
|
entry_schema: test
|
||||||
|
virtual_memory:
|
||||||
|
virtual_mem_size: 512 MB
|
||||||
|
virtual_cpu:
|
||||||
|
num_virtual_cpu: 1
|
||||||
|
virtual_local_storage:
|
||||||
|
- size_of_storage: 3 GB
|
||||||
|
requirements:
|
||||||
|
- virtual_storage: VDU2-VirtualStorage
|
||||||
|
|
||||||
|
VDU2-VirtualStorage:
|
||||||
|
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
|
||||||
|
properties:
|
||||||
|
virtual_block_storage_data:
|
||||||
|
size_of_storage: 1 GB
|
||||||
|
rdma_enabled: true
|
||||||
|
sw_image_data:
|
||||||
|
name: VDU2-VirtualStorage-image
|
||||||
|
version: '0.5.2'
|
||||||
|
checksum:
|
||||||
|
algorithm: sha-256
|
||||||
|
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||||
|
container_format: bare
|
||||||
|
disk_format: qcow2
|
||||||
|
min_disk: 0 GB
|
||||||
|
min_ram: 256 MB
|
||||||
|
size: 12 GB
|
||||||
|
artifacts:
|
||||||
|
sw_image:
|
||||||
|
type: tosca.artifacts.nfv.SwImage
|
||||||
|
file: ../Files/images/cirros-0.5.2-x86_64-disk.img
|
||||||
|
|
||||||
|
VDU1_CP1:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 0
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
||||||
|
|
||||||
|
VDU1_CP2:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 1
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
||||||
|
- virtual_link: internalVL1
|
||||||
|
|
||||||
|
VDU1_CP3:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 2
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
||||||
|
- virtual_link: internalVL2
|
||||||
|
|
||||||
|
VDU2_CP1:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 0
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU2
|
||||||
|
|
||||||
|
VDU2_CP2:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 1
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU2
|
||||||
|
- virtual_link: internalVL1
|
||||||
|
|
||||||
|
VDU2_CP3:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 2
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU2
|
||||||
|
- virtual_link: internalVL2
|
||||||
|
|
||||||
|
internalVL1:
|
||||||
|
type: tosca.nodes.nfv.VnfVirtualLink
|
||||||
|
properties:
|
||||||
|
connectivity_type:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
description: External Managed Virtual link in the VNF
|
||||||
|
vl_profile:
|
||||||
|
max_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
min_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
virtual_link_protocol_data:
|
||||||
|
- associated_layer_protocol: ipv4
|
||||||
|
l3_protocol_data:
|
||||||
|
ip_version: ipv4
|
||||||
|
cidr: 192.168.3.0/24
|
||||||
|
|
||||||
|
internalVL2:
|
||||||
|
type: tosca.nodes.nfv.VnfVirtualLink
|
||||||
|
properties:
|
||||||
|
connectivity_type:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
description: External Managed Virtual link in the VNF
|
||||||
|
vl_profile:
|
||||||
|
max_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
min_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
virtual_link_protocol_data:
|
||||||
|
- associated_layer_protocol: ipv4
|
||||||
|
l3_protocol_data:
|
||||||
|
ip_version: ipv4
|
||||||
|
cidr: 192.168.4.0/24
|
||||||
|
|
||||||
|
groups:
|
||||||
|
affinityOrAntiAffinityGroup1:
|
||||||
|
type: tosca.groups.nfv.PlacementGroup
|
||||||
|
members: [ VDU1, VDU2 ]
|
||||||
|
|
||||||
|
policies:
|
||||||
|
- scaling_aspects:
|
||||||
|
type: tosca.policies.nfv.ScalingAspects
|
||||||
|
properties:
|
||||||
|
aspects:
|
||||||
|
VDU1_scale:
|
||||||
|
name: VDU1_scale
|
||||||
|
description: VDU1 scaling aspect
|
||||||
|
max_scale_level: 2
|
||||||
|
step_deltas:
|
||||||
|
- delta_1
|
||||||
|
|
||||||
|
- VDU1_initial_delta:
|
||||||
|
type: tosca.policies.nfv.VduInitialDelta
|
||||||
|
properties:
|
||||||
|
initial_delta:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU1 ]
|
||||||
|
|
||||||
|
- VDU2_initial_delta:
|
||||||
|
type: tosca.policies.nfv.VduInitialDelta
|
||||||
|
properties:
|
||||||
|
initial_delta:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU2 ]
|
||||||
|
|
||||||
|
- VDU1_scaling_aspect_deltas:
|
||||||
|
type: tosca.policies.nfv.VduScalingAspectDeltas
|
||||||
|
properties:
|
||||||
|
aspect: VDU1_scale
|
||||||
|
deltas:
|
||||||
|
delta_1:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU1 ]
|
||||||
|
|
||||||
|
- instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.InstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
description: Smallest size
|
||||||
|
scale_info:
|
||||||
|
VDU1_scale:
|
||||||
|
scale_level: 0
|
||||||
|
instantiation_level_2:
|
||||||
|
description: Largest size
|
||||||
|
scale_info:
|
||||||
|
VDU1_scale:
|
||||||
|
scale_level: 1
|
||||||
|
default_level: instantiation_level_1
|
||||||
|
|
||||||
|
- VDU1_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VduInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
number_of_instances: 1
|
||||||
|
instantiation_level_2:
|
||||||
|
number_of_instances: 2
|
||||||
|
targets: [ VDU1 ]
|
||||||
|
|
||||||
|
- VDU2_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VduInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
number_of_instances: 1
|
||||||
|
instantiation_level_2:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU2 ]
|
||||||
|
|
||||||
|
- internalVL1_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
instantiation_level_2:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
targets: [ internalVL1 ]
|
||||||
|
|
||||||
|
- internalVL2_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
instantiation_level_2:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
targets: [ internalVL2 ]
|
||||||
|
|
||||||
|
- policy_antiaffinity_group:
|
||||||
|
type: tosca.policies.nfv.AntiAffinityRule
|
||||||
|
targets: [ affinityOrAntiAffinityGroup1 ]
|
||||||
|
properties:
|
||||||
|
scope: nfvi_node
|
|
@ -0,0 +1,31 @@
|
||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: Sample VNF
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
- v2_sample3_types.yaml
|
||||||
|
- v2_sample3_df_simple.yaml
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
inputs:
|
||||||
|
selected_flavour:
|
||||||
|
type: string
|
||||||
|
description: VNF deployment flavour selected by the consumer. It is provided in the API
|
||||||
|
|
||||||
|
node_templates:
|
||||||
|
VNF:
|
||||||
|
type: company.provider.VNF
|
||||||
|
properties:
|
||||||
|
flavour_id: { get_input: selected_flavour }
|
||||||
|
descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
|
||||||
|
provider: Company
|
||||||
|
product_name: Sample VNF
|
||||||
|
software_version: '1.0'
|
||||||
|
descriptor_version: '1.0'
|
||||||
|
vnfm_info:
|
||||||
|
- Tacker
|
||||||
|
requirements:
|
||||||
|
#- virtual_link_external # mapped in lower-level templates
|
||||||
|
#- virtual_link_internal # mapped in lower-level templates
|
|
@ -0,0 +1,55 @@
|
||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: VNF type definition
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
|
||||||
|
node_types:
|
||||||
|
company.provider.VNF:
|
||||||
|
derived_from: tosca.nodes.nfv.VNF
|
||||||
|
properties:
|
||||||
|
descriptor_id:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ]
|
||||||
|
default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
|
||||||
|
descriptor_version:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ '1.0' ] ]
|
||||||
|
default: '1.0'
|
||||||
|
provider:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ 'Company' ] ]
|
||||||
|
default: 'Company'
|
||||||
|
product_name:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ 'Sample VNF' ] ]
|
||||||
|
default: 'Sample VNF'
|
||||||
|
software_version:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ '1.0' ] ]
|
||||||
|
default: '1.0'
|
||||||
|
vnfm_info:
|
||||||
|
type: list
|
||||||
|
entry_schema:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ Tacker ] ]
|
||||||
|
default: [ Tacker ]
|
||||||
|
flavour_id:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ simple ] ]
|
||||||
|
default: simple
|
||||||
|
flavour_description:
|
||||||
|
type: string
|
||||||
|
default: "flavour"
|
||||||
|
requirements:
|
||||||
|
- virtual_link_external1:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
- virtual_link_external2:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
- virtual_link_internal:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
interfaces:
|
||||||
|
Vnflcm:
|
||||||
|
type: tosca.interfaces.nfv.Vnflcm
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class FailScript(object):
|
||||||
|
def __init__(self, vnfc_param):
|
||||||
|
self.vnfc_param = vnfc_param
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
operation = 'change_vnfpkg'
|
||||||
|
if self.vnfc_param['is_rollback']:
|
||||||
|
operation += '_rollback'
|
||||||
|
if os.path.exists(f'/tmp/{operation}'):
|
||||||
|
raise Exception(f'test {operation} error')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
vnfc_param = pickle.load(sys.stdin.buffer)
|
||||||
|
script = FailScript(vnfc_param)
|
||||||
|
script.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
os._exit(0)
|
||||||
|
except Exception as ex:
|
||||||
|
sys.stderr.write(str(ex))
|
||||||
|
sys.stderr.flush()
|
||||||
|
os._exit(1)
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class FailScript(object):
|
||||||
|
"""Define error method for each operation
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
def instantiate_start(self):
|
||||||
|
if os.path.exists('/tmp/instantiate_start')
|
||||||
|
raise Exception('test instantiate_start error')
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, req, inst, grant_req, grant, csar_dir):
|
||||||
|
self.req = req
|
||||||
|
self.inst = inst
|
||||||
|
self.grant_req = grant_req
|
||||||
|
self.grant = grant
|
||||||
|
self.csar_dir = csar_dir
|
||||||
|
|
||||||
|
def _fail(self, method):
|
||||||
|
if os.path.exists(f'/tmp/{method}'):
|
||||||
|
raise Exception(f'test {method} error')
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return functools.partial(self._fail, name)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
script_dict = pickle.load(sys.stdin.buffer)
|
||||||
|
|
||||||
|
operation = script_dict['operation']
|
||||||
|
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']
|
||||||
|
|
||||||
|
script = FailScript(req, inst, grant_req, grant, csar_dir)
|
||||||
|
getattr(script, operation)()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
os._exit(0)
|
||||||
|
except Exception as ex:
|
||||||
|
sys.stderr.write(str(ex))
|
||||||
|
sys.stderr.flush()
|
||||||
|
os._exit(1)
|
|
@ -0,0 +1,4 @@
|
||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Created-by: Onboarding portal
|
||||||
|
Entry-Definitions: Definitions/v2_sample3_top.vnfd.yaml
|
|
@ -0,0 +1,83 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
from tacker.tests.functional.sol_v2_common import paramgen
|
||||||
|
from tacker.tests.functional.sol_v2_common import utils
|
||||||
|
|
||||||
|
|
||||||
|
zip_file_name = os.path.basename(os.path.abspath(".")) + '.zip'
|
||||||
|
tmp_dir = tempfile.mkdtemp()
|
||||||
|
vnfd_id = uuidutils.generate_uuid()
|
||||||
|
|
||||||
|
# tacker/tests/etc...
|
||||||
|
# /functional/sol_v2_common/samples/smapleX
|
||||||
|
image_dir = "../../../../etc/samples/etsi/nfv/common/Files/images/"
|
||||||
|
image_file = "cirros-0.5.2-x86_64-disk.img"
|
||||||
|
image_path = os.path.abspath(image_dir + image_file)
|
||||||
|
|
||||||
|
# tacker/sol_refactored/infra_drivers/openstack/userdata_standard.py
|
||||||
|
# /tests/functional/sol_v2_common/samples/smapleX
|
||||||
|
userdata_dir = "../../../../../sol_refactored/infra_drivers/openstack/"
|
||||||
|
userdata_file = "userdata_standard.py"
|
||||||
|
userdata_path = os.path.abspath(userdata_dir + userdata_file)
|
||||||
|
|
||||||
|
utils.make_zip(".", tmp_dir, vnfd_id, image_path=image_path,
|
||||||
|
userdata_path=userdata_path)
|
||||||
|
|
||||||
|
shutil.copy(os.path.join(tmp_dir, zip_file_name), ".")
|
||||||
|
shutil.rmtree(tmp_dir)
|
||||||
|
|
||||||
|
create_req = paramgen.sample3_create(vnfd_id)
|
||||||
|
terminate_req = paramgen.sample3_terminate()
|
||||||
|
|
||||||
|
net_ids = utils.get_network_ids(['net0', 'net1', 'net_mgmt'])
|
||||||
|
subnet_ids = utils.get_subnet_ids(['subnet0', 'subnet1'])
|
||||||
|
|
||||||
|
instantiate_req = paramgen.sample3_instantiate(
|
||||||
|
net_ids, subnet_ids, "http://localhost/identity/v3")
|
||||||
|
|
||||||
|
scale_out_req = paramgen.sample3_scale_out()
|
||||||
|
scale_in_req = paramgen.sample3_scale_in()
|
||||||
|
heal_req = paramgen.sample3_heal()
|
||||||
|
change_ext_conn_req = paramgen.sample3_change_ext_conn(net_ids)
|
||||||
|
|
||||||
|
with open("create_req", "w") as f:
|
||||||
|
f.write(json.dumps(create_req, indent=2))
|
||||||
|
|
||||||
|
with open("terminate_req", "w") as f:
|
||||||
|
f.write(json.dumps(terminate_req, indent=2))
|
||||||
|
|
||||||
|
with open("instantiate_req", "w") as f:
|
||||||
|
f.write(json.dumps(instantiate_req, indent=2))
|
||||||
|
|
||||||
|
with open("scale_out_req", "w") as f:
|
||||||
|
f.write(json.dumps(scale_out_req, indent=2))
|
||||||
|
|
||||||
|
with open("scale_in_req", "w") as f:
|
||||||
|
f.write(json.dumps(scale_in_req, indent=2))
|
||||||
|
|
||||||
|
# NOTE: vnfcInstanceId should be filled by hand
|
||||||
|
with open("heal_req", "w") as f:
|
||||||
|
f.write(json.dumps(heal_req, indent=2))
|
||||||
|
|
||||||
|
with open("change_ext_conn_req", "w") as f:
|
||||||
|
f.write(json.dumps(change_ext_conn_req, indent=2))
|
|
@ -0,0 +1,53 @@
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'VDU1 HOT for Sample VNF'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
flavor:
|
||||||
|
type: string
|
||||||
|
image-VDU1:
|
||||||
|
type: string
|
||||||
|
net1:
|
||||||
|
type: string
|
||||||
|
net2:
|
||||||
|
type: string
|
||||||
|
net3:
|
||||||
|
type: string
|
||||||
|
affinity:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: flavor }
|
||||||
|
name: VDU1
|
||||||
|
image: { get_param: image-VDU1 }
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: VDU1_CP1
|
||||||
|
# replace the following line to Port ID when extmanagedVLs' Ports are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
- port:
|
||||||
|
get_resource: VDU1_CP2
|
||||||
|
- port:
|
||||||
|
get_resource: VDU1_CP3
|
||||||
|
scheduler_hints:
|
||||||
|
group: { get_param: affinity }
|
||||||
|
|
||||||
|
# extVL without FixedIP or with numDynamicAddresses
|
||||||
|
VDU1_CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net1 }
|
||||||
|
|
||||||
|
# CPs of internal VLs are deleted when extmanagedVLs and port are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
VDU1_CP2:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net2 }
|
||||||
|
|
||||||
|
VDU1_CP3:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net3 }
|
|
@ -0,0 +1,69 @@
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'VDU2 HOT for Sample VNF'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
flavor:
|
||||||
|
type: string
|
||||||
|
image-VDU2-VirtualStorage:
|
||||||
|
type: string
|
||||||
|
net1:
|
||||||
|
type: string
|
||||||
|
net2:
|
||||||
|
type: string
|
||||||
|
net3:
|
||||||
|
type: string
|
||||||
|
subnet1:
|
||||||
|
type: string
|
||||||
|
affinity:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU2:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: flavor }
|
||||||
|
name: VDU2
|
||||||
|
block_device_mapping_v2: [{"volume_id": { get_resource: VDU2-VirtualStorage }}]
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: VDU2_CP1
|
||||||
|
# replace the following line to Port ID when extmanagedVLs' Ports are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
- port:
|
||||||
|
get_resource: VDU2_CP2
|
||||||
|
- port:
|
||||||
|
get_resource: VDU2_CP3
|
||||||
|
scheduler_hints:
|
||||||
|
group: {get_param: affinity }
|
||||||
|
|
||||||
|
VDU2-VirtualStorage:
|
||||||
|
type: OS::Cinder::Volume
|
||||||
|
properties:
|
||||||
|
image: { get_param: image-VDU2-VirtualStorage }
|
||||||
|
size: 1
|
||||||
|
volume_type: { get_resource: multi }
|
||||||
|
multi:
|
||||||
|
type: OS::Cinder::VolumeType
|
||||||
|
properties:
|
||||||
|
name: VDU2-multi
|
||||||
|
metadata: { multiattach: "<is> True" }
|
||||||
|
|
||||||
|
# extVL with numDynamicAddresses and subnet
|
||||||
|
VDU2_CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net1 }
|
||||||
|
fixed_ips:
|
||||||
|
- subnet: { get_param: subnet1 }
|
||||||
|
|
||||||
|
# CPs of internal VLs are deleted when extmanagedVLs and port are
|
||||||
|
# specified in instantiatevnfrequest
|
||||||
|
VDU2_CP2:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net2 }
|
||||||
|
|
||||||
|
VDU2_CP3:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: { get_param: net3 }
|
|
@ -0,0 +1,57 @@
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: 'Simple Base HOT for Sample VNF'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
nfv:
|
||||||
|
type: json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: VDU1.yaml
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
|
||||||
|
image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
|
||||||
|
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
|
||||||
|
net2: { get_resource: internalVL1 }
|
||||||
|
net3: { get_resource: internalVL2 }
|
||||||
|
affinity: { get_resource: nfvi_node_affinity }
|
||||||
|
|
||||||
|
VDU2:
|
||||||
|
type: VDU2.yaml
|
||||||
|
properties:
|
||||||
|
flavor: { get_param: [ nfv, VDU, VDU2, computeFlavourId ] }
|
||||||
|
image-VDU2-VirtualStorage: { get_param: [ nfv, VDU, VDU2-VirtualStorage, vcImageId ] }
|
||||||
|
net1: { get_param: [ nfv, CP, VDU2_CP1, network ] }
|
||||||
|
subnet1: { get_param: [nfv, CP, VDU2_CP1, fixed_ips, 0, subnet ]}
|
||||||
|
net2: { get_resource: internalVL1 }
|
||||||
|
net3: { get_resource: internalVL2 }
|
||||||
|
affinity: { get_resource: nfvi_node_affinity }
|
||||||
|
|
||||||
|
# delete the following lines when extmanagedVLs are specified in instantiatevnfrequest
|
||||||
|
internalVL1:
|
||||||
|
type: OS::Neutron::Net
|
||||||
|
internalVL2:
|
||||||
|
type: OS::Neutron::Net
|
||||||
|
|
||||||
|
internalVL1_subnet:
|
||||||
|
type: OS::Neutron::Subnet
|
||||||
|
properties:
|
||||||
|
ip_version: 4
|
||||||
|
network:
|
||||||
|
get_resource: internalVL1
|
||||||
|
cidr: 192.168.3.0/24
|
||||||
|
internalVL2_subnet:
|
||||||
|
type: OS::Neutron::Subnet
|
||||||
|
properties:
|
||||||
|
ip_version: 4
|
||||||
|
network:
|
||||||
|
get_resource: internalVL2
|
||||||
|
cidr: 192.168.4.0/24
|
||||||
|
|
||||||
|
nfvi_node_affinity:
|
||||||
|
type: OS::Nova::ServerGroup
|
||||||
|
properties:
|
||||||
|
name: nfvi_node_affinity
|
||||||
|
policies: [ 'affinity' ]
|
||||||
|
|
||||||
|
outputs: {}
|
|
@ -0,0 +1,357 @@
|
||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: Simple deployment flavour for Sample VNF
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
- v2_sample4_types.yaml
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
inputs:
|
||||||
|
descriptor_id:
|
||||||
|
type: string
|
||||||
|
descriptor_version:
|
||||||
|
type: string
|
||||||
|
provider:
|
||||||
|
type: string
|
||||||
|
product_name:
|
||||||
|
type: string
|
||||||
|
software_version:
|
||||||
|
type: string
|
||||||
|
vnfm_info:
|
||||||
|
type: list
|
||||||
|
entry_schema:
|
||||||
|
type: string
|
||||||
|
flavour_id:
|
||||||
|
type: string
|
||||||
|
flavour_description:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
substitution_mappings:
|
||||||
|
node_type: company.provider.VNF
|
||||||
|
properties:
|
||||||
|
flavour_id: simple
|
||||||
|
requirements:
|
||||||
|
virtual_link_external1_1: [ VDU1_CP1, virtual_link ]
|
||||||
|
virtual_link_external1_2: [ VDU2_CP1, virtual_link ]
|
||||||
|
|
||||||
|
node_templates:
|
||||||
|
VNF:
|
||||||
|
type: company.provider.VNF
|
||||||
|
properties:
|
||||||
|
flavour_description: A simple flavour
|
||||||
|
interfaces:
|
||||||
|
Vnflcm:
|
||||||
|
instantiate_start:
|
||||||
|
implementation: sample-script
|
||||||
|
instantiate_end:
|
||||||
|
implementation: sample-script
|
||||||
|
terminate_start:
|
||||||
|
implementation: sample-script
|
||||||
|
terminate_end:
|
||||||
|
implementation: sample-script
|
||||||
|
scale_start:
|
||||||
|
implementation: sample-script
|
||||||
|
scale_end:
|
||||||
|
implementation: sample-script
|
||||||
|
heal_start:
|
||||||
|
implementation: sample-script
|
||||||
|
heal_end:
|
||||||
|
implementation: sample-script
|
||||||
|
change_external_connectivity_start:
|
||||||
|
implementation: sample-script
|
||||||
|
change_external_connectivity_end:
|
||||||
|
implementation: sample-script
|
||||||
|
modify_information_start:
|
||||||
|
implementation: sample-script
|
||||||
|
modify_information_end:
|
||||||
|
implementation: sample-script
|
||||||
|
artifacts:
|
||||||
|
sample-script:
|
||||||
|
description: Sample script
|
||||||
|
type: tosca.artifacts.Implementation.Python
|
||||||
|
file: ../Scripts/sample_script.py
|
||||||
|
|
||||||
|
VDU1:
|
||||||
|
type: tosca.nodes.nfv.Vdu.Compute
|
||||||
|
properties:
|
||||||
|
name: VDU1
|
||||||
|
description: VDU1 compute node
|
||||||
|
vdu_profile:
|
||||||
|
min_number_of_instances: 1
|
||||||
|
max_number_of_instances: 3
|
||||||
|
sw_image_data:
|
||||||
|
name: VDU1-image
|
||||||
|
version: '0.5.2'
|
||||||
|
checksum:
|
||||||
|
algorithm: sha-256
|
||||||
|
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||||
|
container_format: bare
|
||||||
|
disk_format: qcow2
|
||||||
|
min_disk: 0 GB
|
||||||
|
min_ram: 256 MB
|
||||||
|
size: 12 GB
|
||||||
|
capabilities:
|
||||||
|
virtual_compute:
|
||||||
|
properties:
|
||||||
|
requested_additional_capabilities:
|
||||||
|
properties:
|
||||||
|
requested_additional_capability_name: m1.tiny
|
||||||
|
support_mandatory: true
|
||||||
|
target_performance_parameters:
|
||||||
|
entry_schema: test
|
||||||
|
virtual_memory:
|
||||||
|
virtual_mem_size: 512 MB
|
||||||
|
virtual_cpu:
|
||||||
|
num_virtual_cpu: 1
|
||||||
|
virtual_local_storage:
|
||||||
|
- size_of_storage: 3 GB
|
||||||
|
artifacts:
|
||||||
|
sw_image:
|
||||||
|
type: tosca.artifacts.nfv.SwImage
|
||||||
|
file: ../Files/images/cirros-0.5.2-x86_64-disk.img
|
||||||
|
|
||||||
|
VDU2:
|
||||||
|
type: tosca.nodes.nfv.Vdu.Compute
|
||||||
|
properties:
|
||||||
|
name: VDU2
|
||||||
|
description: VDU2 compute node
|
||||||
|
vdu_profile:
|
||||||
|
min_number_of_instances: 1
|
||||||
|
max_number_of_instances: 1
|
||||||
|
capabilities:
|
||||||
|
virtual_compute:
|
||||||
|
properties:
|
||||||
|
requested_additional_capabilities:
|
||||||
|
properties:
|
||||||
|
requested_additional_capability_name: m1.tiny
|
||||||
|
support_mandatory: true
|
||||||
|
target_performance_parameters:
|
||||||
|
entry_schema: test
|
||||||
|
virtual_memory:
|
||||||
|
virtual_mem_size: 512 MB
|
||||||
|
virtual_cpu:
|
||||||
|
num_virtual_cpu: 1
|
||||||
|
virtual_local_storage:
|
||||||
|
- size_of_storage: 3 GB
|
||||||
|
requirements:
|
||||||
|
- virtual_storage: VDU2-VirtualStorage
|
||||||
|
|
||||||
|
VDU2-VirtualStorage:
|
||||||
|
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
|
||||||
|
properties:
|
||||||
|
virtual_block_storage_data:
|
||||||
|
size_of_storage: 1 GB
|
||||||
|
rdma_enabled: true
|
||||||
|
sw_image_data:
|
||||||
|
name: cirros-0.5.2-x86_64-disk
|
||||||
|
version: '0.5.2'
|
||||||
|
checksum:
|
||||||
|
algorithm: sha-256
|
||||||
|
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||||
|
container_format: bare
|
||||||
|
disk_format: qcow2
|
||||||
|
min_disk: 0 GB
|
||||||
|
min_ram: 256 MB
|
||||||
|
size: 12 GB
|
||||||
|
|
||||||
|
VDU1_CP1:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 0
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
||||||
|
|
||||||
|
VDU1_CP2:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 1
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
||||||
|
- virtual_link: internalVL1
|
||||||
|
|
||||||
|
VDU1_CP3:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 2
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU1
|
||||||
|
- virtual_link: internalVL2
|
||||||
|
|
||||||
|
VDU2_CP1:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 0
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU2
|
||||||
|
|
||||||
|
VDU2_CP2:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 1
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU2
|
||||||
|
- virtual_link: internalVL1
|
||||||
|
|
||||||
|
VDU2_CP3:
|
||||||
|
type: tosca.nodes.nfv.VduCp
|
||||||
|
properties:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
order: 2
|
||||||
|
requirements:
|
||||||
|
- virtual_binding: VDU2
|
||||||
|
- virtual_link: internalVL2
|
||||||
|
|
||||||
|
internalVL1:
|
||||||
|
type: tosca.nodes.nfv.VnfVirtualLink
|
||||||
|
properties:
|
||||||
|
connectivity_type:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
description: External Managed Virtual link in the VNF
|
||||||
|
vl_profile:
|
||||||
|
max_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
min_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
virtual_link_protocol_data:
|
||||||
|
- associated_layer_protocol: ipv4
|
||||||
|
l3_protocol_data:
|
||||||
|
ip_version: ipv4
|
||||||
|
cidr: 192.168.3.0/24
|
||||||
|
|
||||||
|
internalVL2:
|
||||||
|
type: tosca.nodes.nfv.VnfVirtualLink
|
||||||
|
properties:
|
||||||
|
connectivity_type:
|
||||||
|
layer_protocols: [ ipv4 ]
|
||||||
|
description: External Managed Virtual link in the VNF
|
||||||
|
vl_profile:
|
||||||
|
max_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
min_bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
virtual_link_protocol_data:
|
||||||
|
- associated_layer_protocol: ipv4
|
||||||
|
l3_protocol_data:
|
||||||
|
ip_version: ipv4
|
||||||
|
cidr: 192.168.4.0/24
|
||||||
|
|
||||||
|
groups:
|
||||||
|
affinityOrAntiAffinityGroup1:
|
||||||
|
type: tosca.groups.nfv.PlacementGroup
|
||||||
|
members: [ VDU1, VDU2 ]
|
||||||
|
|
||||||
|
policies:
|
||||||
|
- scaling_aspects:
|
||||||
|
type: tosca.policies.nfv.ScalingAspects
|
||||||
|
properties:
|
||||||
|
aspects:
|
||||||
|
VDU1_scale:
|
||||||
|
name: VDU1_scale
|
||||||
|
description: VDU1 scaling aspect
|
||||||
|
max_scale_level: 2
|
||||||
|
step_deltas:
|
||||||
|
- delta_1
|
||||||
|
|
||||||
|
- VDU1_initial_delta:
|
||||||
|
type: tosca.policies.nfv.VduInitialDelta
|
||||||
|
properties:
|
||||||
|
initial_delta:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU1 ]
|
||||||
|
|
||||||
|
- VDU2_initial_delta:
|
||||||
|
type: tosca.policies.nfv.VduInitialDelta
|
||||||
|
properties:
|
||||||
|
initial_delta:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU2 ]
|
||||||
|
|
||||||
|
- VDU1_scaling_aspect_deltas:
|
||||||
|
type: tosca.policies.nfv.VduScalingAspectDeltas
|
||||||
|
properties:
|
||||||
|
aspect: VDU1_scale
|
||||||
|
deltas:
|
||||||
|
delta_1:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU1 ]
|
||||||
|
|
||||||
|
- instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.InstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
description: Smallest size
|
||||||
|
scale_info:
|
||||||
|
VDU1_scale:
|
||||||
|
scale_level: 0
|
||||||
|
instantiation_level_2:
|
||||||
|
description: Largest size
|
||||||
|
scale_info:
|
||||||
|
VDU1_scale:
|
||||||
|
scale_level: 1
|
||||||
|
default_level: instantiation_level_1
|
||||||
|
|
||||||
|
- VDU1_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VduInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
number_of_instances: 1
|
||||||
|
instantiation_level_2:
|
||||||
|
number_of_instances: 2
|
||||||
|
targets: [ VDU1 ]
|
||||||
|
|
||||||
|
- VDU2_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VduInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
number_of_instances: 1
|
||||||
|
instantiation_level_2:
|
||||||
|
number_of_instances: 1
|
||||||
|
targets: [ VDU2 ]
|
||||||
|
|
||||||
|
- internalVL1_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
instantiation_level_2:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
targets: [ internalVL1 ]
|
||||||
|
|
||||||
|
- internalVL2_instantiation_levels:
|
||||||
|
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
|
||||||
|
properties:
|
||||||
|
levels:
|
||||||
|
instantiation_level_1:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
instantiation_level_2:
|
||||||
|
bitrate_requirements:
|
||||||
|
root: 1048576
|
||||||
|
leaf: 1048576
|
||||||
|
targets: [ internalVL2 ]
|
||||||
|
|
||||||
|
- policy_antiaffinity_group:
|
||||||
|
type: tosca.policies.nfv.AntiAffinityRule
|
||||||
|
targets: [ affinityOrAntiAffinityGroup1 ]
|
||||||
|
properties:
|
||||||
|
scope: nfvi_node
|
|
@ -0,0 +1,31 @@
|
||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: Sample VNF
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
- v2_sample4_types.yaml
|
||||||
|
- v2_sample4_df_simple.yaml
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
inputs:
|
||||||
|
selected_flavour:
|
||||||
|
type: string
|
||||||
|
description: VNF deployment flavour selected by the consumer. It is provided in the API
|
||||||
|
|
||||||
|
node_templates:
|
||||||
|
VNF:
|
||||||
|
type: company.provider.VNF
|
||||||
|
properties:
|
||||||
|
flavour_id: { get_input: selected_flavour }
|
||||||
|
descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
|
||||||
|
provider: Company
|
||||||
|
product_name: Sample VNF
|
||||||
|
software_version: '1.0'
|
||||||
|
descriptor_version: '1.0'
|
||||||
|
vnfm_info:
|
||||||
|
- Tacker
|
||||||
|
requirements:
|
||||||
|
#- virtual_link_external # mapped in lower-level templates
|
||||||
|
#- virtual_link_internal # mapped in lower-level templates
|
|
@ -0,0 +1,55 @@
|
||||||
|
tosca_definitions_version: tosca_simple_yaml_1_2
|
||||||
|
|
||||||
|
description: VNF type definition
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- etsi_nfv_sol001_common_types.yaml
|
||||||
|
- etsi_nfv_sol001_vnfd_types.yaml
|
||||||
|
|
||||||
|
node_types:
|
||||||
|
company.provider.VNF:
|
||||||
|
derived_from: tosca.nodes.nfv.VNF
|
||||||
|
properties:
|
||||||
|
descriptor_id:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ]
|
||||||
|
default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000
|
||||||
|
descriptor_version:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ '1.0' ] ]
|
||||||
|
default: '1.0'
|
||||||
|
provider:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ 'Company' ] ]
|
||||||
|
default: 'Company'
|
||||||
|
product_name:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ 'Sample VNF' ] ]
|
||||||
|
default: 'Sample VNF'
|
||||||
|
software_version:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ '1.0' ] ]
|
||||||
|
default: '1.0'
|
||||||
|
vnfm_info:
|
||||||
|
type: list
|
||||||
|
entry_schema:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ Tacker ] ]
|
||||||
|
default: [ Tacker ]
|
||||||
|
flavour_id:
|
||||||
|
type: string
|
||||||
|
constraints: [ valid_values: [ simple ] ]
|
||||||
|
default: simple
|
||||||
|
flavour_description:
|
||||||
|
type: string
|
||||||
|
default: "flavour"
|
||||||
|
requirements:
|
||||||
|
- virtual_link_external1:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
- virtual_link_external2:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
- virtual_link_internal:
|
||||||
|
capability: tosca.capabilities.nfv.VirtualLinkable
|
||||||
|
interfaces:
|
||||||
|
Vnflcm:
|
||||||
|
type: tosca.interfaces.nfv.Vnflcm
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class FailScript(object):
|
||||||
|
def __init__(self, vnfc_param):
|
||||||
|
self.vnfc_param = vnfc_param
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
operation = 'change_vnfpkg'
|
||||||
|
if self.vnfc_param['is_rollback']:
|
||||||
|
operation += '_rollback'
|
||||||
|
if os.path.exists(f'/tmp/{operation}'):
|
||||||
|
raise Exception(f'test {operation} error')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
vnfc_param = pickle.load(sys.stdin.buffer)
|
||||||
|
script = FailScript(vnfc_param)
|
||||||
|
script.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
os._exit(0)
|
||||||
|
except Exception as ex:
|
||||||
|
sys.stderr.write(str(ex))
|
||||||
|
sys.stderr.flush()
|
||||||
|
os._exit(1)
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class FailScript(object):
|
||||||
|
"""Define error method for each operation
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
def instantiate_start(self):
|
||||||
|
if os.path.exists('/tmp/instantiate_start')
|
||||||
|
raise Exception('test instantiate_start error')
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, req, inst, grant_req, grant, csar_dir):
|
||||||
|
self.req = req
|
||||||
|
self.inst = inst
|
||||||
|
self.grant_req = grant_req
|
||||||
|
self.grant = grant
|
||||||
|
self.csar_dir = csar_dir
|
||||||
|
|
||||||
|
def _fail(self, method):
|
||||||
|
if os.path.exists(f'/tmp/{method}'):
|
||||||
|
raise Exception(f'test {method} error')
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return functools.partial(self._fail, name)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
script_dict = pickle.load(sys.stdin.buffer)
|
||||||
|
|
||||||
|
operation = script_dict['operation']
|
||||||
|
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']
|
||||||
|
|
||||||
|
script = FailScript(req, inst, grant_req, grant, csar_dir)
|
||||||
|
getattr(script, operation)()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
os._exit(0)
|
||||||
|
except Exception as ex:
|
||||||
|
sys.stderr.write(str(ex))
|
||||||
|
sys.stderr.flush()
|
||||||
|
os._exit(1)
|
|
@ -0,0 +1,4 @@
|
||||||
|
TOSCA-Meta-File-Version: 1.0
|
||||||
|
CSAR-Version: 1.1
|
||||||
|
Created-by: Onboarding portal
|
||||||
|
Entry-Definitions: Definitions/v2_sample4_top.vnfd.yaml
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
from tacker.tests.functional.sol_v2_common import paramgen
|
||||||
|
from tacker.tests.functional.sol_v2_common import utils
|
||||||
|
|
||||||
|
|
||||||
|
zip_file_name = os.path.basename(os.path.abspath(".")) + '.zip'
|
||||||
|
tmp_dir = tempfile.mkdtemp()
|
||||||
|
vnfd_id = uuidutils.generate_uuid()
|
||||||
|
|
||||||
|
# tacker/tests/etc...
|
||||||
|
# /functional/sol_v2_common/samples/sampleX
|
||||||
|
image_dir = "../../../../etc/samples/etsi/nfv/common/Files/images/"
|
||||||
|
image_file = "cirros-0.5.2-x86_64-disk.img"
|
||||||
|
image_path = os.path.abspath(image_dir + image_file)
|
||||||
|
|
||||||
|
# tacker/sol_refactored/infra_drivers/openstack/userdata_standard.py
|
||||||
|
# /tests/functional/sol_v2_common/samples/sampleX
|
||||||
|
userdata_dir = "../../../../../sol_refactored/infra_drivers/openstack/"
|
||||||
|
userdata_file = "userdata_standard.py"
|
||||||
|
userdata_path = os.path.abspath(userdata_dir + userdata_file)
|
||||||
|
|
||||||
|
utils.make_zip(".", tmp_dir, vnfd_id, image_path=image_path,
|
||||||
|
userdata_path=userdata_path)
|
||||||
|
|
||||||
|
shutil.copy(os.path.join(tmp_dir, zip_file_name), ".")
|
||||||
|
shutil.rmtree(tmp_dir)
|
||||||
|
|
||||||
|
change_vnfpkg_req = paramgen.sample4_change_vnfpkg(vnfd_id)
|
||||||
|
|
||||||
|
with open("change_vnfpkg_req", "w") as f:
|
||||||
|
f.write(json.dumps(change_vnfpkg_req, indent=2))
|
|
@ -23,7 +23,8 @@ import subprocess
|
||||||
SAMPLE_VNFD_ID = "b1bb0ce7-ebca-4fa7-95ed-4840d7000000"
|
SAMPLE_VNFD_ID = "b1bb0ce7-ebca-4fa7-95ed-4840d7000000"
|
||||||
|
|
||||||
|
|
||||||
def make_zip(sample_dir, tmp_dir, vnfd_id, image_path=None):
|
def make_zip(sample_dir, tmp_dir, vnfd_id, image_path=None,
|
||||||
|
userdata_path=None):
|
||||||
# NOTE: '.zip' will be added by shutil.make_archive
|
# NOTE: '.zip' will be added by shutil.make_archive
|
||||||
zip_file_name = os.path.basename(os.path.abspath(sample_dir))
|
zip_file_name = os.path.basename(os.path.abspath(sample_dir))
|
||||||
zip_file_path = os.path.join(tmp_dir, zip_file_name)
|
zip_file_path = os.path.join(tmp_dir, zip_file_name)
|
||||||
|
@ -53,6 +54,12 @@ def make_zip(sample_dir, tmp_dir, vnfd_id, image_path=None):
|
||||||
os.makedirs(file_path)
|
os.makedirs(file_path)
|
||||||
shutil.copy(image_path, file_path)
|
shutil.copy(image_path, file_path)
|
||||||
|
|
||||||
|
if userdata_path is not None:
|
||||||
|
# mkdir UserData/ and copy userdata_path into it
|
||||||
|
file_path = os.path.join(tmp_contents, "UserData")
|
||||||
|
os.makedirs(file_path)
|
||||||
|
shutil.copy(userdata_path, file_path)
|
||||||
|
|
||||||
shutil.make_archive(zip_file_path, "zip", tmp_contents)
|
shutil.make_archive(zip_file_path, "zip", tmp_contents)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue