Support Flow of the Get Operation Status
Supported Flow of the Get Operation Status as the part of LCM notifications for VNF based on ETSI NFV-SOL specification. Implements: blueprint support-etsi-nfv-specs Spec: https://specs.openstack.org/openstack/tacker-specs/specs/victoria/support-notification-api-based-on-etsi-nfv-sol.html Change-Id: Id23d025aeba568c4c67adc745171c0540140d233
This commit is contained in:
parent
f8f58e8cec
commit
13065dfbdd
|
@ -12,6 +12,12 @@ vnf_instance_id:
|
|||
in: path
|
||||
required: true
|
||||
type: string
|
||||
vnf_lcm_op_occ_id:
|
||||
description: |
|
||||
Identifier of the VNF lifecycle management operation occurrence.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
|
||||
# variables in body
|
||||
added_storage_resource_ids:
|
||||
|
@ -714,6 +720,15 @@ is_automatic_invocation:
|
|||
in: body
|
||||
required: true
|
||||
type: boolean
|
||||
is_cancel_pending:
|
||||
description: |
|
||||
If the VNF LCM operation occurrence is in "STARTING",
|
||||
"PROCESSING" or "ROLLING_BACK" state and the
|
||||
operation is being cancelled, this attribute shall be set to
|
||||
true. Otherwise, it shall be set to false.
|
||||
in: body
|
||||
required: true
|
||||
type: boolean
|
||||
is_dynamic:
|
||||
description: |
|
||||
Indicates whether this set of addresses was assigned dynamically (true)
|
||||
|
@ -827,6 +842,45 @@ notification_vnf_lcm_op_occ_id:
|
|||
in: body
|
||||
required: true
|
||||
type: string
|
||||
operation:
|
||||
description: |
|
||||
Type of the actual LCM operation represented by this
|
||||
VNF LCM operation occurrence.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
operation_params:
|
||||
description: |
|
||||
Input parameters of the LCM operation. This attribute
|
||||
shall be formatted according to the request data type of
|
||||
the related LCM operation.
|
||||
The following mapping between operationType and the
|
||||
data type of this attribute shall apply:
|
||||
|
||||
INSTANTIATE: InstantiateVnfRequest
|
||||
|
||||
SCALE: ScaleVnfRequest
|
||||
|
||||
HEAL: HealVnfRequest
|
||||
|
||||
TERMINATE: TerminateVnfRequest
|
||||
|
||||
MODIFY_INFO: VnfInfoModificationRequest
|
||||
|
||||
This attribute shall be present if this data type is returned
|
||||
in a response to reading an individual resource, and may
|
||||
be present according to the chosen attribute selector
|
||||
parameter if this data type is returned in a response to a
|
||||
query of a container resource.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
operation_state:
|
||||
description: |
|
||||
The state of the LCM operation.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
removed_storage_resource_ids:
|
||||
description: |
|
||||
References to VirtualStorage resources that
|
||||
|
@ -840,6 +894,14 @@ removed_storage_resource_ids:
|
|||
in: body
|
||||
required: false
|
||||
type: array
|
||||
resource_changes:
|
||||
description: |
|
||||
This attribute contains information about the cumulative
|
||||
changes to virtualised resources that were performed so
|
||||
far by the LCM operation since its start, if applicable.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
resource_handle:
|
||||
description: |
|
||||
Reference to the resource realizing this VL.
|
||||
|
@ -884,6 +946,18 @@ scale_status_scale_level:
|
|||
in: body
|
||||
required: true
|
||||
type: string
|
||||
start_time:
|
||||
description: |
|
||||
Date-time of the start of the operation.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
state_entered_time:
|
||||
description: |
|
||||
Date-time when the current state has been entered.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
subnet_id:
|
||||
description: |
|
||||
Subnet defined by the identifier of the subnet resource in the VIM.
|
||||
|
@ -1170,6 +1244,18 @@ vnf_instance_vnfd_version:
|
|||
in: body
|
||||
required: true
|
||||
type: string
|
||||
vnf_lcm_op_occ_id_response:
|
||||
description: |
|
||||
Identifier of this VNF lifecycle management operation occurrence.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
vnf_lcm_vnf_instance_id:
|
||||
description: |
|
||||
Identifier of the VNF instance to which the operation applies.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
vnf_link_port_cp_instance_id:
|
||||
description: |
|
||||
When the link port is used for external connectivity by the VNF, this
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"id": "d85c6ae4-af16-42c0-96fc-82f7c014c468",
|
||||
"operationState": "COMPLETED",
|
||||
"stateEnteredTime": "2020-08-02T06:50:50.883373",
|
||||
"startTime": "2020-08-02T06:41:34.883483",
|
||||
"vnfInstanceId": "0b7b95a9-21d5-4ac4-80c8-9ae9f7323787",
|
||||
"operation": "INSTANTIATE",
|
||||
"isAutomaticInvocation": false,
|
||||
"operationParams": "{
|
||||
"flavourId": "default",
|
||||
"instantiationLevelId": "vnf-min",
|
||||
}"
|
||||
"isCancelPending": false,
|
||||
"resourceChanges": {
|
||||
"affectedVnfcs": [
|
||||
{
|
||||
"id": "36e24439-829c-4803-a413-385cd658d544",
|
||||
"vduId": "VDU",
|
||||
"changeType": "ADDED",
|
||||
"computeResource": {
|
||||
"vimConnectionId": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resourceId": "e0510ba9-3a53-4fcf-9dcc-58dea5c048b0",
|
||||
"vimLevelResourceType": "OS::Nova::Server",
|
||||
},
|
||||
"affectedVnfcCpIds": [
|
||||
"VDU1_CP0",
|
||||
"VDU1_CP1"
|
||||
],
|
||||
"addedStorageResourceIds": [
|
||||
"81ae44f6-b65b-47aa-a578-e53b7a50a574"
|
||||
]
|
||||
}
|
||||
],
|
||||
"affectedVirtualLinks": [
|
||||
{
|
||||
"id": "9836f7f2-5af4-4df5-a89f-933479448ef7",
|
||||
"vnfVirtualLinkDescId": "internalNW",
|
||||
"changeType": "ADDED",
|
||||
"networkResource": {
|
||||
"vimConnectionId": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resourceId": "400692e5-b2db-478e-acb1-b77a92635ec6",
|
||||
"vimLevelResourceType": "OS::Neutron::Net"
|
||||
}
|
||||
}
|
||||
],
|
||||
"affectedVirtualStorages": [
|
||||
{
|
||||
"id": "81ae44f6-b65b-47aa-a578-e53b7a50a574",
|
||||
"virtualStorageDescId": "Storage",
|
||||
"changeType": "ADDED",
|
||||
"storageResource": {
|
||||
"vimConnectionId": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resourceId": "842f527e-0092-4f11-aede-f981ba4fd884",
|
||||
"vimLevelResourceType": "OS::Cinder::Volume"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "http://sample.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468"
|
||||
},
|
||||
"vnfInstance": {
|
||||
"href": "http://sample.com/vnflcm/v1/vnf_instances/0b7b95a9-21d5-4ac4-80c8-9ae9f7323787"
|
||||
},
|
||||
"grant": {
|
||||
"href": "/grant/v1/grants/3432cebe-db0a-11e8-9023-005056317abe"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -570,6 +570,110 @@ Response Example
|
|||
.. literalinclude:: samples/vnflcm/list-vnf-instance-response.json
|
||||
:language: javascript
|
||||
|
||||
Show VNF LCM operation occurrence
|
||||
=================================
|
||||
|
||||
.. rest_method:: GET /vnflcm/v1/vnf_lcm_op_occs/{vnfLcmOpOccId}
|
||||
|
||||
The client can use this method to retrieve status information about a VNF lifecycle management operation occurrence
|
||||
by reading an "Individual VNF LCM operation occurrence" resource.
|
||||
|
||||
Response Codes
|
||||
--------------
|
||||
|
||||
.. rest_status_code:: success status.yaml
|
||||
|
||||
- 200
|
||||
|
||||
.. rest_status_code:: error status.yaml
|
||||
|
||||
- 400
|
||||
- 401
|
||||
- 403
|
||||
- 404
|
||||
|
||||
Request Parameters
|
||||
------------------
|
||||
|
||||
.. rest_parameters:: parameters_vnflcm.yaml
|
||||
|
||||
- vnfLcmOpOccId: vnf_lcm_op_occ_id
|
||||
|
||||
Response Parameters
|
||||
-------------------
|
||||
|
||||
.. rest_parameters:: parameters_vnflcm.yaml
|
||||
|
||||
- id: vnf_lcm_op_occ_id_response
|
||||
- operationState: operation_state
|
||||
- stateEnteredTime: state_entered_time
|
||||
- startTime: start_time
|
||||
- vnfInstanceId: vnf_lcm_vnf_instance_id
|
||||
- operation: operation
|
||||
- isAutomaticInvocation: is_automatic_invocation
|
||||
- operationParams: operation_params
|
||||
- isCancelPending: is_cancel_pending
|
||||
- error: error
|
||||
- title: error_title
|
||||
- status: error_status
|
||||
- detail: error_detail
|
||||
- resourceChanges: resource_changes
|
||||
- affectedVnfcs: affected_vnfcs
|
||||
- id: affected_vnfcs_id
|
||||
- vduId: affected_vnfcs_vdu_id
|
||||
- changeType: affected_vnfcs_change_type
|
||||
- computeResource: vnfc_resource_info_compute_resource
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- affectedVnfcCpIds: affected_vnfc_cp_ids
|
||||
- addedStorageResourceIds: added_storage_resource_ids
|
||||
- removedStorageResourceIds: removed_storage_resource_ids
|
||||
- affectedVirtualLinks: affected_virtual_links
|
||||
- id: affected_virtual_links_id
|
||||
- vnfVirtualLinkDescId: vnf_virtual_link_resource_info_vnf_virtual_link_desc_id
|
||||
- changeType: affected_virtual_links_change_type
|
||||
- networkResource: vnf_virtual_link_resource_info_network_resource
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- affectedVirtualStorages: affected_virtual_storages
|
||||
- id: affected_virtual_storages_id
|
||||
- virtualStorageDescId: affected_virtual_storages_virtual_storage_desc_id
|
||||
- changeType: affected_virtual_storages_change_type
|
||||
- storageResource: virtual_storage_resource_info_storage_resource
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- changedInfo: changed_info
|
||||
- vnfInstanceName: changed_info_vnf_instance_name
|
||||
- vnfInstanceDescription: changed_info_vnf_instance_description
|
||||
- metadata: changed_info_metadata
|
||||
- vimConnectionInfo: changed_info_vim_connection_info
|
||||
- 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
|
||||
- username: vim_connection_info_access_info_username
|
||||
- region: vim_connection_info_access_info_region
|
||||
- password: vim_connection_info_access_info_password
|
||||
- tenant: vim_connection_info_access_info_tenant
|
||||
- vnfPkgId: changed_info_vnf_pkg_id
|
||||
- vnfdId: changed_info_vnfd_id
|
||||
- vnfProvider: changed_info_vnf_provider
|
||||
- vnfProductName: changed_info_vnf_product_name
|
||||
- vnfSotwareVersion: changed_info_vnf_sotware_version
|
||||
- vnfdVersion: changed_info_vnfd_version
|
||||
- _links: vnf_instance_links
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: samples/vnflcm/show-vnflcm-operation-occurrence-response.json
|
||||
:language: javascript
|
||||
|
||||
Create a new subscription
|
||||
=========================
|
||||
|
||||
|
|
|
@ -89,7 +89,35 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
|
||||
return vim_connections
|
||||
|
||||
def _get_vnf_instance_info(self, vnf_instance):
|
||||
def _get_lcm_op_occs_links(self, vnf_lcm_op_occs):
|
||||
_links = {
|
||||
"self": {
|
||||
"href": '%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"vnfInstance": {
|
||||
"href": '%(endpoint)s/vnflcm/v1/vnf_instances/%(id)s'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.vnf_instance_id}
|
||||
},
|
||||
"rollback": {
|
||||
"href":
|
||||
'%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/rollback'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"grant": {
|
||||
"href": '%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/grant'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
}
|
||||
}
|
||||
|
||||
return {"_links": _links}
|
||||
|
||||
def _get_vnf_instance_info(self,
|
||||
vnf_instance, api_version=None):
|
||||
vnf_instance_dict = vnf_instance.to_dict()
|
||||
if vnf_instance_dict.get('vim_connection_info'):
|
||||
vnf_instance_dict['vim_connection_info'] = \
|
||||
|
@ -108,6 +136,17 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
vnf_instance_dict.update(links)
|
||||
return vnf_instance_dict
|
||||
|
||||
def _get_vnf_lcm_op_occs(self, vnf_lcm_op_occs):
|
||||
vnf_lcm_op_occs_dict = vnf_lcm_op_occs.to_dict()
|
||||
vnf_lcm_op_occs_dict.pop('error_point')
|
||||
vnf_lcm_op_occs_dict = utils.convert_snakecase_to_camelcase(
|
||||
vnf_lcm_op_occs_dict)
|
||||
|
||||
links = self._get_lcm_op_occs_links(vnf_lcm_op_occs)
|
||||
|
||||
vnf_lcm_op_occs_dict.update(links)
|
||||
return vnf_lcm_op_occs_dict
|
||||
|
||||
def create(self, vnf_instance):
|
||||
return self._get_vnf_instance_info(vnf_instance)
|
||||
|
||||
|
@ -224,3 +263,6 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
|
||||
def subscription_show(self, vnf_lcm_subscriptions):
|
||||
return self._get_vnf_lcm_subscription(vnf_lcm_subscriptions)
|
||||
|
||||
def show_lcm_op_occs(self, vnf_lcm_op_occs):
|
||||
return self._get_vnf_lcm_op_occs(vnf_lcm_op_occs)
|
||||
|
|
|
@ -545,6 +545,24 @@ class VnfLcmController(wsgi.Controller):
|
|||
vnf_instance = self._get_vnf_instance(context, id)
|
||||
self._heal(context, vnf_instance, vnf, body)
|
||||
|
||||
@wsgi.response(http_client.OK)
|
||||
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND))
|
||||
def show_lcm_op_occs(self, request, id):
|
||||
context = request.environ['tacker.context']
|
||||
context.can(vnf_lcm_policies.VNFLCM % 'show_lcm_op_occs')
|
||||
|
||||
try:
|
||||
vnf_lcm_op_occs = objects.VnfLcmOpOcc.get_by_id(context, id)
|
||||
except exceptions.NotFound as occ_e:
|
||||
return self._make_problem_detail(str(occ_e),
|
||||
404, title='VnfLcmOpOcc NOT FOUND')
|
||||
except Exception as e:
|
||||
LOG.error(traceback.format_exc())
|
||||
return self._make_problem_detail(str(e),
|
||||
500, title='Internal Server Error')
|
||||
|
||||
return self._view_builder.show_lcm_op_occs(vnf_lcm_op_occs)
|
||||
|
||||
@wsgi.response(http_client.CREATED)
|
||||
@validation.schema(vnf_lcm.register_subscription)
|
||||
def register_subscription(self, request, body):
|
||||
|
|
|
@ -77,6 +77,12 @@ class VnflcmAPIRouter(wsgi.Router):
|
|||
"/vnf_instances/{id}/heal",
|
||||
methods, controller, default_resource)
|
||||
|
||||
# Allowed methods on
|
||||
# /vnflcm/v1/vnf_lcm_op_occs/{vnfLcmOpOccId} resource
|
||||
methods = {"GET": "show_lcm_op_occs"}
|
||||
self._setup_route(mapper, "/vnf_lcm_op_occs/{id}",
|
||||
methods, controller, default_resource)
|
||||
|
||||
# Allowed methods on
|
||||
# /vnflcm/v1/vnf_instances/{vnfInstanceId}/terminate resource
|
||||
methods = {"POST": "terminate"}
|
||||
|
|
|
@ -186,6 +186,37 @@ class VnfcState(BaseTackerEnum):
|
|||
ALL = (STARTED, STOPPED)
|
||||
|
||||
|
||||
class InstanceOperationalState(BaseTackerEnum):
|
||||
STARTING = 'STARTING'
|
||||
PROCESSING = 'PROCESSING'
|
||||
COMPLETED = 'COMPLETED'
|
||||
FAILED_TEMP = 'FAILED_TEMP'
|
||||
ROLLING_BACK = 'ROLLING_BACK'
|
||||
ROLLED_BACK = 'ROLLED_BACK'
|
||||
|
||||
ALL = (STARTING, PROCESSING, COMPLETED, FAILED_TEMP,
|
||||
ROLLING_BACK, ROLLED_BACK)
|
||||
|
||||
|
||||
class InstanceOperationalStateField(BaseEnumField):
|
||||
AUTO_TYPE = InstanceOperationalState()
|
||||
|
||||
|
||||
class InstanceOperation(BaseTackerEnum):
|
||||
INSTANTIATE = 'INSTANTIATE'
|
||||
SCALE = 'SCALE'
|
||||
TERMINATE = 'TERMINATE'
|
||||
HEAL = 'HEAL'
|
||||
MODIFY_INFO = 'MODIFY_INFO'
|
||||
|
||||
ALL = (INSTANTIATE, SCALE,
|
||||
TERMINATE, HEAL, MODIFY_INFO)
|
||||
|
||||
|
||||
class InstanceOperationField(BaseEnumField):
|
||||
AUTO_TYPE = InstanceOperation()
|
||||
|
||||
|
||||
class LcmOccsOperationState(BaseTackerEnum):
|
||||
STARTING = 'STARTING'
|
||||
PROCESSING = 'PROCESSING'
|
||||
|
|
|
@ -77,6 +77,17 @@ rules = [
|
|||
}
|
||||
]
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=VNFLCM % 'show_lcm_op_occs',
|
||||
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||
description="Query an Individual VNF LCM operation occurrence",
|
||||
operations=[
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/vnflcm/v1/vnf_lcm_op_occs/{vnfLcmOpOccId}'
|
||||
}
|
||||
]
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=VNFLCM % 'index',
|
||||
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||
|
|
|
@ -103,6 +103,7 @@ def get_vnf_package_vnfd():
|
|||
|
||||
def get_lcm_op_occs_data():
|
||||
return {
|
||||
"id": uuidsentinel.lcm_op_occs_id,
|
||||
"tenant_id": uuidsentinel.tenant_id,
|
||||
'operation_state': 'PROCESSING',
|
||||
'state_entered_time':
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from copy import deepcopy
|
||||
import datetime
|
||||
import iso8601
|
||||
import os
|
||||
|
@ -32,6 +32,9 @@ from tacker.tests import constants
|
|||
from tacker.tests import uuidsentinel
|
||||
from tacker import wsgi
|
||||
|
||||
import tacker.conf
|
||||
CONF = tacker.conf.CONF
|
||||
|
||||
|
||||
def return_default_vim():
|
||||
default_vim = {
|
||||
|
@ -140,12 +143,44 @@ def return_vnf_instance_model(
|
|||
|
||||
def return_vnf_instance(
|
||||
instantiated_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||
scale_status=None,
|
||||
**updates):
|
||||
|
||||
if instantiated_state == fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
data = _model_non_instantiated_vnf_instance(**updates)
|
||||
data['instantiation_state'] = instantiated_state
|
||||
vnf_instance_obj = objects.VnfInstance(**data)
|
||||
|
||||
elif scale_status:
|
||||
data = _model_non_instantiated_vnf_instance(**updates)
|
||||
data['instantiation_state'] = instantiated_state
|
||||
vnf_instance_obj = objects.VnfInstance(**data)
|
||||
|
||||
get_instantiated_vnf_info = {
|
||||
'flavour_id': uuidsentinel.flavour_id,
|
||||
'vnf_state': 'STARTED',
|
||||
'instance_id': uuidsentinel.instance_id
|
||||
}
|
||||
instantiated_vnf_info = get_instantiated_vnf_info
|
||||
|
||||
s_status = {"aspect_id": "SP1", "scale_level": 1}
|
||||
scale_status = objects.ScaleInfo(**s_status)
|
||||
|
||||
instantiated_vnf_info.update(
|
||||
{"ext_cp_info": [],
|
||||
'ext_virtual_link_info': [],
|
||||
'ext_managed_virtual_link_info': [],
|
||||
'vnfc_resource_info': [],
|
||||
'vnf_virtual_link_resource_info': [],
|
||||
'virtual_storage_resource_info': [],
|
||||
"flavour_id": "simple",
|
||||
"scale_status": [scale_status],
|
||||
"vnf_instance_id": "171f3af2-a753-468a-b5a7-e3e048160a79",
|
||||
"additional_params": {"key": "value"},
|
||||
'vnf_state': "STARTED"})
|
||||
info_data = objects.InstantiatedVnfInfo(**instantiated_vnf_info)
|
||||
|
||||
vnf_instance_obj.instantiated_vnf_info = info_data
|
||||
else:
|
||||
data = _model_non_instantiated_vnf_instance(**updates)
|
||||
data['instantiation_state'] = instantiated_state
|
||||
|
@ -704,6 +739,27 @@ def get_instantiate_vnf_request_with_ext_virtual_links(**updates):
|
|||
return instantiate_vnf_request
|
||||
|
||||
|
||||
def _get_vnf(**updates):
|
||||
vnf_data = {
|
||||
'tenant_id': uuidsentinel.tenant_id,
|
||||
'name': "fake_name",
|
||||
'vnfd_id': uuidsentinel.vnfd_id,
|
||||
'vnf_instance_id': uuidsentinel.instance_id,
|
||||
'mgmt_ip_address': "fake_mgmt_ip_address",
|
||||
'status': 'ACTIVE',
|
||||
'description': 'fake_description',
|
||||
'placement_attr': 'fake_placement_attr',
|
||||
'vim_id': 'uuidsentinel.vim_id',
|
||||
'error_reason': 'fake_error_reason',
|
||||
'attributes': {
|
||||
"scale_group": '{"scaleGroupDict" : {"SP1": {"maxLevel" : 3}}}'}}
|
||||
|
||||
if updates:
|
||||
vnf_data.update(**updates)
|
||||
|
||||
return vnf_data
|
||||
|
||||
|
||||
def get_dummy_grant_response():
|
||||
return {'VDU1': {'checksum': {'algorithm': 'fake algo',
|
||||
'hash': 'fake hash'},
|
||||
|
@ -756,3 +812,210 @@ def wsgi_app_v1(fake_auth_context=None):
|
|||
uuidsentinel.project_id, is_admin=True)
|
||||
api_v1 = InjectContext(ctxt, inner_app_v1)
|
||||
return api_v1
|
||||
|
||||
|
||||
VNFLCMOPOCC_RESPONSE = {
|
||||
'_links': {
|
||||
"self": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_lcm_op_occs/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef'
|
||||
},
|
||||
"vnfInstance": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_instances/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef'
|
||||
},
|
||||
"rollback": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_lcm_op_occs/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef/rollback'
|
||||
},
|
||||
"grant": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_lcm_op_occs/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef/grant'
|
||||
}},
|
||||
'operationState': 'COMPLETED',
|
||||
'stateEnteredTime': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.UTC),
|
||||
'startTime': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.UTC),
|
||||
'vnfInstanceId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'operation': 'MODIFY_INFO',
|
||||
'isAutomaticInvocation': False,
|
||||
'operationParams': '{"is_reverse": False, "is_auto": False}',
|
||||
'error': {
|
||||
'status': 500,
|
||||
'detail': "name 'con' is not defined",
|
||||
'title': "ERROR"
|
||||
},
|
||||
'id': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'isCancelPending': False,
|
||||
'resourceChanges': {
|
||||
'affectedVnfcs': [{
|
||||
'id': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'vduId': 'VDU1',
|
||||
'changeType': 'ADDED',
|
||||
'computeResource': {
|
||||
'vimConnectionId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'resourceId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'vimLevelResourceType': "OS::Nova::Server",
|
||||
},
|
||||
'affectedVnfcCpIds': [],
|
||||
'addedStorageResourceIds': [],
|
||||
'removedStorageResourceIds': []
|
||||
}],
|
||||
'affectedVirtualLinks': [{
|
||||
'id': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'vnfVirtualLinkDescId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'changeType': 'ADDED',
|
||||
'networkResource': {
|
||||
'vimConnectionId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'resourceId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'vimLevelResourceType': 'COMPUTE'
|
||||
}
|
||||
}],
|
||||
'affectedVirtualStorages': [{
|
||||
'id': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'virtualStorageDescId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'changeType': 'ADDED',
|
||||
'storageResource': {
|
||||
'vimConnectionId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'resourceId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'vimLevelResourceType': 'COMPUTE'
|
||||
}
|
||||
}]
|
||||
},
|
||||
'changedInfo': {
|
||||
'vimConnectionInfo': [],
|
||||
'vimConnectionInfoDeleteIds': [],
|
||||
'vnfPkgId': None,
|
||||
'vnfInstanceName': 'fake_name',
|
||||
'vnfInstanceDescription': "fake_vnf_instance_description",
|
||||
'vnfdId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'vnfProvider': 'fake_vnf_provider',
|
||||
'vnfProductName': 'fake_vnf_product_name',
|
||||
'vnfSoftwareVersion': 'fake_vnf_software_version',
|
||||
'vnfdVersion': 'fake_vnfd_version'
|
||||
}
|
||||
}
|
||||
|
||||
VNFLCMOPOCC_INDEX_RESPONSE = [VNFLCMOPOCC_RESPONSE]
|
||||
|
||||
|
||||
def index_response(remove_attrs=None, vnf_lcm_op_occs_updates=None):
|
||||
# Returns VNFLCMOPOCC_RESPONSE
|
||||
# parameter remove_attrs is a list of attribute names
|
||||
# to be removed before returning the response
|
||||
if not remove_attrs:
|
||||
return VNFLCMOPOCC_INDEX_RESPONSE
|
||||
vnf_lcm_op_occs = deepcopy(VNFLCMOPOCC_RESPONSE)
|
||||
for attr in remove_attrs:
|
||||
vnf_lcm_op_occs.pop(attr, None)
|
||||
if vnf_lcm_op_occs_updates:
|
||||
vnf_lcm_op_occs.update(vnf_lcm_op_occs_updates)
|
||||
return [vnf_lcm_op_occs]
|
||||
|
||||
|
||||
def fake_vnf_lcm_op_occs():
|
||||
error = {"status": 500, "detail": "name 'con' is not defined",
|
||||
"title": "ERROR"}
|
||||
error_obj = objects.ProblemDetails(**error)
|
||||
|
||||
compute_resource = {
|
||||
"vim_connection_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resource_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"vim_level_resource_type": "OS::Nova::Server"}
|
||||
compute_resource_obj = objects.ResourceHandle(**compute_resource)
|
||||
affected_vnfcs = {
|
||||
"id": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"vdu_id": "VDU1",
|
||||
"change_type": "ADDED",
|
||||
"compute_resource": compute_resource_obj,
|
||||
"affected_vnfc_cp_ids": [],
|
||||
"added_storage_resource_ids": [],
|
||||
"removed_storage_sesource_ids": []
|
||||
}
|
||||
affected_vnfcs_obj = objects.AffectedVnfc(**affected_vnfcs)
|
||||
|
||||
network_resource = {
|
||||
"vim_connection_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resource_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"vim_level_resource_type": "COMPUTE"
|
||||
}
|
||||
network_resource_obj = \
|
||||
objects.ResourceHandle(**network_resource)
|
||||
affected_virtual_links = {
|
||||
"id": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"vnf_virtual_link_desc_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"change_type": "ADDED",
|
||||
"network_resource": network_resource_obj,
|
||||
}
|
||||
affected_virtual_links_obj = \
|
||||
objects.AffectedVirtualLink(**affected_virtual_links)
|
||||
|
||||
storage_resource = {
|
||||
"vim_connection_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resource_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"vim_level_resource_type": "COMPUTE"}
|
||||
storage_resource_obj = \
|
||||
objects.ResourceHandle(**storage_resource)
|
||||
affected_virtual_storages = {
|
||||
"id": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"virtual_storage_desc_id":
|
||||
"f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"change_type": "ADDED",
|
||||
"storage_resource": storage_resource_obj,
|
||||
}
|
||||
affected_virtual_storages_obj = \
|
||||
objects.AffectedVirtualStorage(**affected_virtual_storages)
|
||||
|
||||
resource_changes = {
|
||||
"affected_vnfcs": [affected_vnfcs_obj],
|
||||
"affected_virtual_links": [affected_virtual_links_obj],
|
||||
"affected_virtual_storages": [affected_virtual_storages_obj]
|
||||
}
|
||||
resource_changes_obj = objects.ResourceChanges(**resource_changes)
|
||||
|
||||
changed_info = {
|
||||
"vnf_instance_name": "fake_name",
|
||||
"vnf_instance_description":
|
||||
"fake_vnf_instance_description",
|
||||
"metadata": {},
|
||||
"vnfd_id": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"vnf_provider": "fake_vnf_provider",
|
||||
"vnf_product_name": "fake_vnf_product_name",
|
||||
"vnf_software_version": "fake_vnf_software_version",
|
||||
"vnfd_version": "fake_vnfd_version"
|
||||
}
|
||||
changed_info_obj = objects.VnfInfoModifications(**changed_info)
|
||||
|
||||
vnf_lcm_op_occs = {
|
||||
'id': constants.UUID,
|
||||
'operation_state': 'COMPLETED',
|
||||
'state_entered_time': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.UTC),
|
||||
'start_time': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.UTC),
|
||||
'vnf_instance_id': constants.UUID,
|
||||
'operation': 'MODIFY_INFO',
|
||||
'is_automatic_invocation': False,
|
||||
'operation_params': '{"is_reverse": False, "is_auto": False}',
|
||||
'is_cancel_pending': False,
|
||||
'error': error_obj,
|
||||
'resource_changes': resource_changes_obj,
|
||||
'changed_info': changed_info_obj
|
||||
}
|
||||
|
||||
return vnf_lcm_op_occs
|
||||
|
||||
|
||||
def return_vnf_lcm_opoccs_obj():
|
||||
vnf_lcm_op_occs = fake_vnf_lcm_op_occs()
|
||||
obj = objects.VnfLcmOpOcc(**vnf_lcm_op_occs)
|
||||
|
||||
return obj
|
||||
|
|
|
@ -14,11 +14,15 @@
|
|||
# under the License.
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
import codecs
|
||||
import os
|
||||
|
||||
import ddt
|
||||
import json
|
||||
from oslo_serialization import jsonutils
|
||||
from six.moves import http_client
|
||||
import urllib
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
from tacker.api.vnflcm.v1 import controller
|
||||
|
@ -27,6 +31,7 @@ from tacker.conductor.conductorrpc.vnf_lcm_rpc import VNFLcmRPCAPI
|
|||
from tacker import context
|
||||
import tacker.db.vnfm.vnfm_db
|
||||
from tacker.extensions import nfvo
|
||||
from tacker.extensions import vnfm
|
||||
from tacker.manager import TackerManager
|
||||
from tacker import objects
|
||||
from tacker.objects import fields
|
||||
|
@ -40,6 +45,13 @@ from tacker.tests import uuidsentinel
|
|||
from tacker.vnfm import vim_client
|
||||
|
||||
|
||||
def _get_template(name):
|
||||
filename = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||
'../../etc/samples/' + str(name)))
|
||||
f = codecs.open(filename, encoding='utf-8', errors='strict')
|
||||
return f.read()
|
||||
|
||||
|
||||
class FakeVNFMPlugin(mock.Mock):
|
||||
|
||||
def __init__(self):
|
||||
|
@ -59,6 +71,100 @@ class FakeVNFMPlugin(mock.Mock):
|
|||
self.cp32_id = '3d1bd2a2-bf0e-44d1-87af-a2c6b2cad3ed'
|
||||
self.cp32_update_id = '064c0d99-5a61-4711-9597-2a44dc5da14b'
|
||||
|
||||
def get_vnfd(self, *args, **kwargs):
|
||||
if 'VNF1' in args:
|
||||
return {'id': self.vnf1_vnfd_id,
|
||||
'name': 'VNF1',
|
||||
'attributes': {'vnfd': _get_template(
|
||||
'test-nsd-vnfd1.yaml')}}
|
||||
elif 'VNF2' in args:
|
||||
return {'id': self.vnf3_vnfd_id,
|
||||
'name': 'VNF2',
|
||||
'attributes': {'vnfd': _get_template(
|
||||
'test-nsd-vnfd2.yaml')}}
|
||||
|
||||
def get_vnfds(self, *args, **kwargs):
|
||||
if {'name': ['VNF1']} in args:
|
||||
return [{'id': self.vnf1_vnfd_id}]
|
||||
elif {'name': ['VNF3']} in args:
|
||||
return [{'id': self.vnf3_vnfd_id}]
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_vnfs(self, *args, **kwargs):
|
||||
if {'vnfd_id': [self.vnf1_vnfd_id]} in args:
|
||||
return [{'id': self.vnf1_vnf_id}]
|
||||
elif {'vnfd_id': [self.vnf3_vnfd_id]} in args:
|
||||
return [{'id': self.vnf3_vnf_id}]
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_vnf(self, *args, **kwargs):
|
||||
if self.vnf1_vnf_id in args:
|
||||
return self.get_dummy_vnf_error()
|
||||
elif self.vnf3_vnf_id in args:
|
||||
return self.get_dummy_vnf_not_error()
|
||||
else:
|
||||
return self.get_dummy_vnf_active()
|
||||
|
||||
def get_vnf_resources(self, *args, **kwargs):
|
||||
if self.vnf1_vnf_id in args:
|
||||
return self.get_dummy_vnf1_details()
|
||||
elif self.vnf1_update_vnf_id in args:
|
||||
return self.get_dummy_vnf1_update_details()
|
||||
elif self.vnf3_vnf_id in args:
|
||||
return self.get_dummy_vnf3_details()
|
||||
elif self.vnf3_update_vnf_id in args:
|
||||
return self.get_dummy_vnf3_update_details()
|
||||
|
||||
def get_dummy_vnf1_details(self):
|
||||
return [{'name': 'CP11', 'id': self.cp11_id},
|
||||
{'name': 'CP12', 'id': self.cp12_id}]
|
||||
|
||||
def get_dummy_vnf1_update_details(self):
|
||||
return [{'name': 'CP11', 'id': self.cp11_update_id},
|
||||
{'name': 'CP12', 'id': self.cp12_update_id}]
|
||||
|
||||
def get_dummy_vnf3_details(self):
|
||||
return [{'name': 'CP32', 'id': self.cp32_id}]
|
||||
|
||||
def get_dummy_vnf3_update_details(self):
|
||||
return [{'name': 'CP32', 'id': self.cp32_update_id}]
|
||||
|
||||
def get_dummy_vnf_active(self):
|
||||
return {'tenant_id': uuidsentinel.tenant_id,
|
||||
'name': "fake_name",
|
||||
'vnfd_id': uuidsentinel.vnfd_id,
|
||||
'vnf_instance_id': uuidsentinel.instance_id,
|
||||
'mgmt_ip_address': "fake_mgmt_ip_address",
|
||||
'status': 'ACTIVE',
|
||||
'description': 'fake_description',
|
||||
'placement_attr': 'fake_placement_attr',
|
||||
'vim_id': 'uuidsentinel.vim_id',
|
||||
'error_reason': 'fake_error_reason',
|
||||
'attributes': {
|
||||
"scale_group": '{"scaleGroupDict":' +
|
||||
'{"SP1": {"maxLevel" : 3}}}'}}
|
||||
|
||||
def get_dummy_vnf_error(self):
|
||||
return {'tenant_id': uuidsentinel.tenant_id,
|
||||
'name': "fake_name",
|
||||
'vnfd_id': uuidsentinel.vnfd_id,
|
||||
'vnf_instance_id': uuidsentinel.instance_id,
|
||||
'mgmt_ip_address': "fake_mgmt_ip_address",
|
||||
'status': 'ERROR',
|
||||
'description': 'fake_description',
|
||||
'placement_attr': 'fake_placement_attr',
|
||||
'vim_id': 'uuidsentinel.vim_id',
|
||||
'error_reason': 'fake_error_reason',
|
||||
'attributes': {
|
||||
"scale_group": '{"scaleGroupDict":' +
|
||||
'{"SP1": {"maxLevel" : 3}}}'}}
|
||||
|
||||
def get_dummy_vnf_not_error(self):
|
||||
msg = _('VNF %(vnf_id)s could not be found')
|
||||
raise vnfm.VNFNotFound(explanation=msg)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestController(base.TestCase):
|
||||
|
@ -104,6 +210,27 @@ class TestController(base.TestCase):
|
|||
|
||||
return vnf_dict
|
||||
|
||||
def _make_problem_detail(
|
||||
self,
|
||||
detail,
|
||||
status,
|
||||
title=None,
|
||||
type=None,
|
||||
instance=None):
|
||||
res = webob.Response(content_type='application/problem+json')
|
||||
problemDetails = {}
|
||||
if type:
|
||||
problemDetails['type'] = type
|
||||
if title:
|
||||
problemDetails['title'] = title
|
||||
problemDetails['detail'] = detail
|
||||
problemDetails['status'] = status
|
||||
if instance:
|
||||
problemDetails['instance'] = instance
|
||||
res.text = json.dumps(problemDetails)
|
||||
res.status_int = status
|
||||
return res
|
||||
|
||||
@mock.patch.object(objects.VnfInstance, 'save')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
|
||||
|
@ -1631,3 +1758,30 @@ class TestController(base.TestCase):
|
|||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
self.assertRaises(exceptions.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||
def test_show_lcm_op_occs(self, mock_get_by_id,
|
||||
mock_get_service_plugins):
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnf_lcm_op_occs/%s' % constants.UUID)
|
||||
mock_get_by_id.return_value = fakes.return_vnf_lcm_opoccs_obj()
|
||||
expected_result = fakes.VNFLCMOPOCC_RESPONSE
|
||||
res_dict = self.controller.show_lcm_op_occs(req, constants.UUID)
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||
def test_show_lcm_op_occs_not_found(self, mock_get_by_id,
|
||||
mock_get_service_plugins):
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnfpkgm/v1/vnf_packages/%s' % constants.UUID)
|
||||
mock_get_by_id.side_effect = exceptions.NotFound()
|
||||
|
||||
req.headers['Content-Type'] = 'application/json'
|
||||
req.method = 'GET'
|
||||
resp = req.get_response(self.app)
|
||||
|
||||
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||
|
|
Loading…
Reference in New Issue