Support Additional Parameters for List VNF

Supported additional parameters for vimConnectionInfo
and instantiatedVnfInfo.

Implements: blueprint support-etsi-nfv-specs
Spec: https://specs.openstack.org/openstack/tacker-specs/specs/victoria/enhancement_enhance-vnf-lcm-api-support.html
Closes-bug:#1897827

Change-Id: I7b0be28d089de8feedfceda8a88d7297fa36f1e5
This commit is contained in:
Aldinson Esto 2020-08-21 22:48:29 +09:00
parent 3f957d4897
commit 35d15a089f
17 changed files with 448 additions and 68 deletions

View File

@ -1,5 +1,4 @@
# variables in header
vnf_instance_id:
description: |
Identifier of the VNF instance.
@ -49,6 +48,16 @@ ext_cp_info:
in: body
required: true
type: array
ext_cp_info_associated_vnfc_cp_id:
description: |
Identifier of the "vnfcCpInfo" structure in
"VnfcResourceInfo" structure that represents the
VNFC CP which is exposed by this external CP
instance. Shall be present in case this CP instance
maps to a VNFC CP.
in: body
required: false
type: string
ext_cp_info_cp_protocol_info:
description: |
Network protocol information for this CP.
@ -77,6 +86,12 @@ ext_cp_info_id:
in: body
required: true
type: string
ext_cp_info_metadata:
description: |
Metadata about this external CP.
in: body
required: false
type: string
ext_cps:
description: |
External CPs of the VNF to be connected to this external VL.
@ -361,6 +376,30 @@ resource_handle_vim_level_resource_type:
in: body
required: false
type: string
scale_status:
description: |
Scale status of the VNF, one entry per aspect.
Represents for every scaling aspect how "big"
the VNF has been scaled with reference to that aspect.
This attribute shall be present if the VNF
supports scaling.
in: body
required: false
type: array
scale_status_aspect_id:
description: |
Identifier of the scaling aspect.
in: body
required: true
type: string
scale_status_scale_level:
description: |
Indicates the scale level. The minimum value shall be 0
and the maximum value shall be less than or equal to maxScaleLevel as
described in the VNFD.
in: body
required: true
type: string
subnet_id:
description: |
Subnet defined by the identifier of the subnet resource in the VIM.
@ -386,6 +425,14 @@ termination_type:
in: body
required: true
type: string
vim_connection_id:
description: |
Identifier of the VIM connection to manage the resource.
This attribute shall only be supported and present if VNF related
resource management in direct mode is applicable.
in: body
required: false
type: string
vim_connection_info_access_info:
description: |
Authentication credentials for accessing the VIM, and other access-related
@ -409,6 +456,24 @@ vim_connection_info_id:
in: body
required: true
type: string
vim_connection_info_interface_info:
description: |
Information about the interface or interfaces to the VIM, if
applicable, such as the URI of an interface endpoint to
communicate with the VIM. The applicable keys are
dependent on the content of vimType.
Alternatively, such information may have been configured
into the VNFM and bound to the vimId.
in: body
required: false
type: string
vim_connection_info_interface_info_endpoint:
description: |
The url representing the interface endpoint.
in: body
required: true
type: string
vim_connection_info_vim_id:
description: |
The identifier of the VIM instance. This identifier is managed by
@ -702,6 +767,35 @@ vnfc_cp_info_vnf_link_port_id:
in: body
required: false
type: string
vnfc_info:
description: |
Information about the VNFC instances.
in: body
required: array
type: string
vnfc_info_id:
description: |
Identifier of the VNFC instance.
in: body
required: true
type: string
vnfc_info_vdu_id:
description: |
Reference to the applicable VDU information element in the VNFD.
in: body
required: true
type: string
vnfc_info_vnfc_state:
description: |
State of the VNFC instance.
Permitted values:
STARTED: The VNFC instance is up and running.
STOPPED: The VNFC instance has been shut down.
in: body
required: true
type: string
vnfc_resource_info:
description: |
Information about the virtualised compute and storage resources used by

View File

@ -316,11 +316,16 @@ Response Parameters
- id: vim_connection_info_id
- vimId: vim_connection_info_vim_id
- vimType: vim_connection_info_vim_type
- interfaceInfo: vim_connection_info_interface_info
- endpoint: vim_connection_info_interface_info_endpoint
- accessInfo: vim_connection_info_access_info
- instantiationState: vnf_instance_instantiation_state
- instantiatedVnfInfo: instantiated_vnf_info
- flavourId: flavour_id_response
- vnfState: vnf_state
- scaleStatus: scale_status
- aspectId: scale_status_aspect_id
- scaleLevel: scale_status_scale_level
- extCpInfo: ext_cp_info
- id: ext_cp_info_id
- cpdId: ext_cp_info_cpd_id
@ -334,14 +339,18 @@ Response Parameters
- isDynamic: is_dynamic
- subnetId: subnet_id
- extLinkPortId: ext_cp_info_ext_link_port_id
- metadata: ext_cp_info_metadata
- associatedVnfcCpId: ext_cp_info_associated_vnfc_cp_id
- extVirtualLinkInfo: ext_virtual_link_info
- id: ext_virtual_link_info_id
- resourceHandle: resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- extLinkPorts: ext_virtual_link_info_ext_link_ports
- id: ext_virtual_link_info_ext_link_ports_id
- resourceHandle: resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- cpInstanceId: ext_virtual_link_info_ext_link_ports_cp_instance_id
@ -349,11 +358,13 @@ Response Parameters
- id: ext_managed_virtual_link_info_id
- vnfVirtualLinkDescId: ext_managed_virtual_link_info_vnf_virtual_link_desc_id
- networkResource: ext_managed_virtual_link_info_network_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- vnfLinkPorts: vnf_link_ports
- id: vnf_link_port_id
- resourceHandle: vnf_link_port_resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- cpInstanceId: vnf_link_port_cp_instance_id
@ -361,6 +372,7 @@ Response Parameters
- id: vnfc_resource_info_id
- vduId: vnfc_resource_info_vdu_id
- computeResource: vnfc_resource_info_compute_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- storageResourceIds: vnfc_resource_info_storage_resource_ids
@ -382,11 +394,13 @@ Response Parameters
- id: vnf_virtual_link_resource_info_id
- vnfVirtualLinkDescId: vnf_virtual_link_resource_info_vnf_virtual_link_desc_id
- networkResource: vnf_virtual_link_resource_info_network_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- vnfLinkPorts: vnf_link_ports
- id: vnf_link_port_id
- resourceHandle: vnf_link_port_resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- cpInstanceId: vnf_link_port_cp_instance_id
@ -394,8 +408,13 @@ Response Parameters
- id: virtual_storage_resource_info_id
- virtualStorageDescId: virtual_storage_resource_info_virtual_storage_desc_id
- storageResource: virtual_storage_resource_info_storage_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- vnfcInfo: vnfc_info
- id: vnfc_info_id
- vduId: vnfc_info_vdu_id
- vnfcState: vnfc_info_vnfc_state
- _links: vnf_instance_links
Response Example
@ -444,11 +463,16 @@ Response Parameters
- id: vim_connection_info_id
- vimId: vim_connection_info_vim_id
- vimType: vim_connection_info_vim_type
- interfaceInfo: vim_connection_info_interface_info
- endpoint: vim_connection_info_interface_info_endpoint
- accessInfo: vim_connection_info_access_info
- instantiationState: vnf_instance_instantiation_state
- instantiatedVnfInfo: instantiated_vnf_info
- flavourId: flavour_id_response
- vnfState: vnf_state
- scaleStatus: scale_status
- aspectId: scale_status_aspect_id
- scaleLevel: scale_status_scale_level
- extCpInfo: ext_cp_info
- id: ext_cp_info_id
- cpdId: ext_cp_info_cpd_id
@ -462,14 +486,18 @@ Response Parameters
- isDynamic: is_dynamic
- subnetId: subnet_id
- extLinkPortId: ext_cp_info_ext_link_port_id
- metadata: ext_cp_info_metadata
- associatedVnfcCpId: ext_cp_info_associated_vnfc_cp_id
- extVirtualLinkInfo: ext_virtual_link_info
- id: ext_virtual_link_info_id
- resourceHandle: resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- extLinkPorts: ext_virtual_link_info_ext_link_ports
- id: ext_virtual_link_info_ext_link_ports_id
- resourceHandle: resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- cpInstanceId: ext_virtual_link_info_ext_link_ports_cp_instance_id
@ -477,11 +505,13 @@ Response Parameters
- id: ext_managed_virtual_link_info_id
- vnfVirtualLinkDescId: ext_managed_virtual_link_info_vnf_virtual_link_desc_id
- networkResource: ext_managed_virtual_link_info_network_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- vnfLinkPorts: vnf_link_ports
- id: vnf_link_port_id
- resourceHandle: vnf_link_port_resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- cpInstanceId: vnf_link_port_cp_instance_id
@ -489,6 +519,7 @@ Response Parameters
- id: vnfc_resource_info_id
- vduId: vnfc_resource_info_vdu_id
- computeResource: vnfc_resource_info_compute_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- storageResourceIds: vnfc_resource_info_storage_resource_ids
@ -510,11 +541,13 @@ Response Parameters
- id: vnf_virtual_link_resource_info_id
- vnfVirtualLinkDescId: vnf_virtual_link_resource_info_vnf_virtual_link_desc_id
- networkResource: vnf_virtual_link_resource_info_network_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- vnfLinkPorts: vnf_link_ports
- id: vnf_link_port_id
- resourceHandle: vnf_link_port_resource_handle
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- cpInstanceId: vnf_link_port_cp_instance_id
@ -522,10 +555,15 @@ Response Parameters
- id: virtual_storage_resource_info_id
- virtualStorageDescId: virtual_storage_resource_info_virtual_storage_desc_id
- storageResource: virtual_storage_resource_info_storage_resource
- vimConnectionId: vim_connection_id
- resourceId: resource_handle_resource_id
- vimLevelResourceType: resource_handle_vim_level_resource_type
- vnfcInfo: vnfc_info
- id: vnfc_info_id
- vduId: vnfc_info_vdu_id
- vnfcState: vnfc_info_vnfc_state
- _links: vnf_instance_links
Response Example
----------------

View File

@ -58,9 +58,35 @@ class ViewBuilder(base.BaseViewBuilder):
return {"_links": links}
def _get_vnf_instance_info(self,
vnf_instance, api_version=None):
def _get_vim_conn_info(self, vim_connection_info):
vim_connections = []
for vim in vim_connection_info:
access_info = {
'username': '',
'region': '',
'password': '',
'tenant': ''
}
vim_conn = vim
for key_name in access_info.keys():
if vim['access_info'].get(key_name):
access_info[key_name] = vim['access_info'].get(key_name)
vim_conn['access_info'] = access_info
vim_connections.append(vim_conn)
return vim_connections
def _get_vnf_instance_info(self, vnf_instance):
vnf_instance_dict = vnf_instance.to_dict()
if vnf_instance_dict.get('vim_connection_info'):
vnf_instance_dict['vim_connection_info'] = \
self._get_vim_conn_info(vnf_instance_dict.get(
'vim_connection_info', []))
if 'vnf_metadata' in vnf_instance_dict:
metadata_val = vnf_instance_dict.pop('vnf_metadata')
vnf_instance_dict['metadata'] = metadata_val
@ -68,9 +94,6 @@ class ViewBuilder(base.BaseViewBuilder):
vnf_instance_dict = utils.convert_snakecase_to_camelcase(
vnf_instance_dict)
if api_version == "2.6.1":
del vnf_instance_dict["vnfPkgId"]
links = self._get_links(vnf_instance)
vnf_instance_dict.update(links)
@ -82,6 +105,6 @@ class ViewBuilder(base.BaseViewBuilder):
def show(self, vnf_instance):
return self._get_vnf_instance_info(vnf_instance)
def index(self, vnf_instances, api_version=None):
return [self._get_vnf_instance_info(vnf_instance, api_version)
def index(self, vnf_instances):
return [self._get_vnf_instance_info(vnf_instance)
for vnf_instance in vnf_instances]

View File

@ -174,6 +174,22 @@ class VnfLcmController(wsgi.Controller):
except exceptions.VnfPackageVnfdNotFound as exc:
raise webob.exc.HTTPBadRequest(explanation=six.text_type(exc))
# get default vim information
vim_client_obj = vim_client.VimClient()
default_vim = vim_client_obj.get_vim(context)
# set vim_connection_info
access_info = {
'username': default_vim.get('vim_auth', {}).get('username'),
'password': default_vim.get('vim_auth', {}).get('password'),
'region': default_vim.get('placement_attr', {}).get('region'),
'tenant': default_vim.get('tenant')
}
vim_con_info = objects.VimConnectionInfo(id=default_vim.get('vim_id'),
vim_id=default_vim.get('vim_id'),
vim_type=default_vim.get('vim_type'),
access_info=access_info)
vnf_instance = objects.VnfInstance(
context=request.context,
vnf_instance_name=req_body.get('vnf_instance_name'),
@ -190,6 +206,11 @@ class VnfLcmController(wsgi.Controller):
vnf_metadata=req_body.get('metadata'))
vnf_instance.create()
# add default vim to vim_connection_info
setattr(vnf_instance, 'vim_connection_info', [vim_con_info])
vnf_instance.save()
result = self._view_builder.create(vnf_instance)
headers = {"location": self._get_vnf_instance_href(vnf_instance)}
return wsgi.ResponseObject(result, headers=headers)
@ -215,8 +236,7 @@ class VnfLcmController(wsgi.Controller):
vnf_instances = objects.VnfInstanceList.get_by_filters(
request.context, filters=filters)
api_version = request.headers['Version']
return self._view_builder.index(vnf_instances, api_version)
return self._view_builder.index(vnf_instances)
@check_vnf_state(action="delete",
instantiation_state=[fields.VnfInstanceState.NOT_INSTANTIATED],

View File

@ -221,6 +221,7 @@ class VnfInstantiatedInfo(model_base.BASE, models.SoftDeleteMixin,
vnfc_resource_info = sa.Column(sa.JSON(), nullable=True)
vnf_virtual_link_resource_info = sa.Column(sa.JSON(), nullable=True)
virtual_storage_resource_info = sa.Column(sa.JSON(), nullable=True)
vnfc_info = sa.Column(sa.JSON(), nullable=True)
vnf_state = sa.Column(sa.String(255), nullable=False)
instance_id = sa.Column(sa.Text(), nullable=True)
instantiation_level_id = sa.Column(sa.String(255), nullable=True)

View File

@ -0,0 +1,39 @@
# Copyright 2020 OpenStack Foundation
#
# 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.
#
# flake8: noqa: E402
"""add_vnfc_info_to_instantiated_vnf_info
Revision ID: 8a7ca803e0d0
Revises: aaf461c8844c
Create Date: 2020-09-21 15:00:00.004343
"""
# revision identifiers, used by Alembic.
revision = '8a7ca803e0d0'
down_revision = 'aaf461c8844c'
from alembic import op
import sqlalchemy as sa
from tacker.db import migration
def upgrade(active_plugins=None, options=None):
op.add_column('vnf_instantiated_info',
sa.Column('vnfc_info', sa.JSON(), nullable=True))

View File

@ -1 +1 @@
aaf461c8844c
8a7ca803e0d0

View File

@ -177,3 +177,10 @@ class VnfInstanceTerminationType(BaseTackerEnum):
class VnfInstanceTerminationTypeField(BaseEnumField):
AUTO_TYPE = VnfInstanceTerminationType()
class VnfcState(BaseTackerEnum):
STARTED = 'STARTED'
STOPPED = 'STOPPED'
ALL = (STARTED, STOPPED)

View File

@ -72,6 +72,8 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
'VnfVirtualLinkResourceInfo', nullable=True, default=[]),
'virtual_storage_resource_info': fields.ListOfObjectsField(
'VirtualStorageResourceInfo', nullable=True, default=[]),
'vnfc_info': fields.ListOfObjectsField(
'VnfcInfo', nullable=True, default=[]),
'vnf_state': fields.VnfOperationalStateTypeField(nullable=False,
default=fields.VnfOperationalStateType.STOPPED),
'instance_id': fields.StringField(nullable=True, default=None),
@ -116,6 +118,10 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
'additional_params', 'key_value_pair',
{"key_column": "key", "value_column": "value",
"model": "VnfInstantiatedInfo"}),
'vnfcInfo/*': (
'vnfc_info', 'key_value_pair',
{"key_column": "key", "value_column": "value",
"model": "VnfInstantiatedInfo"}),
}
}
@ -128,7 +134,8 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
'ext_managed_virtual_link_info',
'vnfc_resource_info',
'vnf_virtual_link_resource_info',
'virtual_storage_resource_info']
'virtual_storage_resource_info',
'vnfc_info']
for key in inst_vnf_info.fields:
if key in special_fields:
continue
@ -169,6 +176,13 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
vnf_vl_resource_info]
inst_vnf_info.vnf_virtual_link_resource_info = vnf_vl_info_list
vnfc_info = db_inst_vnf_info[
'vnfc_info']
vnfc_info_list = [VnfcInfo.
obj_from_primitive(vnfc, context) for vnfc in
vnfc_info]
inst_vnf_info.vnfc_info = vnfc_info_list
inst_vnf_info._context = context
inst_vnf_info.obj_reset_changes()
return inst_vnf_info
@ -241,6 +255,12 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
'virtual_storage_resource_info', [])]
primitive.update({'virtual_storage_resource_info': obj_data})
if 'vnfc_info' in primitive.keys():
obj_data = [VnfcInfo.obj_from_primitive(
vnfc_info, context) for vnfc_info in primitive.get(
'vnfc_info', [])]
primitive.update({'vnfc_info': obj_data})
instantiate_vnf_info = \
InstantiatedVnfInfo._from_dict(primitive)
@ -265,6 +285,7 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
vnf_state = data_dict.get('vnf_state')
instantiation_level_id = data_dict.get('instantiation_level_id')
additional_params = data_dict.get('additional_params', {})
vnfc_info = data_dict.get('vnfc_info', [])
obj = cls(flavour_id=flavour_id, ext_cp_info=ext_cp_info,
ext_virtual_link_info=ext_virtual_link_info,
@ -272,6 +293,7 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
vnfc_resource_info=vnfc_resource_info,
vnf_virtual_link_resource_info=vnf_virtual_link_resource_info,
virtual_storage_resource_info=virtual_storage_resource_info,
vnfc_info=vnfc_info,
vnf_state=vnf_state,
instantiation_level_id=instantiation_level_id,
additional_params=additional_params)
@ -328,6 +350,14 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
data.update({'virtual_storage_resource_info':
virtual_storage_resource_info_list})
if self.vnfc_info:
vnfc_info = []
for vnfc in self.vnfc_info:
info = vnfc.to_dict()
vnfc_info.append(info)
data.update({'vnfc_info': vnfc_info})
data.update({'additional_params':
self.additional_params})
@ -343,6 +373,7 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
self.virtual_storage_resource_info = []
self.instance_id = None
self.vnf_state = fields.VnfOperationalStateType.STOPPED
self.vnfc_info = []
@base.TackerObjectRegistry.register
@ -358,6 +389,7 @@ class VnfExtCpInfo(base.TackerObject, base.TackerObjectDictCompat,
'cp_protocol_info': fields.ListOfObjectsField(
'CpProtocolInfo', nullable=False, default=[]),
'ext_link_port_id': fields.StringField(nullable=True, default=None),
'associated_vnfc_cp_id': fields.StringField(nullable=False)
}
@classmethod
@ -383,16 +415,19 @@ class VnfExtCpInfo(base.TackerObject, base.TackerObjectDictCompat,
cpd_id = data_dict.get('cpd_id')
cp_protocol_info = data_dict.get('cp_protocol_info', [])
ext_link_port_id = data_dict.get('ext_link_port_id')
associated_vnfc_cp_id = data_dict.get('associated_vnfc_cp_id')
obj = cls(id=id, cpd_id=cpd_id,
cp_protocol_info=cp_protocol_info,
ext_link_port_id=ext_link_port_id)
ext_link_port_id=ext_link_port_id,
associated_vnfc_cp_id=associated_vnfc_cp_id)
return obj
def to_dict(self):
data = {'id': self.id,
'cpd_id': self.cpd_id,
'ext_link_port_id': self.ext_link_port_id}
'ext_link_port_id': self.ext_link_port_id,
'associated_vnfc_cp_id': self.associated_vnfc_cp_id}
cp_protocol_info_list = []
for cp_protocol_info in self.cp_protocol_info:
@ -987,12 +1022,53 @@ class VirtualStorageResourceInfo(base.TackerObject,
'storage_resource': self.storage_resource.to_dict()}
@base.TackerObjectRegistry.register
class VnfcInfo(base.TackerObject, base.TackerPersistentObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'id': fields.StringField(nullable=False),
'vdu_id': fields.StringField(nullable=False),
'vnfc_state': fields.StringField(nullable=False)
}
@classmethod
def obj_from_primitive(cls, primitive, context):
if 'tacker_object.name' in primitive:
obj_vnfc_info = super(
VnfcInfo, cls).obj_from_primitive(
primitive, context)
else:
obj_vnfc_info = VnfcInfo._from_dict(
primitive)
return obj_vnfc_info
@classmethod
def _from_dict(cls, data_dict):
id = data_dict.get('id')
vdu_id = data_dict.get('vdu_id')
vnfc_state = data_dict.get('vnfc_state')
obj = cls(id=id, vdu_id=vdu_id,
vnfc_state=vnfc_state)
return obj
def to_dict(self):
return {'id': self.id,
'vdu_id': self.vdu_id,
'vnfc_state': self.vnfc_state}
@base.TackerObjectRegistry.register
class ResourceHandle(base.TackerObject,
base.TackerPersistentObject):
# Version 1.0: Initial version
VERSION = '1.0'
# TODO(esto-aln):Add vimConnectionId in Type:ResourceHandle
fields = {
'resource_id': fields.StringField(nullable=False, default=""),
'vim_level_resource_type': fields.StringField(nullable=True,

View File

@ -298,7 +298,8 @@ virtual_storage_resource_info = {
vnf_ext_cp_info = {
'id': uuidsentinel.id,
'cpd_id': 'CP1',
'cp_protocol_info': [cp_protocol_info]
'cp_protocol_info': [cp_protocol_info],
'associated_vnfc_cp_id': uuidsentinel.associated_vnfc_cp_id
}

View File

@ -120,12 +120,14 @@ def get_instantiated_info_dict_for_ext_links_and_flavour_id():
"layer_protocol": "IP_OVER_ETHERNET"}],
"cpd_id": "CP1",
"id": "19f0aa71-9376-43dc-8e13-5e76e4bdc8bf",
"ext_link_port_id": None}, {
"ext_link_port_id": None,
"associated_vnfc_cp_id": "dc67ee99-e963-44e2-a152-f0fb492eae76"}, {
"cp_protocol_info": [{
"layer_protocol": "IP_OVER_ETHERNET"}],
"cpd_id": "CP2",
"id": "f47a9e33-b31a-4290-828a-c7569c52bd0e",
"ext_link_port_id": None}]
"ext_link_port_id": None,
"associated_vnfc_cp_id": "7ec01a11-e584-404a-88bd-39a56b63e29c"}]
}
}

View File

@ -33,6 +33,43 @@ from tacker.tests import uuidsentinel
from tacker import wsgi
def return_default_vim():
default_vim = {
'vim_auth': {
'username': 'user123',
'password': 'pass123'
},
'placement_attr': {
'region': 'RegionOne'
},
'tenant': uuidsentinel.tenant_uuid,
'vim_id': uuidsentinel.vim_uuid,
'vim_type': 'openstack'
}
return default_vim
def return_vim_connection_object(fields):
access_info = {
'username': fields.get('vim_auth', {}).
get('username'),
'password': fields.get('vim_auth', {}).
get('password'),
'region': fields.get('placement_attr', {}).
get('region'),
'tenant': fields.get('tenant')
}
vim_con_info = objects.\
VimConnectionInfo(id=fields.get('vim_id'),
vim_id=fields.get('vim_id'),
vim_type=fields.get('vim_type'),
access_info=access_info)
return vim_con_info
def fake_vnf_package_vnfd_model_dict(**updates):
vnfd = {
'package_uuid': uuidsentinel.package_uuid,

View File

@ -65,6 +65,13 @@ class TestController(base.TestCase):
return_value={'VNFM': nfvo_plugin.FakeVNFMPlugin()})
self.mock_manager = self.patcher.start()
self.controller = controller.VnfLcmController()
self.vim_info = {
'vim_id': uuidsentinel.vnfd_id,
'vim_type': 'test',
'vim_auth': {'username': 'test', 'password': 'test'},
'placement_attr': {'region': 'TestRegionOne'},
'tenant': 'test'
}
def tearDown(self):
self.mock_manager.stop()
@ -74,6 +81,7 @@ class TestController(base.TestCase):
def app(self):
return fakes.wsgi_app_v1()
@mock.patch.object(objects.VnfInstance, 'save')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@ -82,8 +90,9 @@ class TestController(base.TestCase):
def test_create_without_name_and_description(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create, mock_package_save,
mock_get_by_id_package, mock_get_vim):
mock_get_by_id_package, mock_get_vim,
mock_save):
mock_get_vim.return_value = self.vim_info
mock_get_by_id_package_vnfd.return_value = \
fakes.return_vnf_package_vnfd()
mock_get_by_id_package.return_value = \
@ -121,6 +130,7 @@ class TestController(base.TestCase):
self.assertEqual(expected_vnf, resp.json)
self.assertEqual(location_header, resp.headers['location'])
@mock.patch.object(objects.VnfInstance, 'save')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@ -129,7 +139,9 @@ class TestController(base.TestCase):
def test_create_with_name_and_description(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create, mock_package_save,
mock_get_by_id_package, mock_get_vim):
mock_get_by_id_package, mock_get_vim,
mock_save):
mock_get_vim.return_value = self.vim_info
mock_get_by_id_package_vnfd.return_value = \
fakes.return_vnf_package_vnfd()
mock_get_by_id_package.return_value = \
@ -169,6 +181,7 @@ class TestController(base.TestCase):
self.assertEqual(expected_vnf, resp.json)
self.assertEqual(location_header, resp.headers['location'])
@mock.patch.object(objects.VnfInstance, 'save')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@ -177,7 +190,9 @@ class TestController(base.TestCase):
def test_create_without_name_and_description_with_v241(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create, mock_package_save,
mock_get_by_id_package, mock_get_vim):
mock_get_by_id_package, mock_get_vim,
mock_save):
mock_get_vim.return_value = self.vim_info
mock_get_by_id_package_vnfd.return_value = \
fakes.return_vnf_package_vnfd()
mock_get_by_id_package.return_value = \
@ -1098,28 +1113,22 @@ class TestController(base.TestCase):
self.assertEqual(expected_message, exception.msg)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@ddt.data(' ', '2.6.1')
def test_index(self, api_version, mock_vnf_list):
def test_index(self, mock_vnf_list):
req = fake_request.HTTPRequest.blank('/vnf_instances')
req.headers['Version'] = api_version
vnf_instance_1 = fakes.return_vnf_instance()
vnf_instance_2 = fakes.return_vnf_instance(
fields.VnfInstanceState.INSTANTIATED)
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
resp = self.controller.index(req)
expected_result = [fakes.fake_vnf_instance_response(
api_version=api_version),
expected_result = [fakes.fake_vnf_instance_response(),
fakes.fake_vnf_instance_response(
fields.VnfInstanceState.INSTANTIATED,
api_version=api_version)]
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, resp)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@ddt.data(' ', '2.6.1')
def test_index_empty_response(self, api_version, mock_vnf_list):
def test_index_empty_response(self, mock_vnf_list):
req = fake_request.HTTPRequest.blank('/vnf_instances')
req.headers['Version'] = api_version
mock_vnf_list.return_value = []
resp = self.controller.index(req)
self.assertEqual([], resp)
@ -1234,12 +1243,10 @@ class TestController(base.TestCase):
)
def test_index_filter_operator(self, filter_params, mock_vnf_list):
"""Tests all supported operators in filter expression."""
api_version = '2.6.1'
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = api_version
vnf_instance_1 = fakes.return_vnf_instance()
vnf_instance_2 = fakes.return_vnf_instance(
@ -1248,11 +1255,9 @@ class TestController(base.TestCase):
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
res_dict = self.controller.index(req)
expected_result = [fakes.fake_vnf_instance_response(
api_version=api_version),
expected_result = [fakes.fake_vnf_instance_response(),
fakes.fake_vnf_instance_response(
fields.VnfInstanceState.INSTANTIATED,
api_version=api_version)]
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, res_dict)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@ -1262,11 +1267,9 @@ class TestController(base.TestCase):
'filter': "(eq,vnfInstanceName,'dummy_name');"
"(eq,vnfInstanceDescription,'dummy_desc')"}
api_version = '2.6.1'
query = urllib.parse.urlencode(params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = '2.6.1'
vnf_instance_1 = fakes.return_vnf_instance()
vnf_instance_2 = fakes.return_vnf_instance(
@ -1275,11 +1278,9 @@ class TestController(base.TestCase):
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
res_dict = self.controller.index(req)
expected_result = [fakes.fake_vnf_instance_response(
api_version=api_version),
expected_result = [fakes.fake_vnf_instance_response(),
fakes.fake_vnf_instance_response(
fields.VnfInstanceState.INSTANTIATED,
api_version=api_version)]
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, res_dict)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@ -1318,11 +1319,9 @@ class TestController(base.TestCase):
def test_index_filter_attributes(self, filter_params,
mock_vnf_list):
"""Test various attributes supported for filter parameter."""
api_version = '2.6.1'
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = '2.6.1'
vnf_instance_1 = fakes.return_vnf_instance()
vnf_instance_2 = fakes.return_vnf_instance(
@ -1331,11 +1330,9 @@ class TestController(base.TestCase):
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
res_dict = self.controller.index(req)
expected_result = [fakes.fake_vnf_instance_response(
api_version=api_version),
expected_result = [fakes.fake_vnf_instance_response(),
fakes.fake_vnf_instance_response(
fields.VnfInstanceState.INSTANTIATED,
api_version=api_version)]
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, res_dict)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@ -1348,11 +1345,9 @@ class TestController(base.TestCase):
def test_index_filter_invalid_expression(self, filter_params,
mock_vnf_list):
"""Test invalid filter expression."""
api_version = '2.6.1'
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = api_version
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@ -1369,11 +1364,9 @@ class TestController(base.TestCase):
def test_index_filter_invalid_string_values(self, filter_params,
mock_vnf_list):
"""Test invalid string values as per ETSI NFV SOL013 5.2.2."""
api_version = '2.6.1'
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = api_version
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@ -1386,11 +1379,9 @@ class TestController(base.TestCase):
def test_index_filter_invalid_operator(self, filter_params,
mock_vnf_list):
"""Test invalid operator in filter expression."""
api_version = '2.6.1'
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = api_version
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@ -1402,11 +1393,9 @@ class TestController(base.TestCase):
def test_index_filter_invalid_attribute(self, filter_params,
mock_vnf_list):
"""Test invalid attribute in filter expression."""
api_version = '2.6.1'
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = api_version
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@ -1420,10 +1409,8 @@ class TestController(base.TestCase):
def test_index_filter_invalid_value_type(self, filter_params,
mock_vnf_list):
"""Test values which doesn't match with attribute data type."""
api_version = '2.6.1'
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
req.headers['Version'] = api_version
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)

View File

@ -26,7 +26,8 @@ class TestVIMClient(base.TestCase):
self.vim_info = {'id': 'aaaa', 'name': 'VIM0', 'type': 'test_vim',
'auth_cred': {'password': '****'},
'auth_url': 'http://127.0.0.1/identity/v3',
'placement_attr': {'regions': ['TestRegionOne']}}
'placement_attr': {'regions': ['TestRegionOne']},
'tenant_id': 'test'}
self.vimclient = vim_client.VimClient()
self.service_plugins = mock.Mock()
self.nfvo_plugin = mock.Mock()
@ -71,7 +72,8 @@ class TestVIMClient(base.TestCase):
vim_id=self.vim_info['id'],
region_name='TestRegionOne')
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
'vim_name': 'VIM0', 'vim_type': 'test_vim'}
'vim_name': 'VIM0', 'vim_type': 'test_vim',
'tenant': 'test'}
self.assertEqual(vim_expect, vim_result)
def test_get_vim_with_default_name(self):
@ -86,7 +88,8 @@ class TestVIMClient(base.TestCase):
vim_id=self.vim_info['id'],
region_name='TestRegionOne')
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
'vim_name': 'aaaa', 'vim_type': 'test_vim'}
'vim_name': 'aaaa', 'vim_type': 'test_vim',
'tenant': 'test'}
self.assertEqual(vim_expect, vim_result)
def test_find_vim_key_with_key_not_found_exception(self):

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import io
import os
import six
@ -256,6 +257,10 @@ def _get_vim_connection_info_from_vnf_req(vnf_instance, instantiate_vnf_req):
vim_connection_obj_list = []
if not instantiate_vnf_req.vim_connection_info:
# add default vim
if len(vnf_instance.vim_connection_info):
vim_connection_obj_list.append(vnf_instance.vim_connection_info[0])
return vim_connection_obj_list
for vim_connection in instantiate_vnf_req.vim_connection_info:
@ -265,6 +270,16 @@ def _get_vim_connection_info_from_vnf_req(vnf_instance, instantiate_vnf_req):
vim_connection_obj_list.append(vim_conn)
# add default vim
if len(vnf_instance.vim_connection_info):
if vim_conn.id and vnf_instance.vim_connection_info[0].id:
is_default_vim_exist = [vim_conn for vim_conn
in vim_connection_obj_list
if vim_conn.id == vnf_instance.vim_connection_info[0].id]
if not len(is_default_vim_exist):
vim_connection_obj_list.append(vnf_instance.
vim_connection_info[0])
return vim_connection_obj_list
@ -272,9 +287,6 @@ def _build_instantiated_vnf_info(vnfd_dict, instantiate_vnf_req,
vnf_instance, vim_id):
inst_vnf_info = vnf_instance.instantiated_vnf_info
inst_vnf_info.vnf_state = fields.VnfOperationalStateType.STARTED
inst_vnf_info.ext_cp_info = _set_ext_cp_info(instantiate_vnf_req)
inst_vnf_info.ext_virtual_link_info = _set_ext_virtual_link_info(
instantiate_vnf_req, inst_vnf_info.ext_cp_info)
node_templates = vnfd_dict.get(
'topology_template', {}).get('node_templates')
@ -283,6 +295,13 @@ def _build_instantiated_vnf_info(vnfd_dict, instantiate_vnf_req,
_get_vnfc_resource_info(vnfd_dict, instantiate_vnf_req, vim_id)
inst_vnf_info.vnfc_resource_info = vnfc_resource_info
tmp_insta_vnf_info = copy.deepcopy(inst_vnf_info)
inst_vnf_info.ext_cp_info = _set_ext_cp_info(instantiate_vnf_req,
inst_vnf_info=tmp_insta_vnf_info)
inst_vnf_info.ext_virtual_link_info = _set_ext_virtual_link_info(
instantiate_vnf_req, inst_vnf_info.ext_cp_info)
inst_vnf_info.virtual_storage_resource_info = \
virtual_storage_resource_info
inst_vnf_info.vnf_virtual_link_resource_info = \
@ -530,8 +549,12 @@ def _get_vnfc_resource_info(vnfd_dict, instantiate_vnf_req, vim_id):
return vnfc_resource_info_list, virtual_storage_resource_info_list
def _set_ext_cp_info(instantiate_vnf_req):
def _set_ext_cp_info(instantiate_vnf_req, inst_vnf_info=None):
ext_cp_info_list = []
vnfc_info = []
if inst_vnf_info.vnfc_resource_info:
vnfc_info = inst_vnf_info.vnfc_resource_info
if not instantiate_vnf_req.ext_virtual_links:
return ext_cp_info_list
@ -546,6 +569,8 @@ def _set_ext_cp_info(instantiate_vnf_req):
cpd_id=ext_cp.cpd_id,
cp_protocol_info=_set_cp_protocol_info(ext_cp),
ext_link_port_id=_get_ext_link_port_id(ext_virt_link,
ext_cp.cpd_id),
associated_vnfc_cp_id=_get_associated_vnfc_cp_id(vnfc_info,
ext_cp.cpd_id))
ext_cp_info_list.append(ext_cp_info)
@ -562,6 +587,17 @@ def _get_ext_link_port_id(ext_virtual_link, cpd_id):
return ext_link.id
def _get_associated_vnfc_cp_id(vnfc_info, cpd_id):
if not isinstance(vnfc_info, list):
return
for vnfc in vnfc_info:
if vnfc.vnfc_cp_info:
for cp_info in vnfc.vnfc_cp_info:
if cp_info.cpd_id == cpd_id:
return vnfc.id
def _build_ip_over_ethernet_address_info(cp_protocol_data):
"""Convert IpOverEthernetAddressData to IpOverEthernetAddressInfo"""

View File

@ -27,6 +27,7 @@ from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import excutils
from oslo_utils import uuidutils
import yaml
from tacker._i18n import _
@ -36,6 +37,7 @@ from tacker.common import utils
from tacker.extensions import vnflcm
from tacker.extensions import vnfm
from tacker import objects
from tacker.objects import fields
from tacker.tosca.utils import represent_odict
from tacker.vnfm.infra_drivers import abstract_driver
from tacker.vnfm.infra_drivers.openstack import constants as infra_cnst
@ -796,6 +798,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
inst_vnf_info.instance_id, heatclient)
self._update_vnfc_resources(vnf_instance, stack_resources)
self._update_vnfc_info(vnf_instance)
def _update_resource_handle(self, vnf_instance, resource_handle,
stack_resources, resource_name):
@ -926,6 +929,18 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
for vl_port in vnf_vl_resource_info.vnf_link_ports:
_update_link_port(vl_port)
def _update_vnfc_info(self, vnf_instance):
inst_vnf_info = vnf_instance.instantiated_vnf_info
vnfc_info = []
for vnfc_res_info in inst_vnf_info.vnfc_resource_info:
vnfc = objects.VnfcInfo(id=uuidutils.generate_uuid(),
vdu_id=vnfc_res_info.vdu_id,
vnfc_state=fields.VnfcState.STARTED)
vnfc_info.append(vnfc)
inst_vnf_info.vnfc_info = vnfc_info
def _update_vnfc_resources(self, vnf_instance, stack_resources):
inst_vnf_info = vnf_instance.instantiated_vnf_info
for vnfc_res_info in inst_vnf_info.vnfc_resource_info:

View File

@ -63,7 +63,8 @@ class VimClient(object):
vim_auth = self._build_vim_auth(vim_info)
vim_res = {'vim_auth': vim_auth, 'vim_id': vim_info['id'],
'vim_name': vim_info.get('name', vim_info['id']),
'vim_type': vim_info['type']}
'vim_type': vim_info['type'],
'tenant': vim_info['tenant_id']}
return vim_res
@staticmethod