Support LCM notifications for VNF based on ETSI
Supported for Flow of sending notifications as defined in ETSI SOL003. Notify LCM status to the cannback URL registered in subscription Support for transmission processing from each LCM 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: Idff7a98490ee87bb034d346cfda943bf03620b57
This commit is contained in:
parent
5baeeefedf
commit
f8f58e8cec
@ -14,6 +14,149 @@ vnf_instance_id:
|
||||
type: string
|
||||
|
||||
# variables in body
|
||||
added_storage_resource_ids:
|
||||
description: |
|
||||
References to VirtualStorage resources that
|
||||
have been added.
|
||||
Each value refers to a
|
||||
VirtualStorageResourceInfo item in the
|
||||
VnfInstance that was added to the VNFC.
|
||||
It shall be provided if at least one storage
|
||||
resource was added to the VNFC.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
affected_virtual_links:
|
||||
description: |
|
||||
Information about VL instances that were affected during
|
||||
the lifecycle operation.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
affected_virtual_links_change_type:
|
||||
description: |
|
||||
Signals the type of change.
|
||||
Permitted values:
|
||||
|
||||
ADDED
|
||||
|
||||
REMOVED
|
||||
|
||||
MODIFIED
|
||||
|
||||
TEMPORARY
|
||||
|
||||
LINK_PORT_ADDED
|
||||
|
||||
LINK_PORT_REMOVED
|
||||
|
||||
For a temporary resource, an
|
||||
AffectedVirtualLink structure exists as long as
|
||||
the temporary resource exists.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
affected_virtual_links_id:
|
||||
description: |
|
||||
Identifier of the virtual link instance, identifying
|
||||
the applicable "vnfVirtualLinkResourceInfo"
|
||||
entry in the "VnfInstance" data type.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
affected_virtual_storages:
|
||||
description: |
|
||||
Information about virtualised storage instances that were
|
||||
affected during the lifecycle operation.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
affected_virtual_storages_change_type:
|
||||
description: |
|
||||
Signals the type of change.
|
||||
Permitted values:
|
||||
|
||||
ADDED
|
||||
|
||||
REMOVED
|
||||
|
||||
MODIFIED
|
||||
|
||||
TEMPORARY
|
||||
|
||||
For a temporary resource, an
|
||||
AffectedVirtualStorage structure exists as long
|
||||
as the temporary resource exists.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
affected_virtual_storages_id:
|
||||
description: |
|
||||
Identifier of the storage instance, identifying the
|
||||
applicable "virtualStorageResourceInfo" entry
|
||||
in the "VnfInstance" data type.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
affected_virtual_storages_virtual_storage_desc_id:
|
||||
description: |
|
||||
Identifier of the related VirtualStorage
|
||||
descriptor in the VNFD.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
affected_vnfc_cp_ids:
|
||||
description: |
|
||||
Identifiers of CP(s) of the VNFC instance that
|
||||
were affected by the change.
|
||||
Shall be present for those affected CPs of the
|
||||
VNFC instance that are associated to an
|
||||
external CP of the VNF instance.
|
||||
May be present for further affected CPs of the
|
||||
VNFC instance.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
affected_vnfcs:
|
||||
description: |
|
||||
Information about VNFC instances that were affected
|
||||
during the lifecycle operation.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
affected_vnfcs_change_type:
|
||||
description: |
|
||||
Signals the type of change
|
||||
Permitted values:
|
||||
|
||||
ADDED
|
||||
|
||||
REMOVED
|
||||
|
||||
MODIFIED
|
||||
|
||||
TEMPORARY
|
||||
|
||||
For a temporary resource, an AffectedVnfc
|
||||
structure exists as long as the temporary
|
||||
resource exists.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
affected_vnfcs_id:
|
||||
description: |
|
||||
Identifier of the Vnfc instance, identifying the
|
||||
applicable "vnfcResourceInfo" entry in the
|
||||
"VnfInstance" data type.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
affected_vnfcs_vdu_id:
|
||||
description: |
|
||||
Identifier of the related VDU in the VNFD.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
authentication:
|
||||
description: |
|
||||
Authentication parameters to configure the use of
|
||||
@ -118,6 +261,83 @@ cause:
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info:
|
||||
description: |
|
||||
Information about the changed VNF instance information,
|
||||
including VNF configurable properties, if applicable.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
changed_info_metadata:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"metadata" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vim_connection_info:
|
||||
description: |
|
||||
If present, this attribute signals modifications of certain
|
||||
entries in the "vimConnectionInfo" attribute array in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
changed_info_vnf_instance_description:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfInstanceDescription" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vnf_instance_name:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfInstanceName" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vnf_pkg_id:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfPkgId" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vnf_product_name:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfProductName" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vnf_provider:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfProvider" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vnf_sotware_version:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfSoftwareVersion" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vnfd_id:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfdId" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
changed_info_vnfd_version:
|
||||
description: |
|
||||
If present, this attribute signals modifications of the
|
||||
"vnfdVersion" attribute in "VnfInstance".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
cp_config:
|
||||
description: |
|
||||
List of instance data that need to be configured on the CP instances
|
||||
@ -147,6 +367,41 @@ cpd_id:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
error:
|
||||
description: |
|
||||
If "operationState" is "FAILED_TEMP" or "FAILED" or
|
||||
"operationState" is "PROCESSING" or "ROLLING_BACK"
|
||||
and previous value of "operationState" was
|
||||
"FAILED_TEMP", this attribute shall be present and
|
||||
contain error information, unless it has been requested to
|
||||
be excluded via an attribute selector.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
error_detail:
|
||||
description: |
|
||||
A human-readable explanation specific to this occurrence
|
||||
of the problem.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
error_status:
|
||||
description: |
|
||||
The HTTP status code for this occurrence of the problem.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
error_title:
|
||||
description: |
|
||||
A URI reference according to IETF RFC 3986 that
|
||||
identifies the problem type. It is encouraged that the URI
|
||||
provides human-readable documentation for the problem
|
||||
(e.g. using HTML) when dereferenced. When this
|
||||
member is not present, its value is assumed to be
|
||||
"about:blank".
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
ext_cp_info:
|
||||
description: |
|
||||
Information about the external CPs exposed by the VNF instance.
|
||||
@ -449,6 +704,16 @@ ip_over_ethernet_cp_info:
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
is_automatic_invocation:
|
||||
description: |
|
||||
Set to true if this VNF LCM operation occurrence has
|
||||
been triggered by an automated procedure inside the
|
||||
VNFM (i.e. ScaleVnf triggered by autoscale,
|
||||
or HealVnf triggered by auto-heal).
|
||||
Set to false otherwise.
|
||||
in: body
|
||||
required: true
|
||||
type: boolean
|
||||
is_dynamic:
|
||||
description: |
|
||||
Indicates whether this set of addresses was assigned dynamically (true)
|
||||
@ -495,6 +760,86 @@ mac_address_cp_info:
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
notification_id:
|
||||
description: |
|
||||
Identifier of this notification. If a notification is sent
|
||||
multiple times due to multiple subscriptions, the "id"
|
||||
attribute of all these notifications shall have the same
|
||||
value.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_operation:
|
||||
description: |
|
||||
The lifecycle management operation.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_operation_state:
|
||||
description: |
|
||||
The state of the VNF LCM operation occurrence.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_status:
|
||||
description: |
|
||||
Indicates whether this notification reports about the start
|
||||
of a lifecycle operation or the result of a lifecycle
|
||||
operation.
|
||||
Permitted values:
|
||||
|
||||
START: Informs about the start of the VNF LCM
|
||||
operation occurrence.
|
||||
|
||||
RESULT: Informs about the final or intermediate
|
||||
result of the VNF LCM operation occurrence.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_subscription_id:
|
||||
description: |
|
||||
Identifier of the subscription that this notification relates to.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_time_tamp:
|
||||
description: |
|
||||
Date-time of the generation of the notification.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_type:
|
||||
description: |
|
||||
Discriminator for the different notification types.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_vnf_instance_id:
|
||||
description: |
|
||||
The identifier of the VNF instance affected.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
notification_vnf_lcm_op_occ_id:
|
||||
description: |
|
||||
The identifier of the VNF lifecycle management
|
||||
operation occurrence associated to the notification.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
removed_storage_resource_ids:
|
||||
description: |
|
||||
References to VirtualStorage resources that
|
||||
have been removed.
|
||||
The value contains the identifier of a
|
||||
VirtualStorageResourceInfo item that has been
|
||||
removed from the VNFC, and might no longer
|
||||
exist in the VnfInstance.
|
||||
It shall be provided if at least one storage
|
||||
resource was removed from the VNFC.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
resource_handle:
|
||||
description: |
|
||||
Reference to the resource realizing this VL.
|
||||
@ -594,6 +939,30 @@ vim_connection_info_access_info:
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
vim_connection_info_access_info_password:
|
||||
description: |
|
||||
The password to use for access.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
vim_connection_info_access_info_region:
|
||||
description: |
|
||||
The OpenStack region to use for the VIM connection.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
vim_connection_info_access_info_tenant:
|
||||
description: |
|
||||
The OpenStack tenant to use for the VIM connection.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
vim_connection_info_access_info_username:
|
||||
description: |
|
||||
The username to use for access.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
vim_connection_info_id:
|
||||
description: |
|
||||
The identifier of the VIM Connection. This identifier is managed by
|
||||
|
100
api-ref/source/v1/samples/vnflcm/notification-request.json
Normal file
100
api-ref/source/v1/samples/vnflcm/notification-request.json
Normal file
@ -0,0 +1,100 @@
|
||||
{
|
||||
"id": "fb864bd0-25f3-4180-b591-2910086c0013",
|
||||
"notificationType": "VnfLcmOperationOccurrenceNotification",
|
||||
"subscriptionId": "c25ae285-e245-4898-9df7-0527841efdc4",
|
||||
"timeStamp": "2020-08-02T06:50:50.883373",
|
||||
"notificationStatus": "RESULT",
|
||||
"operationState": "COMPLETED",
|
||||
"vnfInstanceId": "0b7b95a9-21d5-4ac4-80c8-9ae9f7323787",
|
||||
"operation": "INSTANTIATE",
|
||||
"isAutomaticInvocation": false,
|
||||
"vnfLcmOpOccId": "1266b5b4-84d3-4c3a-acbf-aa515fada6b0",
|
||||
"affectedVnfcs": [
|
||||
{
|
||||
"id": "36e24439-829c-4803-a413-385cd658d544",
|
||||
"vduId": "VDU1",
|
||||
"changeType": "ADDED",
|
||||
"computeResource": {
|
||||
"vimConnectionId": null,
|
||||
"resourceId": "e0510ba9-3a53-4fcf-9dcc-58dea5c048b0",
|
||||
"vimLevelResourceType": "OS::Nova::Server"
|
||||
},
|
||||
"metadata": {
|
||||
"stackId": "f0faec36-721a-4245-8f50-4a19edec757a"
|
||||
},
|
||||
"affectedVnfcCpIds": [
|
||||
"VDU1_CP0",
|
||||
"VDU1_CP1"
|
||||
],
|
||||
"addedStorageResourceIds": []
|
||||
},
|
||||
{
|
||||
"id": "51f930d7-f8b9-4a7f-8b02-18c47ec31340",
|
||||
"vduId": "VDU2",
|
||||
"changeType": "ADDED",
|
||||
"computeResource": {
|
||||
"vimConnectionId": null,
|
||||
"resourceId": "",
|
||||
"vimLevelResourceType": null
|
||||
},
|
||||
"metadata": {},
|
||||
"affectedVnfcCpIds": [
|
||||
"VDU2_CP0",
|
||||
"VDU2_CP1"
|
||||
],
|
||||
"addedStorageResourceIds": []
|
||||
},
|
||||
{
|
||||
"id": "52e4253a-7c9e-4161-bb74-0642d5072271",
|
||||
"vduId": "VDU3",
|
||||
"changeType": "ADDED",
|
||||
"computeResource": {
|
||||
"vimConnectionId": null,
|
||||
"resourceId": "",
|
||||
"vimLevelResourceType": null
|
||||
},
|
||||
"metadata": {},
|
||||
"affectedVnfcCpIds": [
|
||||
"VDU3_CP0",
|
||||
"VDU3_CP1"
|
||||
],
|
||||
"addedStorageResourceIds": []
|
||||
}
|
||||
],
|
||||
"affectedVirtualLinks": [
|
||||
{
|
||||
"id": "9836f7f2-5af4-4df5-a89f-933479448ef7",
|
||||
"vnfVirtualLinkDescId": "internalNW1",
|
||||
"changeType": "ADDED",
|
||||
"networkResource": {
|
||||
"vimConnectionId": null,
|
||||
"resourceId": "400692e5-b2db-478e-acb1-b77a92635ec6",
|
||||
"vimLevelResourceType": "OS::Neutron::Net"
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"id": "8d6c4a5f-cbd1-4fd8-b240-867ed1d48385",
|
||||
"vnfVirtualLinkDescId": "internalNW2",
|
||||
"changeType": "ADDED",
|
||||
"networkResource": {
|
||||
"vimConnectionId": null,
|
||||
"resourceId": "",
|
||||
"vimLevelResourceType": null
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
],
|
||||
"affectedVirtualStorages": [],
|
||||
"_links": {
|
||||
"vnfInstance": {
|
||||
"href": "http://sample.com/vnflcm/v1/vnf_instances/0b7b95a9-21d5-4ac4-80c8-9ae9f7323787"
|
||||
},
|
||||
"subscription": {
|
||||
"href": "http://sample.com/vnflcm/v1/subscriptions/c25ae285-e245-4898-9df7-0527841efdc4"
|
||||
},
|
||||
"vnfLcmOpOcc": {
|
||||
"href": "http://sample.com/vnflcmv1/vnf_lcm_op_occs/1266b5b4-84d3-4c3a-acbf-aa515fada6b0"
|
||||
}
|
||||
}
|
||||
}
|
@ -758,3 +758,100 @@ Response Example
|
||||
|
||||
.. literalinclude:: samples/vnflcm/list-subscription-response.json
|
||||
:language: javascript
|
||||
|
||||
Notification
|
||||
=================
|
||||
|
||||
.. rest_method:: POST URI is provided by the client when creating the subscription.
|
||||
|
||||
The POST method delivers a notification from the API producer to an API consumer. The API consumer shall have
|
||||
previously created an "Individual subscription" resource with a matching filter.
|
||||
|
||||
Response Codes
|
||||
--------------
|
||||
|
||||
.. rest_status_code:: success status.yaml
|
||||
|
||||
- 204
|
||||
|
||||
.. rest_status_code:: error status.yaml
|
||||
|
||||
- 401
|
||||
- 403
|
||||
|
||||
Request Parameters
|
||||
------------------
|
||||
|
||||
.. rest_parameters:: parameters_vnflcm.yaml
|
||||
|
||||
|
||||
- id: notification_id
|
||||
- notificationType: notification_type
|
||||
- subscriptionId: notification_subscription_id
|
||||
- timeStamp: notification_time_tamp
|
||||
- notificationStatus: notification_status
|
||||
- operationState: notification_operation_state
|
||||
- vnfInstanceId: notification_vnf_instance_id
|
||||
- operation: notification_operation
|
||||
- isAutomaticInvocation: is_automatic_invocation
|
||||
- vnfLcmOpOccId: notification_vnf_lcm_op_occ_id
|
||||
- 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
|
||||
- virtualLinkDescId: 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
|
||||
- error: error
|
||||
- title: error_title
|
||||
- status: error_status
|
||||
- detail: error_detail
|
||||
- _links: vnf_instance_links
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: samples/vnflcm/notification-request.json
|
||||
:language: javascript
|
||||
|
@ -158,10 +158,7 @@ class ViewBuilder(base.BaseViewBuilder):
|
||||
paging):
|
||||
# filter processing
|
||||
lcmsubscription = []
|
||||
|
||||
# last_flg is True if nextpage_opaque_marker is set
|
||||
last_flg = False
|
||||
|
||||
start_num = CONF.vnf_lcm.subscription_num * (paging - 1)
|
||||
# Subscription_data counter for comparing
|
||||
# subscription_data and start_num
|
||||
|
@ -15,18 +15,21 @@
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
import ast
|
||||
import functools
|
||||
import json
|
||||
import re
|
||||
import traceback
|
||||
|
||||
import six
|
||||
from six.moves import http_client
|
||||
from six.moves.urllib import parse
|
||||
import webob
|
||||
|
||||
from urllib import parse
|
||||
|
||||
from tacker._i18n import _
|
||||
from tacker.api.schemas import vnf_lcm
|
||||
@ -37,10 +40,12 @@ from tacker.common import utils
|
||||
from tacker.conductor.conductorrpc import vnf_lcm_rpc
|
||||
import tacker.conf
|
||||
from tacker.extensions import nfvo
|
||||
from tacker.extensions import vnfm
|
||||
from tacker import manager
|
||||
from tacker import objects
|
||||
from tacker.objects import fields
|
||||
from tacker.objects import vnf_lcm_subscriptions as subscription_obj
|
||||
from tacker.plugins.common import constants
|
||||
from tacker.policies import vnf_lcm as vnf_lcm_policies
|
||||
from tacker.vnfm import vim_client
|
||||
from tacker import wsgi
|
||||
@ -63,7 +68,7 @@ def check_vnf_state(action, instantiation_state=None, task_state=(None,)):
|
||||
task_state = set(task_state)
|
||||
|
||||
def outer(f):
|
||||
@six.wraps(f)
|
||||
@functools.wraps(f)
|
||||
def inner(self, context, vnf_instance, *args, **kw):
|
||||
if instantiation_state is not None and \
|
||||
vnf_instance.instantiation_state not in \
|
||||
@ -85,6 +90,31 @@ def check_vnf_state(action, instantiation_state=None, task_state=(None,)):
|
||||
return outer
|
||||
|
||||
|
||||
def check_vnf_status(action, status=None):
|
||||
"""Decorator to check vnf status are valid for particular action.
|
||||
|
||||
If the vnf is in the wrong state, it will raise conflict exception.
|
||||
"""
|
||||
|
||||
if status is not None and not isinstance(status, set):
|
||||
status = set(status)
|
||||
|
||||
def outer(f):
|
||||
@functools.wraps(f)
|
||||
def inner(self, context, vnf_instance, vnf, *args, **kw):
|
||||
if status is not None and \
|
||||
vnf['status'] not in \
|
||||
status:
|
||||
raise exceptions.VnfConflictState(
|
||||
attr='status',
|
||||
uuid=vnf['id'],
|
||||
state=vnf['status'],
|
||||
action=action)
|
||||
return f(self, context, vnf_instance, vnf, *args, **kw)
|
||||
return inner
|
||||
return outer
|
||||
|
||||
|
||||
class VnfLcmController(wsgi.Controller):
|
||||
|
||||
notification_type_list = ['VnfLcmOperationOccurrenceNotification',
|
||||
@ -117,6 +147,9 @@ class VnfLcmController(wsgi.Controller):
|
||||
def _get_vnf_instance_href(self, vnf_instance):
|
||||
return '/vnflcm/v1/vnf_instances/%s' % vnf_instance.id
|
||||
|
||||
def _get_vnf_lcm_op_occs_href(self, vnf_lcm_op_occs_id):
|
||||
return '/vnflcm/v1/vnf_lcm_op_occs/%s' % vnf_lcm_op_occs_id
|
||||
|
||||
def _get_vnf_instance(self, context, id):
|
||||
# check if id is of type uuid format
|
||||
if not uuidutils.is_uuid_like(id):
|
||||
@ -131,6 +164,24 @@ class VnfLcmController(wsgi.Controller):
|
||||
|
||||
return vnf_instance
|
||||
|
||||
def _get_vnf(self, context, id):
|
||||
# check if id is of type uuid format
|
||||
if not uuidutils.is_uuid_like(id):
|
||||
msg = _("Can not find requested vnf: %s") % id
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
try:
|
||||
vnf = self._vnfm_plugin.get_vnf(context, id)
|
||||
except vnfm.VNFNotFound:
|
||||
msg = _("Can not find requested vnf: %s") % id
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
except Exception as exc:
|
||||
msg = _("Encountered error while fetching vnf: %s") % id
|
||||
LOG.debug("{}: {}".format(msg, six.text_type(exc)))
|
||||
raise webob.exc.HTTPInternalServerError(explanation=six.
|
||||
text_type(exc))
|
||||
return vnf
|
||||
|
||||
def _validate_flavour_and_inst_level(self, context, req_body,
|
||||
vnf_instance):
|
||||
inst_levels = {}
|
||||
@ -197,6 +248,65 @@ class VnfLcmController(wsgi.Controller):
|
||||
% vim_id
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
def _notification_process(self, context, vnf_instance,
|
||||
lcm_operation, request, is_auto=False):
|
||||
vnf_lcm_op_occs_id = uuidutils.generate_uuid()
|
||||
error_point = 0
|
||||
if lcm_operation == fields.LcmOccsOperationType.HEAL:
|
||||
request_dict = {
|
||||
'vnfc_instance_id': request.vnfc_instance_id,
|
||||
'cause': request.cause
|
||||
}
|
||||
operation_params = str(request_dict)
|
||||
else:
|
||||
# lcm is instantiation by default
|
||||
operation_params = str(request.additional_params)
|
||||
try:
|
||||
# call create lcm op occs here
|
||||
LOG.debug('Create LCM OP OCCS')
|
||||
vnf_lcm_op_occs = objects.VnfLcmOpOcc(
|
||||
context=context,
|
||||
id=vnf_lcm_op_occs_id,
|
||||
operation_state=fields.LcmOccsOperationState.STARTING,
|
||||
start_time=timeutils.utcnow(),
|
||||
state_entered_time=timeutils.utcnow(),
|
||||
vnf_instance_id=vnf_instance.id,
|
||||
is_cancel_pending=is_auto,
|
||||
operation=lcm_operation,
|
||||
is_automatic_invocation=is_auto,
|
||||
operation_params=operation_params,
|
||||
error_point=error_point)
|
||||
vnf_lcm_op_occs.create()
|
||||
except Exception:
|
||||
msg = _("Failed to create LCM occurrence")
|
||||
raise webob.exc.HTTPInternalServerError(explanation=msg)
|
||||
|
||||
vnf_lcm_url = self._get_vnf_lcm_op_occs_href(vnf_lcm_op_occs_id)
|
||||
notification = {
|
||||
'notificationType':
|
||||
fields.LcmOccsNotificationType.VNF_OP_OCC_NOTIFICATION,
|
||||
'notificationStatus': fields.LcmOccsNotificationStatus.START,
|
||||
'operationState': fields.LcmOccsOperationState.STARTING,
|
||||
'vnfInstanceId': vnf_instance.id,
|
||||
'operation': lcm_operation,
|
||||
'isAutomaticInvocation': is_auto,
|
||||
'vnfLcmOpOccId': vnf_lcm_op_occs_id,
|
||||
'_links': {
|
||||
'vnfInstance': {
|
||||
'href': self._get_vnf_instance_href(vnf_instance)},
|
||||
'vnfLcmOpOcc': {
|
||||
'href': vnf_lcm_url}}}
|
||||
|
||||
# call send notification
|
||||
try:
|
||||
self.rpc_api.send_notification(context, notification)
|
||||
except Exception as ex:
|
||||
LOG.error(
|
||||
"Encoutered problem sending notification {}".format(
|
||||
encodeutils.exception_to_unicode(ex)))
|
||||
|
||||
return vnf_lcm_op_occs_id
|
||||
|
||||
@wsgi.response(http_client.CREATED)
|
||||
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN))
|
||||
@validation.schema(vnf_lcm.create)
|
||||
@ -247,6 +357,18 @@ class VnfLcmController(wsgi.Controller):
|
||||
|
||||
# add default vim to vim_connection_info
|
||||
setattr(vnf_instance, 'vim_connection_info', [vim_con_info])
|
||||
|
||||
# create notification data
|
||||
notification = {
|
||||
'notificationType':
|
||||
fields.LcmOccsNotificationType.VNF_ID_CREATION_NOTIFICATION,
|
||||
'vnfInstanceId': vnf_instance.id,
|
||||
'links': {
|
||||
'vnfInstance': {
|
||||
'href': self._get_vnf_instance_href(vnf_instance)}}}
|
||||
|
||||
# call send nootification
|
||||
self.rpc_api.send_notification(context, notification)
|
||||
vnf_instance.save()
|
||||
|
||||
result = self._view_builder.create(vnf_instance)
|
||||
@ -291,10 +413,21 @@ class VnfLcmController(wsgi.Controller):
|
||||
vnf_instance = self._get_vnf_instance(context, id)
|
||||
self._delete(context, vnf_instance)
|
||||
|
||||
notification = {
|
||||
"notificationType": "VnfIdentifierDeletionNotification",
|
||||
"vnfInstanceId": vnf_instance.id,
|
||||
"links": {
|
||||
"vnfInstance":
|
||||
"href:{apiRoot}/vnflcm/v1/vnf_instances/{vnfInstanceId}"}}
|
||||
# send notification
|
||||
self.rpc_api.send_notification(context, notification)
|
||||
|
||||
@check_vnf_state(action="instantiate",
|
||||
instantiation_state=[fields.VnfInstanceState.NOT_INSTANTIATED],
|
||||
task_state=[None])
|
||||
def _instantiate(self, context, vnf_instance, request_body):
|
||||
@check_vnf_status(action="instantiate",
|
||||
status=[constants.INACTIVE])
|
||||
def _instantiate(self, context, vnf_instance, vnf, request_body):
|
||||
req_body = utils.convert_camelcase_to_snakecase(request_body)
|
||||
|
||||
try:
|
||||
@ -313,8 +446,13 @@ class VnfLcmController(wsgi.Controller):
|
||||
vnf_instance.task_state = fields.VnfInstanceTaskState.INSTANTIATING
|
||||
vnf_instance.save()
|
||||
|
||||
self.rpc_api.instantiate(context, vnf_instance,
|
||||
instantiate_vnf_request)
|
||||
# lcm op process
|
||||
vnf_lcm_op_occs_id = \
|
||||
self._notification_process(context, vnf_instance,
|
||||
fields.LcmOccsOperationType.INSTANTIATE,
|
||||
instantiate_vnf_request)
|
||||
self.rpc_api.instantiate(context, vnf_instance, vnf,
|
||||
instantiate_vnf_request, vnf_lcm_op_occs_id)
|
||||
|
||||
@wsgi.response(http_client.ACCEPTED)
|
||||
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND,
|
||||
@ -324,14 +462,15 @@ class VnfLcmController(wsgi.Controller):
|
||||
context = request.environ['tacker.context']
|
||||
context.can(vnf_lcm_policies.VNFLCM % 'instantiate')
|
||||
|
||||
vnf = self._get_vnf(context, id)
|
||||
vnf_instance = self._get_vnf_instance(context, id)
|
||||
|
||||
self._instantiate(context, vnf_instance, body)
|
||||
self._instantiate(context, vnf_instance, vnf, body)
|
||||
|
||||
@check_vnf_state(action="terminate",
|
||||
instantiation_state=[fields.VnfInstanceState.INSTANTIATED],
|
||||
task_state=[None])
|
||||
def _terminate(self, context, vnf_instance, request_body):
|
||||
def _terminate(self, context, vnf_instance, request_body, vnf):
|
||||
req_body = utils.convert_camelcase_to_snakecase(request_body)
|
||||
terminate_vnf_req = \
|
||||
objects.TerminateVnfRequest.obj_from_primitive(
|
||||
@ -339,7 +478,15 @@ class VnfLcmController(wsgi.Controller):
|
||||
|
||||
vnf_instance.task_state = fields.VnfInstanceTaskState.TERMINATING
|
||||
vnf_instance.save()
|
||||
self.rpc_api.terminate(context, vnf_instance, terminate_vnf_req)
|
||||
|
||||
# lcm op process
|
||||
vnf_lcm_op_occs_id = \
|
||||
self._notification_process(context, vnf_instance,
|
||||
fields.LcmOccsOperationType.TERMINATE,
|
||||
terminate_vnf_req)
|
||||
|
||||
self.rpc_api.terminate(context, vnf_instance, vnf,
|
||||
terminate_vnf_req, vnf_lcm_op_occs_id)
|
||||
|
||||
@wsgi.response(http_client.ACCEPTED)
|
||||
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN,
|
||||
@ -349,13 +496,16 @@ class VnfLcmController(wsgi.Controller):
|
||||
context = request.environ['tacker.context']
|
||||
context.can(vnf_lcm_policies.VNFLCM % 'terminate')
|
||||
|
||||
vnf = self._get_vnf(context, id)
|
||||
vnf_instance = self._get_vnf_instance(context, id)
|
||||
self._terminate(context, vnf_instance, body)
|
||||
self._terminate(context, vnf_instance, body, vnf)
|
||||
|
||||
@check_vnf_state(action="heal",
|
||||
instantiation_state=[fields.VnfInstanceState.INSTANTIATED],
|
||||
task_state=[None])
|
||||
def _heal(self, context, vnf_instance, request_body):
|
||||
@check_vnf_status(action="heal",
|
||||
status=[constants.ACTIVE])
|
||||
def _heal(self, context, vnf_instance, vnf_dict, request_body):
|
||||
req_body = utils.convert_camelcase_to_snakecase(request_body)
|
||||
heal_vnf_request = objects.HealVnfRequest(context=context, **req_body)
|
||||
inst_vnf_info = vnf_instance.instantiated_vnf_info
|
||||
@ -374,7 +524,14 @@ class VnfLcmController(wsgi.Controller):
|
||||
vnf_instance.task_state = fields.VnfInstanceTaskState.HEALING
|
||||
vnf_instance.save()
|
||||
|
||||
self.rpc_api.heal(context, vnf_instance, heal_vnf_request)
|
||||
# call notification process
|
||||
vnf_lcm_op_occs_id = \
|
||||
self._notification_process(context, vnf_instance,
|
||||
fields.LcmOccsOperationType.HEAL,
|
||||
heal_vnf_request)
|
||||
|
||||
self.rpc_api.heal(context, vnf_instance, vnf_dict, heal_vnf_request,
|
||||
vnf_lcm_op_occs_id)
|
||||
|
||||
@wsgi.response(http_client.ACCEPTED)
|
||||
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN,
|
||||
@ -384,8 +541,9 @@ class VnfLcmController(wsgi.Controller):
|
||||
context = request.environ['tacker.context']
|
||||
context.can(vnf_lcm_policies.VNFLCM % 'heal')
|
||||
|
||||
vnf = self._get_vnf(context, id)
|
||||
vnf_instance = self._get_vnf_instance(context, id)
|
||||
self._heal(context, vnf_instance, body)
|
||||
self._heal(context, vnf_instance, vnf, body)
|
||||
|
||||
@wsgi.response(http_client.CREATED)
|
||||
@validation.schema(vnf_lcm.register_subscription)
|
||||
|
@ -232,6 +232,11 @@ class VnfInstanceConflictState(Conflict):
|
||||
"%(action)s while the vnf instance is in this state.")
|
||||
|
||||
|
||||
class VnfConflictState(Conflict):
|
||||
message = _("Vnf %(uuid)s in %(attr)s %(state)s. Cannot "
|
||||
"%(action)s while the vnf is in this state.")
|
||||
|
||||
|
||||
class FlavourNotFound(NotFound):
|
||||
message = _("No flavour with id '%(flavour_id)s'.")
|
||||
|
||||
@ -342,6 +347,10 @@ class LimitExceeded(TackerException):
|
||||
super(LimitExceeded, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class NotificationProcessingError(TackerException):
|
||||
message = _("Notification Processing Failed: %(error)s")
|
||||
|
||||
|
||||
class UserDataUpdateCreateFailed(TackerException):
|
||||
msg_fmt = _("User data for VNF package %(id)s cannot be updated "
|
||||
"or created after %(retries)d retries.")
|
||||
|
@ -12,29 +12,38 @@
|
||||
# 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 datetime
|
||||
import functools
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
|
||||
|
||||
from glance_store import exceptions as store_exceptions
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_service import periodic_task
|
||||
from oslo_service import service
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
from sqlalchemy import exc as sqlexc
|
||||
from sqlalchemy.orm import exc as orm_exc
|
||||
import yaml
|
||||
|
||||
from tacker.common import coordination
|
||||
from tacker.common import csar_utils
|
||||
from tacker.common import exceptions
|
||||
from tacker.common import log
|
||||
from tacker.common import safe_utils
|
||||
from tacker.common import topics
|
||||
from tacker.common import utils
|
||||
@ -50,6 +59,7 @@ from tacker.objects.vnf_package import VnfPackagesList
|
||||
from tacker.plugins.common import constants
|
||||
from tacker import service as tacker_service
|
||||
from tacker import version
|
||||
from tacker.vnflcm import utils as vnflcm_utils
|
||||
from tacker.vnflcm import vnflcm_driver
|
||||
from tacker.vnfm import plugin
|
||||
|
||||
@ -115,7 +125,7 @@ def revert_upload_vnf_package(function):
|
||||
or isinstance(exp, exceptions.VNFPackageURLInvalid)):
|
||||
# Delete the csar file from the glance store.
|
||||
glance_store.delete_csar(context, vnf_package.id,
|
||||
vnf_package.location_glance_store)
|
||||
vnf_package.location_glance_store)
|
||||
|
||||
csar_utils.delete_csar_data(vnf_package.id)
|
||||
|
||||
@ -407,6 +417,22 @@ class Conductor(manager.Manager):
|
||||
|
||||
return file_path_and_data
|
||||
|
||||
@coordination.synchronized('{vnf_package[id]}')
|
||||
def _update_package_usage_state(self, context, vnf_package):
|
||||
"""Update vnf package usage state to IN_USE/NOT_IN_USE
|
||||
|
||||
If vnf package is not used by any of the vnf instances, it's usage
|
||||
state should be set to NOT_IN_USE otherwise it should be set to
|
||||
IN_USE.
|
||||
"""
|
||||
result = vnf_package.is_package_in_use(context)
|
||||
if result:
|
||||
vnf_package.usage_state = fields.PackageUsageStateType.IN_USE
|
||||
else:
|
||||
vnf_package.usage_state = fields.PackageUsageStateType.NOT_IN_USE
|
||||
|
||||
vnf_package.save()
|
||||
|
||||
@periodic_task.periodic_task(spacing=CONF.vnf_package_delete_interval)
|
||||
def _run_cleanup_vnf_packages(self, context):
|
||||
"""Delete orphan extracted csar zip and files from extracted path
|
||||
@ -438,87 +464,399 @@ class Conductor(manager.Manager):
|
||||
{'zip': csar_path, 'folder': csar_zip_temp_path,
|
||||
'uuid': vnf_pack.id})
|
||||
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def instantiate(self, context, vnf_instance, instantiate_vnf):
|
||||
# Check if vnf is already instantiated.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.INSTANTIATED:
|
||||
LOG.error("Vnf instance %(id)s is already in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
return
|
||||
|
||||
self.vnflcm_driver.instantiate_vnf(context, vnf_instance,
|
||||
instantiate_vnf)
|
||||
|
||||
vnf_package_vnfd = objects.VnfPackageVnfd.get_by_id(context,
|
||||
vnf_instance.vnfd_id)
|
||||
vnf_package = objects.VnfPackage.get_by_id(context,
|
||||
vnf_package_vnfd.package_uuid, expected_attrs=['vnfd'])
|
||||
@log.log
|
||||
def _get_vnf_notify(self, context, id):
|
||||
try:
|
||||
self._update_package_usage_state(context, vnf_package)
|
||||
except Exception:
|
||||
LOG.error("Failed to update usage_state of vnf package %s",
|
||||
vnf_package.id)
|
||||
vnf_notif = objects.VnfLcmOpOcc.get_by_id(context, id)
|
||||
except exceptions.VnfInstanceNotFound:
|
||||
error_msg = _("Can not find requested vnf instance: %s") % id
|
||||
raise exceptions.NotificationProcessingError(error=error_msg)
|
||||
except (sqlexc.SQLAlchemyError, Exception):
|
||||
error_msg = _("Can not find requested vnf instance: %s") % id
|
||||
raise exceptions.NotificationProcessingError(error=error_msg)
|
||||
|
||||
@coordination.synchronized('{vnf_package[id]}')
|
||||
def _update_package_usage_state(self, context, vnf_package):
|
||||
"""Update vnf package usage state to IN_USE/NOT_IN_USE
|
||||
return vnf_notif
|
||||
|
||||
If vnf package is not used by any of the vnf instances, it's usage
|
||||
state should be set to NOT_IN_USE otherwise it should be set to
|
||||
IN_USE.
|
||||
"""
|
||||
result = vnf_package.is_package_in_use(context)
|
||||
if result:
|
||||
vnf_package.usage_state = fields.PackageUsageStateType.IN_USE
|
||||
def _send_lcm_op_occ_notification(
|
||||
self,
|
||||
context,
|
||||
vnf_lcm_op_occs_id,
|
||||
old_vnf_instance,
|
||||
vnf_instance,
|
||||
request_obj,
|
||||
**kwargs):
|
||||
|
||||
operation = kwargs.get('operation',
|
||||
fields.LcmOccsOperationType.INSTANTIATE)
|
||||
operation_state = kwargs.get('operation_state',
|
||||
fields.LcmOccsOperationState.PROCESSING)
|
||||
evacuate_end_list = kwargs.get('evacuate_end_list', None)
|
||||
is_automatic_invocation = \
|
||||
kwargs.get('is_automatic_invocation', False)
|
||||
error = kwargs.get('error', None)
|
||||
|
||||
if old_vnf_instance:
|
||||
vnf_instance_id = old_vnf_instance.id
|
||||
else:
|
||||
vnf_package.usage_state = fields.PackageUsageStateType.NOT_IN_USE
|
||||
vnf_instance_id = vnf_instance.id
|
||||
|
||||
vnf_package.save()
|
||||
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def terminate(self, context, vnf_instance, terminate_vnf_req):
|
||||
# Check if vnf is in instantiated state.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
LOG.error("Terminate action cannot be performed on vnf %(id)s "
|
||||
"which is in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
return
|
||||
|
||||
self.vnflcm_driver.terminate_vnf(context, vnf_instance,
|
||||
terminate_vnf_req)
|
||||
|
||||
vnf_package_vnfd = objects.VnfPackageVnfd.get_by_id(context,
|
||||
vnf_instance.vnfd_id)
|
||||
vnf_package = objects.VnfPackage.get_by_id(context,
|
||||
vnf_package_vnfd.package_uuid, expected_attrs=['vnfd'])
|
||||
try:
|
||||
self._update_package_usage_state(context, vnf_package)
|
||||
LOG.debug("Update vnf lcm %s %s",
|
||||
(vnf_lcm_op_occs_id,
|
||||
operation_state))
|
||||
vnf_notif = self._get_vnf_notify(context, vnf_lcm_op_occs_id)
|
||||
vnf_notif.operation_state = operation_state
|
||||
if operation_state == fields.LcmOccsOperationState.FAILED_TEMP:
|
||||
error_details = objects.ProblemDetails(
|
||||
context=context,
|
||||
status=500,
|
||||
details=error
|
||||
)
|
||||
vnf_notif.error = error_details
|
||||
vnf_notif.save()
|
||||
except Exception:
|
||||
LOG.error("Failed to update usage_state of vnf package %s",
|
||||
vnf_package.id)
|
||||
error_msg = (
|
||||
"Failed to update operation state of vnf instance %s" %
|
||||
vnf_instance_id)
|
||||
LOG.error(error_msg)
|
||||
raise exceptions.NotificationProcessingError(error=error_msg)
|
||||
|
||||
# send notification
|
||||
try:
|
||||
notification_data = {
|
||||
'notificationType':
|
||||
fields.LcmOccsNotificationType.VNF_OP_OCC_NOTIFICATION,
|
||||
'notificationStatus': fields.LcmOccsNotificationStatus.START,
|
||||
'operationState': operation_state,
|
||||
'vnfInstanceId': vnf_instance_id,
|
||||
'operation': operation,
|
||||
'isAutomaticInvocation': is_automatic_invocation,
|
||||
'vnfLcmOpOccId': vnf_lcm_op_occs_id,
|
||||
'_links': {
|
||||
'vnfInstance': {
|
||||
'href':
|
||||
'/vnflcm/v1/vnf_instances/%s'
|
||||
% vnf_instance_id},
|
||||
'vnfLcmOpOcc': {
|
||||
'href':
|
||||
'/vnflcmv1/vnf_lcm_op_occs/%s'
|
||||
% vnf_lcm_op_occs_id}}}
|
||||
|
||||
if(operation_state == fields.LcmOccsOperationState.COMPLETED or
|
||||
operation_state == fields.LcmOccsOperationState.FAILED_TEMP):
|
||||
affected_resources = vnflcm_utils._get_affected_resources(
|
||||
old_vnf_instance=old_vnf_instance,
|
||||
new_vnf_instance=vnf_instance,
|
||||
extra_list=evacuate_end_list)
|
||||
affected_resources_snake_case = \
|
||||
utils.convert_camelcase_to_snakecase(affected_resources)
|
||||
resource_change_obj = \
|
||||
jsonutils.dumps(affected_resources_snake_case)
|
||||
changed_resource = objects.ResourceChanges.obj_from_primitive(
|
||||
resource_change_obj, context)
|
||||
vnf_notif.resource_changes = changed_resource
|
||||
vnf_notif.save()
|
||||
notification_data['affectedVnfcs'] = \
|
||||
affected_resources.get('affectedVnfcs', [])
|
||||
notification_data['affectedVirtualLinks'] = \
|
||||
affected_resources.get('affectedVirtualLinks', [])
|
||||
notification_data['affectedVirtualStorages'] = \
|
||||
affected_resources.get('affectedVirtualStorages', [])
|
||||
notification_data['notificationStatus'] = \
|
||||
fields.LcmOccsNotificationStatus.RESULT
|
||||
|
||||
if operation_state == fields.LcmOccsOperationState.FAILED_TEMP:
|
||||
notification_data['error'] = error
|
||||
|
||||
# send notification
|
||||
self.send_notification(context, notification_data)
|
||||
except Exception as ex:
|
||||
LOG.error(
|
||||
"Failed to send notification {}. Details: {}".format(
|
||||
vnf_lcm_op_occs_id, str(ex)))
|
||||
|
||||
def send_notification(self, context, notification):
|
||||
try:
|
||||
LOG.debug("send_notification start notification[%s]"
|
||||
% notification)
|
||||
if (notification.get('notificationType') ==
|
||||
'VnfLcmOperationOccurrenceNotification'):
|
||||
vnf_lcm_subscriptions = \
|
||||
objects.LccnSubscriptionRequest.vnf_lcm_subscriptions_get(
|
||||
context,
|
||||
operation_type=notification.get('operation'),
|
||||
notification_type=notification.get('notificationType')
|
||||
)
|
||||
else:
|
||||
vnf_lcm_subscriptions = \
|
||||
objects.LccnSubscriptionRequest.vnf_lcm_subscriptions_get(
|
||||
context,
|
||||
notification_type=notification.get('notificationType')
|
||||
)
|
||||
if not vnf_lcm_subscriptions:
|
||||
LOG.warn(
|
||||
"vnf_lcm_subscription not found id[%s]" %
|
||||
notification.get('vnfInstanceId'))
|
||||
return -1
|
||||
|
||||
notification['id'] = uuidutils.generate_uuid()
|
||||
|
||||
# Notification shipping
|
||||
for line in vnf_lcm_subscriptions:
|
||||
notification['subscriptionId'] = line.id.decode()
|
||||
if (notification.get('notificationType') ==
|
||||
'VnfLcmOperationOccurrenceNotification'):
|
||||
notification['_links'] = {}
|
||||
notification['_links']['subscription'] = {}
|
||||
notification['_links']['subscription']['href'] = \
|
||||
CONF.vnf_lcm.endpoint_url + \
|
||||
"/vnflcm/v1/subscriptions/" + line.id.decode()
|
||||
else:
|
||||
notification['links'] = {}
|
||||
notification['links']['subscription'] = {}
|
||||
notification['links']['subscription']['href'] = \
|
||||
CONF.vnf_lcm.endpoint_url + \
|
||||
"/vnflcm/v1/subscriptions/" + line.id.decode()
|
||||
notification['timeStamp'] = datetime.datetime.utcnow(
|
||||
).isoformat()
|
||||
try:
|
||||
for num in range(CONF.vnf_lcm.retry_num):
|
||||
LOG.warn("send notify[%s]" % json.dumps(notification))
|
||||
response = requests.post(
|
||||
line.callback_uri.decode(),
|
||||
data=json.dumps(notification))
|
||||
if response.status_code == 204:
|
||||
LOG.info(
|
||||
"send success notify[%s]" %
|
||||
json.dumps(notification))
|
||||
break
|
||||
else:
|
||||
LOG.warning(
|
||||
"Notification failed id[%s] status[%s] \
|
||||
callback_uri[%s]" %
|
||||
(notification['id'],
|
||||
response.status_code,
|
||||
line.callback_uri.decode()))
|
||||
LOG.debug(
|
||||
"retry_wait %s" %
|
||||
CONF.vnf_lcm.retry_wait)
|
||||
time.sleep(CONF.vnf_lcm.retry_wait)
|
||||
if num == CONF.vnf_lcm.retry_num:
|
||||
LOG.warn("Number of retries \
|
||||
exceeded retry count")
|
||||
|
||||
continue
|
||||
except Exception as e:
|
||||
LOG.warn("send error[%s]" % str(e))
|
||||
LOG.warn(traceback.format_exc())
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
LOG.warn("Internal Sever Error[%s]" % str(e))
|
||||
LOG.warn(traceback.format_exc())
|
||||
return -2
|
||||
return 0
|
||||
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def heal(self, context, vnf_instance, heal_vnf_request):
|
||||
# Check if vnf is in instantiated state.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
LOG.error("Heal action cannot be performed on vnf %(id)s "
|
||||
"which is in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
return
|
||||
def instantiate(
|
||||
self,
|
||||
context,
|
||||
vnf_instance,
|
||||
instantiate_vnf,
|
||||
vnf_lcm_op_occs_id):
|
||||
|
||||
self.vnflcm_driver.heal_vnf(context, vnf_instance, heal_vnf_request)
|
||||
try:
|
||||
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=None,
|
||||
vnf_instance=vnf_instance,
|
||||
request_obj=instantiate_vnf
|
||||
)
|
||||
|
||||
# Check if vnf is already instantiated.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.INSTANTIATED:
|
||||
LOG.error("Vnf instance %(id)s is already in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
return
|
||||
|
||||
self.vnflcm_driver.instantiate_vnf(context, vnf_instance,
|
||||
instantiate_vnf)
|
||||
|
||||
vnf_package_vnfd = objects.VnfPackageVnfd.get_by_id(
|
||||
context, vnf_instance.vnfd_id)
|
||||
vnf_package = objects.VnfPackage.get_by_id(
|
||||
context, vnf_package_vnfd.package_uuid,
|
||||
expected_attrs=['vnfd'])
|
||||
try:
|
||||
self._update_package_usage_state(context, vnf_package)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("Failed to update usage_state of vnf package %s",
|
||||
vnf_package.id)
|
||||
|
||||
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=None,
|
||||
vnf_instance=vnf_instance,
|
||||
request_obj=instantiate_vnf,
|
||||
operation_state=fields.LcmOccsOperationState.COMPLETED
|
||||
)
|
||||
|
||||
except Exception as ex:
|
||||
# Update vnf_lcm_op_occs table and send notification "FAILED_TEMP"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=None,
|
||||
vnf_instance=vnf_instance,
|
||||
request_obj=instantiate_vnf,
|
||||
operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
|
||||
error=str(ex)
|
||||
)
|
||||
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def terminate(self, context, vnf_lcm_op_occs_id,
|
||||
vnf_instance, terminate_vnf_req, vnf_dict):
|
||||
try:
|
||||
# Check if vnf is in instantiated state.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
LOG.error("Terminate action cannot be performed on vnf %(id)s "
|
||||
"which is in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
return
|
||||
|
||||
old_vnf_instance = copy.deepcopy(vnf_instance)
|
||||
|
||||
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=old_vnf_instance,
|
||||
vnf_instance=None,
|
||||
request_obj=terminate_vnf_req,
|
||||
operation=fields.LcmOccsOperationType.TERMINATE
|
||||
)
|
||||
|
||||
self.vnflcm_driver.terminate_vnf(context, vnf_instance,
|
||||
terminate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
|
||||
vnf_package_vnfd = \
|
||||
objects.VnfPackageVnfd.get_by_id(context, vnf_instance.vnfd_id)
|
||||
vnf_package = \
|
||||
objects.VnfPackage.get_by_id(context,
|
||||
vnf_package_vnfd.package_uuid,
|
||||
expected_attrs=['vnfd'])
|
||||
try:
|
||||
self._update_package_usage_state(context, vnf_package)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("Failed to update usage_state of vnf package %s",
|
||||
vnf_package.id)
|
||||
|
||||
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=old_vnf_instance,
|
||||
vnf_instance=None,
|
||||
request_obj=terminate_vnf_req,
|
||||
operation=fields.LcmOccsOperationType.TERMINATE,
|
||||
operation_state=fields.LcmOccsOperationState.COMPLETED
|
||||
)
|
||||
|
||||
except Exception as exc:
|
||||
# Update vnf_lcm_op_occs table and send notification "FAILED_TEMP"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=old_vnf_instance,
|
||||
vnf_instance=None,
|
||||
request_obj=terminate_vnf_req,
|
||||
operation=fields.LcmOccsOperationType.TERMINATE,
|
||||
operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
|
||||
error=str(exc)
|
||||
)
|
||||
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def heal(self,
|
||||
context,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
heal_vnf_request,
|
||||
vnf_lcm_op_occs_id):
|
||||
|
||||
try:
|
||||
evacuate_end_list = []
|
||||
|
||||
# Check if vnf is in instantiated state.
|
||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
||||
vnf_instance.id)
|
||||
if vnf_instance.instantiation_state == \
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
LOG.error("Heal action cannot be performed on vnf %(id)s "
|
||||
"which is in %(state)s state.",
|
||||
{"id": vnf_instance.id,
|
||||
"state": vnf_instance.instantiation_state})
|
||||
return
|
||||
|
||||
old_vnf_instance = copy.deepcopy(vnf_instance)
|
||||
|
||||
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=old_vnf_instance,
|
||||
vnf_instance=vnf_instance,
|
||||
request_obj=heal_vnf_request,
|
||||
operation=fields.LcmOccsOperationType.HEAL
|
||||
)
|
||||
|
||||
heal_result = \
|
||||
self.vnflcm_driver.heal_vnf(context, vnf_instance, vnf_dict,
|
||||
heal_vnf_request,
|
||||
vnf_lcm_op_occs_id)
|
||||
|
||||
# update vnf_lcm_op_occs and send notification "COMPLETED"
|
||||
if heal_result:
|
||||
evacuate_end_list = heal_result.get('evacuate_end_list')
|
||||
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=old_vnf_instance,
|
||||
vnf_instance=vnf_instance,
|
||||
request_obj=heal_vnf_request,
|
||||
operation=fields.LcmOccsOperationType.HEAL,
|
||||
operation_state=fields.LcmOccsOperationState.COMPLETED,
|
||||
evacuate_end_list=evacuate_end_list
|
||||
)
|
||||
except Exception as ex:
|
||||
|
||||
# update vnf_lcm_op_occs and send notification "FAILED_TEMP"
|
||||
self._send_lcm_op_occ_notification(
|
||||
context=context,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
old_vnf_instance=old_vnf_instance,
|
||||
vnf_instance=vnf_instance,
|
||||
request_obj=heal_vnf_request,
|
||||
operation=fields.LcmOccsOperationType.HEAL,
|
||||
operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
|
||||
evacuate_end_list=evacuate_end_list,
|
||||
error=str(ex)
|
||||
)
|
||||
|
||||
|
||||
def init(args, **kwargs):
|
||||
|
@ -14,7 +14,6 @@
|
||||
# under the License.
|
||||
|
||||
import oslo_messaging
|
||||
|
||||
from tacker.common import rpc
|
||||
from tacker.common import topics
|
||||
from tacker.objects import base as objects_base
|
||||
@ -28,7 +27,9 @@ class VNFLcmRPCAPI(object):
|
||||
fanout=False,
|
||||
version='1.0')
|
||||
|
||||
def instantiate(self, context, vnf_instance, instantiate_vnf, cast=True):
|
||||
def instantiate(self, context, vnf_instance, vnf,
|
||||
instantiate_vnf, vnf_lcm_op_occs_id,
|
||||
cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
@ -37,9 +38,13 @@ class VNFLcmRPCAPI(object):
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'instantiate',
|
||||
vnf_instance=vnf_instance,
|
||||
instantiate_vnf=instantiate_vnf)
|
||||
vnf_dict=vnf,
|
||||
instantiate_vnf=instantiate_vnf,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id)
|
||||
|
||||
def terminate(self, context, vnf_instance, terminate_vnf_req, cast=True):
|
||||
def terminate(self, context, vnf_instance, vnf,
|
||||
terminate_vnf_req, vnf_lcm_op_occs_id,
|
||||
cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
@ -47,10 +52,13 @@ class VNFLcmRPCAPI(object):
|
||||
cctxt = client.prepare()
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'terminate',
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||
vnf_instance=vnf_instance,
|
||||
terminate_vnf_req=terminate_vnf_req)
|
||||
terminate_vnf_req=terminate_vnf_req,
|
||||
vnf_dict=vnf)
|
||||
|
||||
def heal(self, context, vnf_instance, heal_vnf_request, cast=True):
|
||||
def heal(self, context, vnf_instance, vnf_dict, heal_vnf_request,
|
||||
vnf_lcm_op_occs_id, cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
@ -59,4 +67,16 @@ class VNFLcmRPCAPI(object):
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'heal',
|
||||
vnf_instance=vnf_instance,
|
||||
heal_vnf_request=heal_vnf_request)
|
||||
vnf_dict=vnf_dict,
|
||||
heal_vnf_request=heal_vnf_request,
|
||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id)
|
||||
|
||||
def send_notification(self, context, notification, cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
serializer=serializer)
|
||||
cctxt = client.prepare()
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'send_notification',
|
||||
notification=notification)
|
||||
|
@ -34,6 +34,7 @@ def register_all():
|
||||
__import__('tacker.objects.vim_connection')
|
||||
__import__('tacker.objects.instantiate_vnf_req')
|
||||
__import__('tacker.objects.vnf_resources')
|
||||
__import__('tacker.objects.vnf_lcm_op_occs')
|
||||
__import__('tacker.objects.terminate_vnf_req')
|
||||
__import__('tacker.objects.vnf_artifact')
|
||||
__import__('tacker.objects.vnf_lcm_subscriptions')
|
||||
|
@ -184,3 +184,43 @@ class VnfcState(BaseTackerEnum):
|
||||
STOPPED = 'STOPPED'
|
||||
|
||||
ALL = (STARTED, STOPPED)
|
||||
|
||||
|
||||
class LcmOccsOperationState(BaseTackerEnum):
|
||||
STARTING = 'STARTING'
|
||||
PROCESSING = 'PROCESSING'
|
||||
COMPLETED = 'COMPLETED'
|
||||
FAILED_TEMP = 'FAILED_TEMP'
|
||||
|
||||
ALL = (STARTING, PROCESSING, COMPLETED, FAILED_TEMP)
|
||||
|
||||
|
||||
class LcmOccsOperationType(BaseTackerEnum):
|
||||
INSTANTIATE = 'INSTANTIATE'
|
||||
TERMINATE = 'TERMINATE'
|
||||
HEAL = 'HEAL'
|
||||
|
||||
ALL = (INSTANTIATE, TERMINATE, HEAL)
|
||||
|
||||
|
||||
class LcmOccsNotificationStatus(BaseTackerEnum):
|
||||
START = 'START'
|
||||
RESULT = 'RESULT'
|
||||
|
||||
ALL = (START, RESULT)
|
||||
|
||||
|
||||
class ResourceChangeType(BaseTackerEnum):
|
||||
ADDED = 'ADDED'
|
||||
REMOVED = 'REMOVED'
|
||||
MODIFIED = 'MODIFIED'
|
||||
TEMPORARY = 'TEMPORARY'
|
||||
|
||||
ALL = (ADDED, REMOVED, MODIFIED, TEMPORARY)
|
||||
|
||||
|
||||
class LcmOccsNotificationType(BaseTackerEnum):
|
||||
VNF_OP_OCC_NOTIFICATION = 'VnfLcmOperationOccurrenceNotification'
|
||||
VNF_ID_CREATION_NOTIFICATION = 'VnfIdentifierCreationNotification'
|
||||
|
||||
ALL = (VNF_OP_OCC_NOTIFICATION)
|
||||
|
@ -30,7 +30,9 @@ class TerminateVnfRequest(base.TackerObject, base.TackerPersistentObject):
|
||||
'termination_type': fields.VnfInstanceTerminationTypeField(
|
||||
nullable=False),
|
||||
'graceful_termination_timeout': fields.IntegerField(nullable=True,
|
||||
default=0)
|
||||
default=0),
|
||||
'additional_params': fields.DictOfStringsField(nullable=True,
|
||||
default={}),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
713
tacker/objects/vnf_lcm_op_occs.py
Normal file
713
tacker/objects/vnf_lcm_op_occs.py
Normal file
@ -0,0 +1,713 @@
|
||||
# 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.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
from sqlalchemy import exc
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from tacker.common import exceptions
|
||||
from tacker.db import api as db_api
|
||||
from tacker.db.db_sqlalchemy import api
|
||||
from tacker.db.db_sqlalchemy import models
|
||||
from tacker import objects
|
||||
from tacker.objects import base
|
||||
from tacker.objects import fields
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@db_api.context_manager.writer
|
||||
def _vnf_lcm_op_occ_create(context, values):
|
||||
context.session.execute(
|
||||
models.VnfLcmOpOccs.__table__.insert(None),
|
||||
values)
|
||||
|
||||
|
||||
@db_api.context_manager.writer
|
||||
def _vnf_lcm_op_occ_update(context, values):
|
||||
update = {'operation_state': values.operation_state,
|
||||
'state_entered_time': values.state_entered_time,
|
||||
'error_point': values.error_point,
|
||||
'updated_at': datetime.utcnow()}
|
||||
LOG.debug('values %s', values)
|
||||
if 'resource_changes' in values:
|
||||
if values.resource_changes:
|
||||
update.update({'resource_changes': jsonutils.dumps(
|
||||
values.resource_changes.to_dict())})
|
||||
if 'error' in values:
|
||||
if values.error:
|
||||
update.update({'error': jsonutils.dumps(values.error.to_dict())})
|
||||
if 'changed_info' in values:
|
||||
if values.changed_info:
|
||||
update.update({'changed_info': jsonutils.dumps(
|
||||
values.changed_info.to_dict())})
|
||||
api.model_query(context, models.VnfLcmOpOccs). \
|
||||
filter_by(id=values.id). \
|
||||
update(update, synchronize_session=False)
|
||||
|
||||
|
||||
@db_api.context_manager.reader
|
||||
def _vnf_lcm_op_occs_get_by_id(context, vnf_lcm_op_occ_id):
|
||||
|
||||
query = api.model_query(context, models.VnfLcmOpOccs,
|
||||
read_deleted="no", project_only=True). \
|
||||
filter_by(id=vnf_lcm_op_occ_id)
|
||||
|
||||
result = query.first()
|
||||
|
||||
if not result:
|
||||
raise exceptions.NotFound(resource='table',
|
||||
name='vnf_lcm_op_occs')
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@db_api.context_manager.reader
|
||||
def _vnf_notify_get_by_id(context, vnf_instance_id, columns_to_join=None):
|
||||
|
||||
query = api.model_query(context, models.VnfLcmOpOccs,
|
||||
read_deleted="no", project_only=True). \
|
||||
filter_by(id=vnf_instance_id)
|
||||
|
||||
if columns_to_join:
|
||||
for column in columns_to_join:
|
||||
query = query.options(joinedload(column))
|
||||
|
||||
result = query.first()
|
||||
|
||||
if not result:
|
||||
raise exceptions.VnfInstanceNotFound(id=vnf_instance_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@db_api.context_manager.writer
|
||||
def _vnf_notify_create(context, values):
|
||||
|
||||
vnf_lcm_op_occs = models.VnfLcmOpOccs()
|
||||
vnf_lcm_op_occs.update(values)
|
||||
vnf_lcm_op_occs.save(context.session)
|
||||
|
||||
return _vnf_notify_get_by_id(context, vnf_lcm_op_occs.id,
|
||||
columns_to_join=None)
|
||||
|
||||
|
||||
@db_api.context_manager.writer
|
||||
def _vnf_notify_update(context, vnf_instance_id, values,
|
||||
columns_to_join=None):
|
||||
|
||||
vnf_lcm_op_occs = _vnf_notify_get_by_id(context, vnf_instance_id,
|
||||
columns_to_join=columns_to_join)
|
||||
values = values.to_dict()
|
||||
vnf_lcm_op_occs.update(values)
|
||||
vnf_lcm_op_occs.save(session=context.session)
|
||||
|
||||
return vnf_lcm_op_occs
|
||||
|
||||
|
||||
@db_api.context_manager.writer
|
||||
def _destroy_vnf_notify(context, uuid):
|
||||
now = timeutils.utcnow()
|
||||
updated_values = {'deleted': True,
|
||||
'deleted_at': now
|
||||
}
|
||||
api.model_query(context, models.VnfLcmOpOccs). \
|
||||
filter_by(id=uuid). \
|
||||
update(updated_values, synchronize_session=False)
|
||||
|
||||
|
||||
# decorator to catch DBAccess exception
|
||||
def _wrap_object_error(method):
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
method(*args, **kwargs)
|
||||
except exc.SQLAlchemyError:
|
||||
raise exceptions.DBAccessError
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
||||
base.TackerPersistentObject):
|
||||
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.UUIDField(nullable=False),
|
||||
'operation_state': fields.StringField(nullable=False),
|
||||
'state_entered_time': fields.DateTimeField(nullable=False),
|
||||
'start_time': fields.DateTimeField(nullable=False),
|
||||
'vnf_instance_id': fields.StringField(nullable=False),
|
||||
'operation': fields.StringField(nullable=False),
|
||||
'is_automatic_invocation': fields.BooleanField(default=False),
|
||||
'operation_params': fields.StringField(nullable=True),
|
||||
'is_cancel_pending': fields.BooleanField(default=False),
|
||||
'error': fields.ObjectField(
|
||||
'ProblemDetails', nullable=True, default=None),
|
||||
'resource_changes': fields.ObjectField(
|
||||
'ResourceChanges', nullable=True, default=None),
|
||||
'changed_info': fields.ObjectField(
|
||||
'VnfInfoModifications', nullable=True, default=None),
|
||||
'error_point': fields.IntegerField(nullable=True, default=0)
|
||||
}
|
||||
|
||||
@base.remotable
|
||||
def create(self):
|
||||
updates = self.obj_clone()
|
||||
_vnf_lcm_op_occ_create(self._context, updates)
|
||||
|
||||
@base.remotable
|
||||
def save(self):
|
||||
updates = self.obj_clone()
|
||||
_vnf_lcm_op_occ_update(self._context, updates)
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object(context, vnf_lcm_op_occ_obj, db_vnf_lcm_op_occ):
|
||||
|
||||
special_fields = ['error',
|
||||
'resource_changes', 'changed_info']
|
||||
for key in vnf_lcm_op_occ_obj.fields:
|
||||
if key in special_fields:
|
||||
continue
|
||||
setattr(vnf_lcm_op_occ_obj, key, db_vnf_lcm_op_occ.get(key))
|
||||
if db_vnf_lcm_op_occ['error']:
|
||||
error = ProblemDetails.obj_from_primitive(
|
||||
db_vnf_lcm_op_occ['error'], context)
|
||||
vnf_lcm_op_occ_obj.error = error
|
||||
if db_vnf_lcm_op_occ['resource_changes']:
|
||||
resource_changes = ResourceChanges.obj_from_primitive(
|
||||
db_vnf_lcm_op_occ['resource_changes'], context)
|
||||
vnf_lcm_op_occ_obj.resource_changes = resource_changes
|
||||
if db_vnf_lcm_op_occ['changed_info']:
|
||||
changed_info = VnfInfoModifications.obj_from_primitive(
|
||||
db_vnf_lcm_op_occ['changed_info'], context)
|
||||
vnf_lcm_op_occ_obj.changed_info = changed_info
|
||||
|
||||
vnf_lcm_op_occ_obj._context = context
|
||||
vnf_lcm_op_occ_obj.obj_reset_changes()
|
||||
return vnf_lcm_op_occ_obj
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
vnf_lcm_op_occ = super(
|
||||
VnfLcmOpOcc, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
if 'error' in primitive.keys():
|
||||
obj_data = ProblemDetails._from_dict(
|
||||
primitive.get('error'))
|
||||
primitive.update({'error': obj_data})
|
||||
if 'resource_changes' in primitive.keys():
|
||||
obj_data = ResourceChanges._from_dict(
|
||||
primitive.get('resource_changes'))
|
||||
primitive.update({'resource_changes': obj_data})
|
||||
if 'changed_info' in primitive.keys():
|
||||
obj_data = VnfInfoModifications._from_dict(
|
||||
primitive.get('changed_info'))
|
||||
primitive.update({'changed_info': obj_data})
|
||||
vnf_lcm_op_occ = VnfLcmOpOcc._from_dict(primitive)
|
||||
|
||||
return vnf_lcm_op_occ
|
||||
|
||||
@classmethod
|
||||
def obj_from_db_obj(cls, context, db_obj):
|
||||
return cls._from_db_object(context, cls(), db_obj)
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
operation_state = data_dict.get('operation_state')
|
||||
state_entered_time = data_dict.get('state_entered_time')
|
||||
start_time = data_dict.get('start_time')
|
||||
vnf_instance_id = data_dict.get('vnf_instance_id')
|
||||
operation = data_dict.get('operation')
|
||||
is_automatic_invocation = data_dict.get('is_automatic_invocation')
|
||||
operation_params = data_dict.get('operation_params')
|
||||
is_cancel_pending = data_dict.get('is_cancel_pending')
|
||||
error = data_dict.get('error')
|
||||
resource_changes = data_dict.get('resource_changes')
|
||||
changed_info = data_dict.get('changed_info')
|
||||
error_point = data_dict.get('error_point')
|
||||
|
||||
obj = cls(operation_state=operation_state,
|
||||
state_entered_time=state_entered_time,
|
||||
start_time=start_time,
|
||||
vnf_instance_id=vnf_instance_id,
|
||||
operation=operation,
|
||||
is_automatic_invocation=is_automatic_invocation,
|
||||
operation_params=operation_params,
|
||||
is_cancel_pending=is_cancel_pending,
|
||||
error=error,
|
||||
resource_changes=resource_changes,
|
||||
changed_info=changed_info,
|
||||
error_point=error_point
|
||||
)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
data = {'id': self.id,
|
||||
'operation_state': self.operation_state,
|
||||
'state_entered_time': self.state_entered_time,
|
||||
'start_time': self.start_time,
|
||||
'vnf_instance_id': self.vnf_instance_id,
|
||||
'operation': self.operation,
|
||||
'is_automatic_invocation': self.is_automatic_invocation,
|
||||
'operation_params': self.operation_params,
|
||||
'is_cancel_pending': self.is_cancel_pending,
|
||||
'error_point': self.error_point}
|
||||
if self.error:
|
||||
data.update({'error': self.error.to_dict()})
|
||||
if self.resource_changes:
|
||||
data.update({'resource_changes': self.resource_changes.to_dict()})
|
||||
if self.changed_info:
|
||||
data.update({'changed_info': self.changed_info.to_dict()})
|
||||
|
||||
return data
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_id(cls, context, id):
|
||||
db_vnf_lcm_op_occs = _vnf_lcm_op_occs_get_by_id(context, id)
|
||||
return cls._from_db_object(context, cls(), db_vnf_lcm_op_occs)
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class ResourceChanges(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'affected_vnfcs': fields.ListOfObjectsField(
|
||||
'AffectedVnfc', nullable=True),
|
||||
'affected_virtual_links': fields.ListOfObjectsField(
|
||||
'AffectedVirtualLink', nullable=True),
|
||||
'affected_virtual_storages': fields.ListOfObjectsField(
|
||||
'AffectedVirtualStorage', nullable=True)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
resource_changes = super(
|
||||
ResourceChanges, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
rs_dict = jsonutils.loads(primitive)
|
||||
if rs_dict.get('affected_vnfcs'):
|
||||
obj_data = [AffectedVnfc._from_dict(
|
||||
affected_vnfc) for affected_vnfc in rs_dict.get(
|
||||
'affected_vnfcs', [])]
|
||||
rs_dict.update({'affected_vnfcs': obj_data})
|
||||
if rs_dict.get('affected_virtual_links'):
|
||||
obj_data = [AffectedVirtualLink._from_dict(
|
||||
affected_virtual_link)
|
||||
for affected_virtual_link in rs_dict.get(
|
||||
'affected_virtual_links', [])]
|
||||
rs_dict.update({'affected_virtual_links': obj_data})
|
||||
if rs_dict.get('affected_virtual_storages'):
|
||||
obj_data = [AffectedVirtualStorage._from_dict(
|
||||
affected_virtual_storage)
|
||||
for affected_virtual_storage in rs_dict.get(
|
||||
'affected_virtual_storages', [])]
|
||||
rs_dict.update({'affected_virtual_storages': obj_data})
|
||||
resource_changes = ResourceChanges._from_dict(rs_dict)
|
||||
|
||||
return resource_changes
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
affected_vnfcs = data_dict.get('affected_vnfcs')
|
||||
affected_virtual_links = data_dict.get('affected_virtual_links')
|
||||
affected_virtual_storages = data_dict.get('affected_virtual_storages')
|
||||
|
||||
obj = cls(affected_vnfcs=affected_vnfcs,
|
||||
affected_virtual_links=affected_virtual_links,
|
||||
affected_virtual_storages=affected_virtual_storages
|
||||
)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
data = {}
|
||||
if self.affected_vnfcs:
|
||||
affected_vnfcs_list = []
|
||||
for affected_vnfc in self.affected_vnfcs:
|
||||
affected_vnfcs_list.append(affected_vnfc.to_dict())
|
||||
|
||||
data.update({'affected_vnfcs': affected_vnfcs_list})
|
||||
if self.affected_virtual_links:
|
||||
affected_virtual_links_list = []
|
||||
for affected_virtual_link in self.affected_virtual_links:
|
||||
affected_virtual_links_list.append(
|
||||
affected_virtual_link.to_dict())
|
||||
|
||||
data.update(
|
||||
{'affected_virtual_links': affected_virtual_links_list})
|
||||
if self.affected_virtual_storages:
|
||||
affected_virtual_storages_list = []
|
||||
for affected_virtual_storage in self.affected_virtual_storages:
|
||||
affected_virtual_storages_list.append(
|
||||
affected_virtual_storage.to_dict())
|
||||
|
||||
data.update(
|
||||
{'affected_virtual_storages': affected_virtual_storages_list})
|
||||
return data
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class ProblemDetails(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'title': fields.StringField(nullable=True, default=''),
|
||||
'status': fields.IntegerField(nullable=False),
|
||||
'detail': fields.StringField(nullable=False)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
problem_detail = super(
|
||||
ProblemDetails, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
p_dict = jsonutils.loads(primitive)
|
||||
problem_detail = ProblemDetails._from_dict(p_dict)
|
||||
|
||||
return problem_detail
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
title = data_dict.get('title')
|
||||
status = data_dict.get('status')
|
||||
detail = data_dict.get('detail')
|
||||
|
||||
obj = cls(title=title,
|
||||
status=status,
|
||||
detail=detail)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
return {'title': self.title,
|
||||
'status': self.status,
|
||||
'detail': self.detail}
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class AffectedVnfc(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.StringField(nullable=False),
|
||||
'vdu_id': fields.StringField(nullable=False),
|
||||
'change_type': fields.StringField(nullable=False),
|
||||
'compute_resource': fields.ObjectField(
|
||||
'ResourceHandle', nullable=False),
|
||||
'affected_vnfc_cp_ids':
|
||||
fields.ListOfStringsField(nullable=True, default=[]),
|
||||
'added_storage_resource_ids':
|
||||
fields.ListOfStringsField(nullable=True, default=[]),
|
||||
'removed_storage_resource_ids':
|
||||
fields.ListOfStringsField(nullable=True, default=[])
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
affected_vnfc = super(
|
||||
AffectedVnfc, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
if 'compute_resource' in primitive.keys():
|
||||
obj_data = ResourceHandle._from_dict(
|
||||
primitive.get('compute_resource'))
|
||||
primitive.update({'compute_resource': obj_data})
|
||||
affected_vnfc = AffectedVnfc._from_dict(primitive)
|
||||
|
||||
return affected_vnfc
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
id = data_dict.get('id')
|
||||
vdu_id = data_dict.get('vdu_id')
|
||||
change_type = data_dict.get('change_type')
|
||||
compute_resource = ResourceHandle._from_dict(
|
||||
data_dict.get('compute_resource'))
|
||||
affected_vnfc_cp_ids = data_dict.get('affected_vnfc_cp_ids')
|
||||
added_storage_resource_ids = data_dict.get(
|
||||
'added_storage_resource_ids')
|
||||
removed_storage_resource_ids = data_dict.get(
|
||||
'removed_storage_resource_ids')
|
||||
|
||||
obj = cls(id=id,
|
||||
vdu_id=vdu_id,
|
||||
change_type=change_type,
|
||||
compute_resource=compute_resource,
|
||||
affected_vnfc_cp_ids=affected_vnfc_cp_ids,
|
||||
added_storage_resource_ids=added_storage_resource_ids,
|
||||
removed_storage_resource_ids=removed_storage_resource_ids
|
||||
)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'vdu_id': self.vdu_id,
|
||||
'change_type': self.change_type,
|
||||
'compute_resource': self.compute_resource.to_dict(),
|
||||
'affected_vnfc_cp_ids': self.affected_vnfc_cp_ids,
|
||||
'added_storage_resource_ids': self.added_storage_resource_ids,
|
||||
'removed_storage_resource_ids': self.removed_storage_resource_ids}
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class AffectedVirtualLink(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.StringField(nullable=False),
|
||||
'vnf_virtual_link_desc_id': fields.StringField(nullable=False),
|
||||
'change_type': fields.StringField(nullable=False),
|
||||
'network_resource': fields.ObjectField(
|
||||
'ResourceHandle', nullable=False)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
affected_virtual_link = super(
|
||||
AffectedVirtualLink, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
if 'network_resource' in primitive.keys():
|
||||
obj_data = ResourceHandle._from_dict(
|
||||
primitive.get('network_resource'))
|
||||
primitive.update({'network_resource': obj_data})
|
||||
affected_virtual_link = AffectedVirtualLink._from_dict(primitive)
|
||||
|
||||
return affected_virtual_link
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
id = data_dict.get('id')
|
||||
vnf_virtual_link_desc_id = data_dict.get('vnf_virtual_link_desc_id')
|
||||
change_type = data_dict.get('change_type')
|
||||
network_resource = ResourceHandle._from_dict(
|
||||
data_dict.get('network_resource'))
|
||||
|
||||
obj = cls(id=id,
|
||||
vnf_virtual_link_desc_id=vnf_virtual_link_desc_id,
|
||||
change_type=change_type,
|
||||
network_resource=network_resource
|
||||
)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
return {'id': self.id,
|
||||
'vnf_virtual_link_desc_id': self.vnf_virtual_link_desc_id,
|
||||
'change_type': self.change_type,
|
||||
'network_resource': self.network_resource.to_dict()}
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class AffectedVirtualStorage(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.StringField(nullable=False),
|
||||
'virtual_storage_desc_id': fields.StringField(nullable=False),
|
||||
'change_type': fields.StringField(nullable=False),
|
||||
'storage_resource': fields.ObjectField(
|
||||
'ResourceHandle', nullable=False)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
affected_virtual_storage = super(
|
||||
AffectedVirtualStorage, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
if 'storage_resource' in primitive.keys():
|
||||
obj_data = ResourceHandle._from_dict(
|
||||
primitive.get('storage_resource'))
|
||||
primitive.update({'storage_resource': obj_data})
|
||||
affected_virtual_storage = AffectedVirtualStorage._from_dict(
|
||||
primitive)
|
||||
|
||||
return affected_virtual_storage
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
id = data_dict.get('id')
|
||||
virtual_storage_desc_id = data_dict.get('virtual_storage_desc_id')
|
||||
change_type = data_dict.get('change_type')
|
||||
storage_resource = ResourceHandle._from_dict(
|
||||
data_dict.get('storage_resource'))
|
||||
|
||||
obj = cls(id=id,
|
||||
virtual_storage_desc_id=virtual_storage_desc_id,
|
||||
change_type=change_type,
|
||||
storage_resource=storage_resource
|
||||
)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
return {'id': self.id,
|
||||
'virtual_storage_desc_id': self.virtual_storage_desc_id,
|
||||
'change_type': self.change_type,
|
||||
'storage_resource': self.storage_resource.to_dict()}
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class VnfInfoModifications(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'vnf_instance_name': fields.StringField(nullable=True),
|
||||
'vnf_instance_description': fields.StringField(nullable=True),
|
||||
'vim_connection_info': fields.ListOfObjectsField(
|
||||
'VimConnectionInfo', nullable=True, default=[]),
|
||||
'vim_connection_info_delete_ids':
|
||||
fields.ListOfStringsField(nullable=True, default=[]),
|
||||
'vnf_pkg_id': fields.StringField(nullable=True, default=None),
|
||||
'vnfd_id': fields.StringField(nullable=True),
|
||||
'vnf_provider': fields.StringField(nullable=True),
|
||||
'vnf_product_name': fields.StringField(nullable=True),
|
||||
'vnf_software_version': fields.StringField(nullable=True),
|
||||
'vnfd_version': fields.StringField(nullable=True)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
vnf_info_modifications = super(
|
||||
VnfInfoModifications, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
if 'vim_connection_info' in primitive.keys():
|
||||
obj_data = [objects.VimConnectionInfo._from_dict(
|
||||
vim_conn) for vim_conn in primitive.get(
|
||||
'vim_connection_info', [])]
|
||||
primitive.update({'vim_connection_info': obj_data})
|
||||
vnf_info_modifications = VnfInfoModifications._from_dict(primitive)
|
||||
|
||||
return vnf_info_modifications
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
vnf_instance_name = data_dict.get('vnf_instance_name')
|
||||
vnf_instance_description = data_dict.get('vnf_instance_description')
|
||||
vim_connection_info = data_dict.get('vim_connection_info', [])
|
||||
vim_connection_info_delete_ids = data_dict.get(
|
||||
'vim_connection_info_delete_ids')
|
||||
vnf_pkg_id = data_dict.get('vnf_pkg_id')
|
||||
vnfd_id = data_dict.get('vnfd_id')
|
||||
vnf_provider = data_dict.get('vnf_provider')
|
||||
vnf_product_name = data_dict.get('vnf_product_name')
|
||||
vnf_software_version = data_dict.get('vnf_software_version')
|
||||
vnfd_version = data_dict.get('vnfd_version')
|
||||
|
||||
obj = cls(
|
||||
vnf_instance_name=vnf_instance_name,
|
||||
vnf_instance_description=vnf_instance_description,
|
||||
vim_connection_info=vim_connection_info,
|
||||
vim_connection_info_delete_ids=vim_connection_info_delete_ids,
|
||||
vnf_pkg_id=vnf_pkg_id,
|
||||
vnfd_id=vnfd_id,
|
||||
vnf_provider=vnf_provider,
|
||||
vnf_product_name=vnf_product_name,
|
||||
vnf_software_version=vnf_software_version,
|
||||
vnfd_version=vnfd_version)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'vnf_instance_name': self.vnf_instance_name,
|
||||
'vnf_instance_description': self.vnf_instance_description,
|
||||
'vim_connection_info': self.vim_connection_info,
|
||||
'vim_connection_info_delete_ids':
|
||||
self.vim_connection_info_delete_ids,
|
||||
'vnf_pkg_id': self.vnf_pkg_id,
|
||||
'vnfd_id': self.vnfd_id,
|
||||
'vnf_provider': self.vnf_provider,
|
||||
'vnf_product_name': self.vnf_product_name,
|
||||
'vnf_software_version': self.vnf_software_version,
|
||||
'vnfd_version': self.vnfd_version}
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class ResourceHandle(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'vim_connection_id': fields.StringField(nullable=True,
|
||||
default=None),
|
||||
'resource_id': fields.StringField(nullable=False, default=""),
|
||||
'vim_level_resource_type': fields.StringField(nullable=True,
|
||||
default=None)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def obj_from_primitive(cls, primitive, context):
|
||||
if 'tacker_object.name' in primitive:
|
||||
resource_handle = super(
|
||||
ResourceHandle, cls).obj_from_primitive(
|
||||
primitive, context)
|
||||
else:
|
||||
resource_handle = ResourceHandle._from_dict(primitive)
|
||||
|
||||
return resource_handle
|
||||
|
||||
@classmethod
|
||||
def _from_dict(cls, data_dict):
|
||||
LOG.debug("data_dict %s", data_dict)
|
||||
vim_connection_id = data_dict.get('vim_connection_id')
|
||||
resource_id = data_dict.get('resource_id', "")
|
||||
vim_level_resource_type = data_dict.get('vim_level_resource_type')
|
||||
|
||||
obj = cls(vim_connection_id=vim_connection_id,
|
||||
resource_id=resource_id,
|
||||
vim_level_resource_type=vim_level_resource_type)
|
||||
|
||||
return obj
|
||||
|
||||
def to_dict(self):
|
||||
return {'vim_connection_id': self.vim_connection_id,
|
||||
'resource_id': self.resource_id,
|
||||
'vim_level_resource_type': self.vim_level_resource_type}
|
@ -31,6 +31,7 @@ COMMON_PREFIXES = {
|
||||
# Service operation status constants
|
||||
ACTIVE = "ACTIVE"
|
||||
ACK = "ACK"
|
||||
INACTIVE = "INACTIVE"
|
||||
|
||||
PENDING_CREATE = "PENDING_CREATE"
|
||||
PENDING_UPDATE = "PENDING_UPDATE"
|
||||
|
@ -13,14 +13,18 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import iso8601
|
||||
|
||||
import os
|
||||
from oslo_config import cfg
|
||||
import shutil
|
||||
import tempfile
|
||||
import uuid
|
||||
import yaml
|
||||
import zipfile
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from tacker.tests import utils
|
||||
from tacker.tests import uuidsentinel
|
||||
|
||||
@ -86,6 +90,40 @@ def create_fake_csar_dir(vnf_package_id, temp_dir,
|
||||
return fake_csar
|
||||
|
||||
|
||||
def get_vnf_package_vnfd():
|
||||
return {
|
||||
"id": uuidsentinel.vnfd_id,
|
||||
"vnf_provider": "test vnf provider",
|
||||
"vnf_product_name": "Sample VNF",
|
||||
"vnf_software_version": "1.0",
|
||||
"vnfd_version": "1.0",
|
||||
"name": 'Sample VNF Instance',
|
||||
}
|
||||
|
||||
|
||||
def get_lcm_op_occs_data():
|
||||
return {
|
||||
"tenant_id": uuidsentinel.tenant_id,
|
||||
'operation_state': 'PROCESSING',
|
||||
'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),
|
||||
'operation': 'MODIFY_INFO',
|
||||
'is_automatic_invocation': 0,
|
||||
'is_cancel_pending': 0,
|
||||
}
|
||||
|
||||
|
||||
def get_vnf_lcm_subscriptions():
|
||||
subscription_id = uuidsentinel.subscription_id
|
||||
return {
|
||||
"id": subscription_id.encode(),
|
||||
"callback_uri": b'http://localhost:9890/'
|
||||
}
|
||||
|
||||
|
||||
def get_expected_vnfd_data(zip_file=None):
|
||||
if zip_file:
|
||||
csar_temp_dir = tempfile.mkdtemp()
|
||||
|
@ -19,8 +19,10 @@ import sys
|
||||
from unittest import mock
|
||||
|
||||
import fixtures
|
||||
|
||||
from glance_store import exceptions as store_exceptions
|
||||
from oslo_config import cfg
|
||||
import requests
|
||||
from six.moves import urllib
|
||||
import six.moves.urllib.error as urlerr
|
||||
import yaml
|
||||
@ -36,6 +38,7 @@ from tacker import objects
|
||||
from tacker.objects import fields
|
||||
from tacker.tests.unit.conductor import fakes
|
||||
from tacker.tests.unit.db.base import SqlTestCase
|
||||
from tacker.tests.unit.db import utils as db_utils
|
||||
from tacker.tests.unit.objects import fakes as fake_obj
|
||||
from tacker.tests.unit.vnflcm import fakes as vnflcm_fakes
|
||||
from tacker.tests import utils
|
||||
@ -62,6 +65,7 @@ class TestConductor(SqlTestCase):
|
||||
self._mock_vnfm_plugin()
|
||||
self.conductor = conductor_server.Conductor('host')
|
||||
self.vnf_package = self._create_vnf_package()
|
||||
self.instance_uuid = uuidsentinel.instance_id
|
||||
self.temp_dir = self.useFixture(fixtures.TempDir()).path
|
||||
|
||||
def _mock_vnfm_plugin(self):
|
||||
@ -84,6 +88,9 @@ class TestConductor(SqlTestCase):
|
||||
vnfpkgm.create()
|
||||
return vnfpkgm
|
||||
|
||||
def _create_vnf_package_vnfd(self):
|
||||
return fakes.get_vnf_package_vnfd()
|
||||
|
||||
@mock.patch.object(conductor_server.Conductor, '_onboard_vnf_package')
|
||||
@mock.patch.object(conductor_server, 'revert_upload_vnf_package')
|
||||
@mock.patch.object(csar_utils, 'load_csar_data')
|
||||
@ -204,10 +211,19 @@ class TestConductor(SqlTestCase):
|
||||
|
||||
return vnf_pack_vnfd_obj
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
def test_instantiate_vnf_instance(self, mock_package_in_use,
|
||||
mock_get_lock):
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||
def test_instantiate_vnf_instance(self, mock_vnf_by_id,
|
||||
mock_package_in_use,
|
||||
mock_get_lock,
|
||||
mock_save):
|
||||
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||
mock_vnf_by_id.return_value = \
|
||||
objects.VnfLcmOpOcc(context=self.context,
|
||||
**lcm_op_occs_data)
|
||||
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -216,17 +232,27 @@ class TestConductor(SqlTestCase):
|
||||
**vnf_instance_data)
|
||||
vnf_instance.create()
|
||||
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
self.conductor.instantiate(self.context, vnf_instance,
|
||||
instantiate_vnf_req)
|
||||
instantiate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, instantiate_vnf_req)
|
||||
mock_package_in_use.assert_called_once()
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
@mock.patch('tacker.conductor.conductor_server.LOG')
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||
def test_instantiate_vnf_instance_already_instantiated(self,
|
||||
mock_log, mock_package_in_use, mock_get_lock):
|
||||
mock_vnf_by_id, mock_log, mock_package_in_use, mock_get_lock,
|
||||
mock_save):
|
||||
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||
mock_vnf_by_id.return_value = \
|
||||
objects.VnfLcmOpOcc(context=self.context,
|
||||
**lcm_op_occs_data)
|
||||
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -236,8 +262,10 @@ class TestConductor(SqlTestCase):
|
||||
**vnf_instance_data)
|
||||
vnf_instance.create()
|
||||
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
self.conductor.instantiate(self.context, vnf_instance,
|
||||
instantiate_vnf_req)
|
||||
instantiate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
self.vnflcm_driver.instantiate_vnf.assert_not_called()
|
||||
mock_package_in_use.assert_not_called()
|
||||
expected_log = 'Vnf instance %(id)s is already in %(state)s state.'
|
||||
@ -245,29 +273,58 @@ class TestConductor(SqlTestCase):
|
||||
{'id': vnf_instance.id,
|
||||
'state': fields.VnfInstanceState.INSTANTIATED})
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||
def test_instantiate_vnf_instance_with_vnf_package_in_use(self,
|
||||
mock_vnf_package_in_use, mock_get_lock):
|
||||
mock_vnf_by_id,
|
||||
mock_vnf_lcm_subscriptions_get,
|
||||
mock_vnf_package_in_use, mock_get_lock, mock_save):
|
||||
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||
mock_vnf_by_id.return_value = \
|
||||
objects.VnfLcmOpOcc(context=self.context,
|
||||
**lcm_op_occs_data)
|
||||
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
m_vnf_lcm_subscriptions = \
|
||||
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
||||
mock_vnf_lcm_subscriptions_get.return_value = \
|
||||
m_vnf_lcm_subscriptions
|
||||
mock_vnf_package_in_use.return_value = True
|
||||
vnf_instance = objects.VnfInstance(context=self.context,
|
||||
**vnf_instance_data)
|
||||
vnf_instance.create()
|
||||
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
self.conductor.instantiate(self.context, vnf_instance,
|
||||
instantiate_vnf_req)
|
||||
instantiate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, instantiate_vnf_req)
|
||||
mock_vnf_package_in_use.assert_called_once()
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
@mock.patch('tacker.conductor.conductor_server.LOG')
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||
@mock.patch('tacker.vnflcm.utils._get_affected_resources')
|
||||
def test_instantiate_vnf_instance_failed_with_exception(
|
||||
self, mock_log, mock_is_package_in_use, mock_get_lock):
|
||||
self, mock_res, mock_vnf_by_id, mock_log,
|
||||
mock_vnf_lcm_subscriptions_get,
|
||||
mock_is_package_in_use, mock_get_lock, mock_save):
|
||||
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||
mock_vnf_by_id.return_value = \
|
||||
objects.VnfLcmOpOcc(context=self.context,
|
||||
**lcm_op_occs_data)
|
||||
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -275,9 +332,16 @@ class TestConductor(SqlTestCase):
|
||||
**vnf_instance_data)
|
||||
vnf_instance.create()
|
||||
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
m_vnf_lcm_subscriptions = \
|
||||
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
||||
mock_vnf_lcm_subscriptions_get.return_value = \
|
||||
m_vnf_lcm_subscriptions
|
||||
mock_is_package_in_use.side_effect = Exception
|
||||
mock_res.return_value = {}
|
||||
self.conductor.instantiate(self.context, vnf_instance,
|
||||
instantiate_vnf_req)
|
||||
instantiate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, instantiate_vnf_req)
|
||||
mock_is_package_in_use.assert_called_once()
|
||||
@ -285,9 +349,13 @@ class TestConductor(SqlTestCase):
|
||||
mock_log.error.assert_called_once_with(expected_log,
|
||||
vnf_package_vnfd.package_uuid)
|
||||
|
||||
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||
'_send_lcm_op_occ_notification')
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
def test_terminate_vnf_instance(self, mock_package_in_use, mock_get_lock):
|
||||
def test_terminate_vnf_instance(self, mock_package_in_use,
|
||||
mock_get_lock,
|
||||
mock_send_notification):
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -299,20 +367,27 @@ class TestConductor(SqlTestCase):
|
||||
vnf_instance.create()
|
||||
|
||||
terminate_vnf_req = objects.TerminateVnfRequest(
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL)
|
||||
|
||||
self.conductor.terminate(self.context, vnf_instance,
|
||||
terminate_vnf_req)
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
|
||||
additional_params={"key": "value"})
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
|
||||
vnf_instance,
|
||||
terminate_vnf_req, vnf_dict)
|
||||
|
||||
self.vnflcm_driver.terminate_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, terminate_vnf_req)
|
||||
self.context, mock.ANY, terminate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
mock_package_in_use.assert_called_once()
|
||||
|
||||
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||
'_send_lcm_op_occ_notification')
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
@mock.patch('tacker.conductor.conductor_server.LOG')
|
||||
def test_terminate_vnf_instance_already_not_instantiated(self,
|
||||
mock_log, mock_package_in_use, mock_get_lock):
|
||||
mock_log, mock_package_in_use, mock_get_lock,
|
||||
mock_send_notification):
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -324,10 +399,13 @@ class TestConductor(SqlTestCase):
|
||||
vnf_instance.create()
|
||||
|
||||
terminate_vnf_req = objects.TerminateVnfRequest(
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL)
|
||||
|
||||
self.conductor.terminate(self.context, vnf_instance,
|
||||
terminate_vnf_req)
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
|
||||
additional_params={"key": "value"})
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
|
||||
vnf_instance,
|
||||
terminate_vnf_req, vnf_dict)
|
||||
|
||||
self.vnflcm_driver.terminate_vnf.assert_not_called()
|
||||
mock_package_in_use.assert_not_called()
|
||||
@ -337,10 +415,13 @@ class TestConductor(SqlTestCase):
|
||||
{'id': vnf_instance.id,
|
||||
'state': fields.VnfInstanceState.NOT_INSTANTIATED})
|
||||
|
||||
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||
'_send_lcm_op_occ_notification')
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
def test_terminate_vnf_instance_with_usage_state_not_in_use(self,
|
||||
mock_vnf_package_is_package_in_use, mock_get_lock):
|
||||
mock_vnf_package_is_package_in_use, mock_get_lock,
|
||||
mock_send_notification):
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -352,19 +433,26 @@ class TestConductor(SqlTestCase):
|
||||
|
||||
mock_vnf_package_is_package_in_use.return_value = False
|
||||
terminate_vnf_req = objects.TerminateVnfRequest(
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL)
|
||||
|
||||
self.conductor.terminate(self.context, vnf_instance,
|
||||
terminate_vnf_req)
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
|
||||
additional_params={"key": "value"})
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
|
||||
vnf_instance,
|
||||
terminate_vnf_req, vnf_dict)
|
||||
|
||||
self.vnflcm_driver.terminate_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, terminate_vnf_req)
|
||||
self.context, mock.ANY, terminate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
mock_vnf_package_is_package_in_use.assert_called_once()
|
||||
|
||||
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||
'_send_lcm_op_occ_notification')
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
def test_terminate_vnf_instance_with_usage_state_already_in_use(self,
|
||||
mock_vnf_package_is_package_in_use, mock_get_lock):
|
||||
mock_vnf_package_is_package_in_use, mock_get_lock,
|
||||
mock_send_notification):
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -376,20 +464,27 @@ class TestConductor(SqlTestCase):
|
||||
|
||||
mock_vnf_package_is_package_in_use.return_value = True
|
||||
terminate_vnf_req = objects.TerminateVnfRequest(
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL)
|
||||
|
||||
self.conductor.terminate(self.context, vnf_instance,
|
||||
terminate_vnf_req)
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
|
||||
additional_params={"key": "value"})
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
|
||||
vnf_instance,
|
||||
terminate_vnf_req, vnf_dict)
|
||||
|
||||
self.vnflcm_driver.terminate_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, terminate_vnf_req)
|
||||
self.context, mock.ANY, terminate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
mock_vnf_package_is_package_in_use.assert_called_once()
|
||||
|
||||
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||
'_send_lcm_op_occ_notification')
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||
@mock.patch('tacker.conductor.conductor_server.LOG')
|
||||
def test_terminate_vnf_instance_failed_to_update_usage_state(
|
||||
self, mock_log, mock_is_package_in_use, mock_get_lock):
|
||||
self, mock_log, mock_is_package_in_use, mock_get_lock,
|
||||
mock_send_notification):
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -399,18 +494,30 @@ class TestConductor(SqlTestCase):
|
||||
**vnf_instance_data)
|
||||
vnf_instance.create()
|
||||
terminate_vnf_req = objects.TerminateVnfRequest(
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL)
|
||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
|
||||
additional_params={"key": "value"})
|
||||
mock_is_package_in_use.side_effect = Exception
|
||||
self.conductor.terminate(self.context, vnf_instance,
|
||||
terminate_vnf_req)
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
|
||||
vnf_instance,
|
||||
terminate_vnf_req, vnf_dict)
|
||||
self.vnflcm_driver.terminate_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, terminate_vnf_req)
|
||||
self.context, mock.ANY, terminate_vnf_req,
|
||||
vnf_lcm_op_occs_id)
|
||||
expected_msg = "Failed to update usage_state of vnf package %s"
|
||||
mock_log.error.assert_called_once_with(expected_msg,
|
||||
vnf_package_vnfd.package_uuid)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
def test_heal_vnf_instance(self, mock_get_lock):
|
||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||
def test_heal_vnf_instance(self, mock_vnf_by_id, mock_get_lock,
|
||||
mock_save):
|
||||
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||
mock_vnf_by_id.return_value = \
|
||||
objects.VnfLcmOpOcc(context=self.context,
|
||||
**lcm_op_occs_data)
|
||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||
vnf_package_vnfd.vnfd_id)
|
||||
@ -421,9 +528,10 @@ class TestConductor(SqlTestCase):
|
||||
fields.VnfInstanceState.INSTANTIATED
|
||||
vnf_instance.save()
|
||||
heal_vnf_req = objects.HealVnfRequest(cause="healing request")
|
||||
self.conductor.heal(self.context, vnf_instance, heal_vnf_req)
|
||||
self.vnflcm_driver.heal_vnf.assert_called_once_with(
|
||||
self.context, mock.ANY, heal_vnf_req)
|
||||
vnf_dict = {"fake": "fake_dict"}
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
self.conductor.heal(self.context, vnf_instance, vnf_dict,
|
||||
heal_vnf_req, vnf_lcm_op_occs_id)
|
||||
|
||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||
@mock.patch('tacker.conductor.conductor_server.LOG')
|
||||
@ -440,7 +548,10 @@ class TestConductor(SqlTestCase):
|
||||
vnf_instance.create()
|
||||
|
||||
heal_vnf_req = objects.HealVnfRequest(cause="healing request")
|
||||
self.conductor.heal(self.context, vnf_instance, heal_vnf_req)
|
||||
vnf_dict = {"fake": "fake_dict"}
|
||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
self.conductor.heal(self.context, vnf_instance, vnf_dict,
|
||||
heal_vnf_req, vnf_lcm_op_occs_id)
|
||||
|
||||
self.vnflcm_driver.heal_vnf.assert_not_called()
|
||||
expected_log = ('Heal action cannot be performed on vnf %(id)s '
|
||||
@ -508,3 +619,149 @@ class TestConductor(SqlTestCase):
|
||||
user_name=user_name,
|
||||
password=password)
|
||||
self.assertEqual('CREATED', self.vnf_package.onboarding_state)
|
||||
|
||||
def test_send_notification_not_found_vnfd(self):
|
||||
notification = {'vnfInstanceId': 'Test'}
|
||||
|
||||
result = self.conductor.send_notification(self.context, notification)
|
||||
|
||||
self.assertEqual(result, -2)
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
def test_send_notification_not_found_subscription(
|
||||
self,
|
||||
mock_vnf_lcm_subscriptions_get):
|
||||
|
||||
mock_vnf_lcm_subscriptions_get.return_value = None
|
||||
notification = {
|
||||
'vnfInstanceId': 'Test',
|
||||
'notificationType': 'VnfLcmOperationOccurrenceNotification'}
|
||||
|
||||
result = self.conductor.send_notification(self.context, notification)
|
||||
|
||||
self.assertEqual(result, -1)
|
||||
mock_vnf_lcm_subscriptions_get.assert_called()
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
@mock.patch('requests.post')
|
||||
def test_send_notification_vnf_lcm_operation_occurrence(
|
||||
self,
|
||||
mock_post,
|
||||
mock_vnf_lcm_subscriptions_get):
|
||||
|
||||
response = mock.Mock()
|
||||
response.status_code = 204
|
||||
mock_post.return_value = response
|
||||
|
||||
m_vnf_lcm_subscriptions = \
|
||||
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
||||
mock_vnf_lcm_subscriptions_get.return_value = \
|
||||
m_vnf_lcm_subscriptions
|
||||
notification = {
|
||||
'vnfInstanceId': 'Test',
|
||||
'notificationType': 'VnfLcmOperationOccurrenceNotification',
|
||||
'operationTypes': 'SCALE',
|
||||
'operationStates': 'RESULT',
|
||||
'_links': {}}
|
||||
|
||||
result = self.conductor.send_notification(self.context, notification)
|
||||
|
||||
self.assertEqual(result, 0)
|
||||
mock_vnf_lcm_subscriptions_get.assert_called()
|
||||
mock_post.assert_called()
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
@mock.patch('requests.post')
|
||||
def test_send_notification_vnf_identifier_creation(
|
||||
self,
|
||||
mock_post,
|
||||
mock_vnf_lcm_subscriptions_get):
|
||||
|
||||
response = mock.Mock()
|
||||
response.status_code = 204
|
||||
mock_post.return_value = response
|
||||
|
||||
m_vnf_lcm_subscriptions = \
|
||||
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
||||
mock_vnf_lcm_subscriptions_get.return_value = \
|
||||
m_vnf_lcm_subscriptions
|
||||
notification = {
|
||||
'vnfInstanceId': 'Test',
|
||||
'notificationType': 'VnfIdentifierCreationNotification',
|
||||
'links': {}}
|
||||
|
||||
result = self.conductor.send_notification(self.context, notification)
|
||||
|
||||
self.assertEqual(result, 0)
|
||||
mock_vnf_lcm_subscriptions_get.assert_called()
|
||||
mock_post.assert_called()
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
@mock.patch('requests.post')
|
||||
def test_send_notification_retry_notification(
|
||||
self,
|
||||
mock_post,
|
||||
mock_vnf_lcm_subscriptions_get):
|
||||
|
||||
response = mock.Mock()
|
||||
response.status_code = 400
|
||||
mock_post.return_value = response
|
||||
|
||||
m_vnf_lcm_subscriptions = \
|
||||
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
||||
mock_vnf_lcm_subscriptions_get.return_value = \
|
||||
m_vnf_lcm_subscriptions
|
||||
notification = {
|
||||
'vnfInstanceId': 'Test',
|
||||
'notificationType': 'VnfIdentifierCreationNotification',
|
||||
'links': {}}
|
||||
|
||||
result = self.conductor.send_notification(self.context, notification)
|
||||
|
||||
self.assertEqual(result, 0)
|
||||
mock_vnf_lcm_subscriptions_get.assert_called()
|
||||
mock_post.assert_called()
|
||||
self.assertEqual(mock_post.call_count, 3)
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
@mock.patch('requests.post')
|
||||
def test_send_notification_send_error(self,
|
||||
mock_post,
|
||||
mock_vnf_lcm_subscriptions_get):
|
||||
mock_post.side_effect = \
|
||||
requests.exceptions.HTTPError("MockException")
|
||||
m_vnf_lcm_subscriptions = \
|
||||
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
||||
mock_vnf_lcm_subscriptions_get.return_value = \
|
||||
m_vnf_lcm_subscriptions
|
||||
notification = {
|
||||
'vnfInstanceId': 'Test',
|
||||
'notificationType': 'VnfIdentifierCreationNotification',
|
||||
'links': {}}
|
||||
|
||||
result = self.conductor.send_notification(self.context, notification)
|
||||
|
||||
self.assertEqual(result, 0)
|
||||
mock_vnf_lcm_subscriptions_get.assert_called()
|
||||
mock_post.assert_called()
|
||||
self.assertEqual(mock_post.call_count, 1)
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
def test_send_notification_internal_server_error(self,
|
||||
mock_vnf_lcm_subscriptions_get):
|
||||
mock_vnf_lcm_subscriptions_get.side_effect = Exception(
|
||||
"MockException")
|
||||
notification = {
|
||||
'vnfInstanceId': 'Test',
|
||||
'notificationType': 'VnfIdentifierCreationNotification',
|
||||
'links': {}}
|
||||
|
||||
result = self.conductor.send_notification(self.context, notification)
|
||||
|
||||
self.assertEqual(result, -2)
|
||||
|
@ -178,6 +178,21 @@ def get_vnf_instance_data_with_id(vnfd_id):
|
||||
}
|
||||
|
||||
|
||||
def get_lcm_op_occs_data(vnf_instance_id):
|
||||
return {
|
||||
"tenant_id": uuidsentinel.tenant_id,
|
||||
'operation_state': 'PROCESSING',
|
||||
'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': vnf_instance_id,
|
||||
'operation': 'MODIFY_INFO',
|
||||
'is_automatic_invocation': 0,
|
||||
'is_cancel_pending': 0,
|
||||
}
|
||||
|
||||
|
||||
def fake_vnf_instance_model_dict(**updates):
|
||||
vnf_instance = {
|
||||
'deleted': False,
|
||||
@ -401,3 +416,17 @@ def vnf_instance_model_object(vnf_instance):
|
||||
vnf_instance_db_obj = models.VnfInstance()
|
||||
vnf_instance_db_obj.update(instance_dict)
|
||||
return vnf_instance_db_obj
|
||||
|
||||
|
||||
def get_changed_info_data():
|
||||
return {
|
||||
"vnf_instance_name": "",
|
||||
"vnf_instance_description": "",
|
||||
"vnf_configurable_properties": {"test": "test_value"},
|
||||
"vnfc_info_modifications_delete_ids": ["test1"],
|
||||
"vnfd_id": "2c69a161-0000-4b0f-bcf8-391f8fc76600",
|
||||
"vnf_provider": "NEC",
|
||||
"vnf_product_name": "MME",
|
||||
"vnf_software_version": "1.0",
|
||||
"vnfd_version": "MME_1.0"
|
||||
}
|
||||
|
92
tacker/tests/unit/objects/test_vnf_lcm_op_occs.py
Normal file
92
tacker/tests/unit/objects/test_vnf_lcm_op_occs.py
Normal file
@ -0,0 +1,92 @@
|
||||
# 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.
|
||||
|
||||
from tacker import context
|
||||
from tacker import objects
|
||||
from tacker.tests.unit.db.base import SqlTestCase
|
||||
from tacker.tests.unit.objects import fakes
|
||||
from tacker.tests import uuidsentinel
|
||||
|
||||
|
||||
class TestVnfLcmOpOcc(SqlTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestVnfLcmOpOcc, self).setUp()
|
||||
self.context = context.get_admin_context()
|
||||
self.vnf_package = self._create_vnf_package()
|
||||
self.vnf_package_vnfd = self._create_and_upload_vnf_package_vnfd()
|
||||
self.vnf_instance = self._create_vnf_instance()
|
||||
self.vnf_lcm_op_occs = self._create_vnf_lcm_op_occs()
|
||||
|
||||
def _create_vnf_package(self):
|
||||
vnfpkgm = objects.VnfPackage(context=self.context,
|
||||
**fakes.vnf_package_data)
|
||||
vnfpkgm.create()
|
||||
return vnfpkgm
|
||||
|
||||
def _create_and_upload_vnf_package_vnfd(self):
|
||||
vnf_package = objects.VnfPackage(context=self.context,
|
||||
**fakes.vnf_package_data)
|
||||
vnf_package.create()
|
||||
|
||||
vnf_pack_vnfd = fakes.get_vnf_package_vnfd_data(
|
||||
vnf_package.id, uuidsentinel.vnfd_id)
|
||||
|
||||
vnf_pack_vnfd_obj = objects.VnfPackageVnfd(
|
||||
context=self.context, **vnf_pack_vnfd)
|
||||
vnf_pack_vnfd_obj.create()
|
||||
|
||||
return vnf_pack_vnfd_obj
|
||||
|
||||
def _create_vnf_instance(self):
|
||||
vnf_instance_data = fakes.get_vnf_instance_data(
|
||||
self.vnf_package_vnfd.vnfd_id)
|
||||
vnf_instance = objects.VnfInstance(context=self.context,
|
||||
**vnf_instance_data)
|
||||
vnf_instance.create()
|
||||
|
||||
return vnf_instance
|
||||
|
||||
def _create_vnf_lcm_op_occs(self):
|
||||
vnf_lcm_op_occs_data = fakes.get_lcm_op_occs_data(self.vnf_instance.id)
|
||||
vnf_lcm_op_occs = objects.vnf_lcm_op_occs.VnfLcmOpOcc(
|
||||
context=self.context, **vnf_lcm_op_occs_data)
|
||||
vnf_lcm_op_occs.create()
|
||||
return vnf_lcm_op_occs
|
||||
|
||||
def test_create(self):
|
||||
vnf_lcm_op_occs_data = fakes.get_lcm_op_occs_data(self.vnf_instance.id)
|
||||
vnf_lcm_op_occs = objects.vnf_lcm_op_occs.VnfLcmOpOcc(
|
||||
context=self.context, **vnf_lcm_op_occs_data)
|
||||
vnf_lcm_op_occs.create()
|
||||
self.assertTrue(vnf_lcm_op_occs.vnf_instance_id)
|
||||
|
||||
def test_save(self):
|
||||
vnf_lcm_op_occs_data = fakes.get_lcm_op_occs_data(self.vnf_instance.id)
|
||||
vnf_lcm_op_occs = objects.vnf_lcm_op_occs.VnfLcmOpOcc(
|
||||
context=self.context, **vnf_lcm_op_occs_data)
|
||||
vnf_lcm_op_occs.create()
|
||||
|
||||
problem_obj = objects.vnf_lcm_op_occs.ProblemDetails()
|
||||
problem_obj.status = '500'
|
||||
problem_obj.detail = 'test_err'
|
||||
changed_info = objects.vnf_lcm_op_occs.VnfInfoModifications(
|
||||
context=self.context, **fakes.get_changed_info_data())
|
||||
vnf_lcm_op_occs.operation_state = 'FAILED_TEMP'
|
||||
vnf_lcm_op_occs.error = problem_obj
|
||||
vnf_lcm_op_occs.id = uuidsentinel.vnf_lcm_op_occs_id
|
||||
vnf_lcm_op_occs.changed_info = changed_info
|
||||
vnf_lcm_op_occs.save()
|
||||
|
||||
self.assertEqual('FAILED_TEMP', vnf_lcm_op_occs.operation_state)
|
||||
self.assertEqual(problem_obj, vnf_lcm_op_occs.error)
|
@ -15,6 +15,7 @@
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from six.moves import http_client
|
||||
import urllib
|
||||
@ -23,11 +24,15 @@ from webob import exc
|
||||
from tacker.api.vnflcm.v1 import controller
|
||||
from tacker.common import exceptions
|
||||
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.manager import TackerManager
|
||||
from tacker import objects
|
||||
from tacker.objects import fields
|
||||
from tacker.tests import constants
|
||||
from tacker.tests.unit import base
|
||||
from tacker.tests.unit.db import utils
|
||||
from tacker.tests.unit import fake_request
|
||||
import tacker.tests.unit.nfvo.test_nfvo_plugin as nfvo_plugin
|
||||
from tacker.tests.unit.vnflcm import fakes
|
||||
@ -72,6 +77,13 @@ class TestController(base.TestCase):
|
||||
'placement_attr': {'region': 'TestRegionOne'},
|
||||
'tenant': 'test'
|
||||
}
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
with mock.patch.object(tacker.db.vnfm.vnfm_db.VNFMPluginDb, 'get_vnfs',
|
||||
return_value=[]):
|
||||
with mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()}):
|
||||
self.controller = controller.VnfLcmController()
|
||||
|
||||
def tearDown(self):
|
||||
self.mock_manager.stop()
|
||||
@ -81,6 +93,17 @@ class TestController(base.TestCase):
|
||||
def app(self):
|
||||
return fakes.wsgi_app_v1()
|
||||
|
||||
def _get_dummy_vnf(self, vnf_id=None, status=None):
|
||||
vnf_dict = utils.get_dummy_vnf()
|
||||
|
||||
if status:
|
||||
vnf_dict['status'] = status
|
||||
|
||||
if vnf_id:
|
||||
vnf_dict['id'] = vnf_id
|
||||
|
||||
return vnf_dict
|
||||
|
||||
@mock.patch.object(objects.VnfInstance, 'save')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
|
||||
@ -125,7 +148,7 @@ class TestController(base.TestCase):
|
||||
instantiated_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||
**updates)
|
||||
location_header = ('http://localhost/vnflcm/v1/vnf_instances/%s'
|
||||
% resp.json['id'])
|
||||
% resp.json['id'])
|
||||
|
||||
self.assertEqual(expected_vnf, resp.json)
|
||||
self.assertEqual(location_header, resp.headers['location'])
|
||||
@ -171,12 +194,10 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.CREATED, resp.status_code)
|
||||
updates = {"vnfInstanceName": "SampleVnf",
|
||||
"vnfInstanceDescription": "SampleVnf Description"}
|
||||
expected_vnf = fakes.fake_vnf_instance_response(
|
||||
instantiated_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||
**updates)
|
||||
"vnfInstanceDescription": "SampleVnf Description"}
|
||||
expected_vnf = fakes.fake_vnf_instance_response(**updates)
|
||||
location_header = ('http://localhost/vnflcm/v1/vnf_instances/%s'
|
||||
% resp.json['id'])
|
||||
% resp.json['id'])
|
||||
|
||||
self.assertEqual(expected_vnf, resp.json)
|
||||
self.assertEqual(location_header, resp.headers['location'])
|
||||
@ -265,12 +286,12 @@ class TestController(base.TestCase):
|
||||
expected_message = ("Invalid input for field/attribute "
|
||||
"{attribute}. Value: {value}. {value} is not "
|
||||
"of type 'string'".
|
||||
format(value=value, attribute=attribute))
|
||||
format(value=value, attribute=attribute))
|
||||
elif expected_type in ["name_allow_zero_min_length", "description"]:
|
||||
expected_message = ("Invalid input for field/attribute "
|
||||
"{attribute}. " "Value: {value}. {value} is "
|
||||
"not of type 'string'".
|
||||
format(value=value, attribute=attribute))
|
||||
format(value=value, attribute=attribute))
|
||||
elif expected_type == 'object':
|
||||
expected_message = ("Invalid input for field/attribute "
|
||||
"{attribute}. " "Value: {value}. {value} is "
|
||||
@ -338,6 +359,12 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@ -347,7 +374,9 @@ class TestController(base.TestCase):
|
||||
def test_instantiate_with_deployment_flavour(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim):
|
||||
mock_vnf_instance_get_by_id, mock_get_vim,
|
||||
mock_get_vnf, mock_insta_notfi_process,
|
||||
mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -355,6 +384,10 @@ class TestController(base.TestCase):
|
||||
fakes.return_vnf_package_vnfd()
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "simple"}
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
@ -368,12 +401,18 @@ class TestController(base.TestCase):
|
||||
self.assertEqual(http_client.ACCEPTED, resp.status_code)
|
||||
mock_instantiate.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
def test_instantiate_with_non_existing_deployment_flavour(
|
||||
self, mock_vnf_package_get_by_id, mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id):
|
||||
self, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id, mock_get_vnf,
|
||||
mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -381,6 +420,10 @@ class TestController(base.TestCase):
|
||||
fakes.return_vnf_package_vnfd()
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "invalid"}
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
@ -393,8 +436,15 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("No flavour with id 'invalid'.",
|
||||
resp.json['badRequest']['message'])
|
||||
resp.json['badRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@ -404,7 +454,9 @@ class TestController(base.TestCase):
|
||||
def test_instantiate_with_instantiation_level(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim):
|
||||
mock_vnf_instance_get_by_id, mock_get_vim,
|
||||
mock_get_vnf, mock_insta_notif_process,
|
||||
mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -412,6 +464,10 @@ class TestController(base.TestCase):
|
||||
fakes.return_vnf_package_vnfd()
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "simple",
|
||||
"instantiationLevelId": "instantiation_level_1"}
|
||||
@ -425,7 +481,13 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.ACCEPTED, resp.status_code)
|
||||
mock_instantiate.assert_called_once()
|
||||
mock_get_vnf.assert_called_once()
|
||||
mock_insta_notif_process.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@ -435,7 +497,8 @@ class TestController(base.TestCase):
|
||||
def test_instantiate_with_no_inst_level_in_flavour(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim):
|
||||
mock_vnf_instance_get_by_id, mock_get_vim,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -444,6 +507,10 @@ class TestController(base.TestCase):
|
||||
vnf_package = fakes.return_vnf_package_with_deployment_flavour()
|
||||
vnf_package.vnf_deployment_flavours[0].instantiation_levels = None
|
||||
mock_vnf_package_get_by_id.return_value = vnf_package
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
# No instantiation level in deployment flavour but it's passed in the
|
||||
# request
|
||||
@ -459,8 +526,14 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("No instantiation level with id "
|
||||
"'instantiation_level_1'.", resp.json['badRequest']['message'])
|
||||
"'instantiation_level_1'.",
|
||||
resp.json['badRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
@ -468,7 +541,8 @@ class TestController(base.TestCase):
|
||||
def test_instantiate_with_non_existing_instantiation_level(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id):
|
||||
mock_vnf_instance_get_by_id, mock_get_vnf,
|
||||
mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -476,6 +550,10 @@ class TestController(base.TestCase):
|
||||
fakes.return_vnf_package_vnfd()
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "simple",
|
||||
"instantiationLevelId": "non-existing"}
|
||||
@ -489,8 +567,15 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("No instantiation level with id 'non-existing'.",
|
||||
resp.json['badRequest']['message'])
|
||||
resp.json['badRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.VnfLcmController.'
|
||||
'_notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@ -500,7 +585,9 @@ class TestController(base.TestCase):
|
||||
def test_instantiate_with_vim_connection(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim):
|
||||
mock_vnf_instance_get_by_id, mock_get_vim,
|
||||
mock_get_vnf, mock_insta_notif_process,
|
||||
mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -508,6 +595,10 @@ class TestController(base.TestCase):
|
||||
fakes.return_vnf_package_vnfd()
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "simple",
|
||||
"vimConnectionInfo": [
|
||||
@ -526,14 +617,22 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.ACCEPTED, resp.status_code)
|
||||
mock_instantiate.assert_called_once()
|
||||
mock_get_vnf.assert_called_once()
|
||||
mock_insta_notif_process.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
def test_instantiate_with_non_existing_vim(
|
||||
self, mock_vnf_package_get_by_id, mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim):
|
||||
self, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -542,6 +641,10 @@ class TestController(base.TestCase):
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vim.side_effect = nfvo.VimNotFoundException
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "simple",
|
||||
"vimConnectionInfo": [
|
||||
@ -559,15 +662,23 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("VimConnection id is not found: %s" %
|
||||
uuidsentinel.vim_id, resp.json['badRequest']['message'])
|
||||
uuidsentinel.vim_id,
|
||||
resp.json['badRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
def test_instantiate_with_non_existing_region_vim(
|
||||
self, mock_vnf_package_get_by_id, mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim):
|
||||
self, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -576,6 +687,10 @@ class TestController(base.TestCase):
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vim.side_effect = nfvo.VimRegionNotFoundException
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "simple",
|
||||
"vimConnectionInfo": [
|
||||
@ -594,15 +709,23 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("Region not found for the VimConnection: %s" %
|
||||
uuidsentinel.vim_id, resp.json['badRequest']['message'])
|
||||
uuidsentinel.vim_id,
|
||||
resp.json['badRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
def test_instantiate_with_default_vim_not_configured(
|
||||
self, mock_vnf_package_get_by_id, mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim):
|
||||
self, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id,
|
||||
mock_vnf_instance_get_by_id, mock_get_vim,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
|
||||
mock_vnf_instance_get_by_id.return_value =\
|
||||
fakes.return_vnf_instance_model()
|
||||
@ -611,6 +734,10 @@ class TestController(base.TestCase):
|
||||
mock_vnf_package_get_by_id.return_value = \
|
||||
fakes.return_vnf_package_with_deployment_flavour()
|
||||
mock_get_vim.side_effect = nfvo.VimDefaultNotDefined
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(
|
||||
vnf_id=mock_vnf_instance_get_by_id.return_value.id,
|
||||
status='INACTIVE')
|
||||
|
||||
body = {"flavourId": "simple"}
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
@ -623,10 +750,16 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("Default VIM is not defined.",
|
||||
resp.json['badRequest']['message'])
|
||||
resp.json['badRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
def test_instantiate_incorrect_instantiation_state(self, mock_vnf_by_id):
|
||||
def test_instantiate_incorrect_instantiation_state(self, mock_vnf_by_id,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
vnf_instance = fakes.return_vnf_instance_model()
|
||||
vnf_instance.instantiation_state = 'INSTANTIATED'
|
||||
mock_vnf_by_id.return_value = vnf_instance
|
||||
@ -642,8 +775,13 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.CONFLICT, resp.status_code)
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
def test_instantiate_incorrect_task_state(self, mock_vnf_by_id):
|
||||
def test_instantiate_incorrect_task_state(self, mock_vnf_by_id,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
vnf_instance = fakes.return_vnf_instance_model(
|
||||
task_state=fields.VnfInstanceTaskState.INSTANTIATING)
|
||||
mock_vnf_by_id.return_value = vnf_instance
|
||||
@ -661,7 +799,7 @@ class TestController(base.TestCase):
|
||||
expected_msg = ("Vnf instance %s in task_state INSTANTIATING. Cannot "
|
||||
"instantiate while the vnf instance is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
resp.json['conflictingRequest']['message'])
|
||||
|
||||
@ddt.data({'attribute': 'flavourId', 'value': 123,
|
||||
'expected_type': 'string'},
|
||||
@ -713,7 +851,7 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("'flavourId' is a required property",
|
||||
resp.json['badRequest']['message'])
|
||||
resp.json['badRequest']['message'])
|
||||
|
||||
def test_instantiate_invalid_request_parameter(self):
|
||||
body = {"flavourId": "simple"}
|
||||
@ -749,12 +887,17 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||
self.assertEqual(
|
||||
"Can not find requested vnf instance: %s" % constants.INVALID_UUID,
|
||||
"Can not find requested vnf: %s" % constants.INVALID_UUID,
|
||||
resp.json['itemNotFound']['message'])
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
def test_instantiate_with_non_existing_vnf_instance(
|
||||
self, mock_vnf_by_id):
|
||||
self, mock_vnf_by_id, mock_get_vnf,
|
||||
mock_get_service_plugins):
|
||||
mock_vnf_by_id.side_effect = exceptions.VnfInstanceNotFound
|
||||
body = {"flavourId": "simple"}
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
@ -770,6 +913,7 @@ class TestController(base.TestCase):
|
||||
self.assertEqual("Can not find requested vnf instance: %s" %
|
||||
uuidsentinel.vnf_instance_id,
|
||||
resp.json['itemNotFound']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@ddt.data('HEAD', 'PUT', 'DELETE', 'PATCH', 'GET')
|
||||
def test_instantiate_invalid_http_method(self, method):
|
||||
@ -813,17 +957,21 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||
self.assertEqual("Can not find requested vnf instance: %s" %
|
||||
uuidsentinel.vnf_instance_id,
|
||||
resp.json['itemNotFound']['message'])
|
||||
uuidsentinel.vnf_instance_id,
|
||||
resp.json['itemNotFound']['message'])
|
||||
|
||||
def test_show_with_invalid_uuid(self):
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
def test_show_with_invalid_uuid(self,
|
||||
mock_get_service_plugins):
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnf_instances/%s' % constants.INVALID_UUID)
|
||||
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||
self.assertEqual("Can not find requested vnf instance: %s" %
|
||||
constants.INVALID_UUID, resp.json['itemNotFound']['message'])
|
||||
constants.INVALID_UUID,
|
||||
resp.json['itemNotFound']['message'])
|
||||
|
||||
@ddt.data('PATCH', 'HEAD', 'PUT', 'POST')
|
||||
def test_show_invalid_http_method(self, http_method):
|
||||
@ -835,6 +983,12 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code)
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "terminate")
|
||||
@ -842,10 +996,15 @@ class TestController(base.TestCase):
|
||||
{'terminationType': 'GRACEFUL'},
|
||||
{'terminationType': 'GRACEFUL',
|
||||
'gracefulTerminationTimeout': 10})
|
||||
def test_terminate(self, body, mock_terminate, mock_save, mock_get_by_id):
|
||||
def test_terminate(self, body, mock_terminate, mock_save,
|
||||
mock_get_by_id, mock_get_vnf,
|
||||
mock_notification_process,
|
||||
mock_get_service_plugins):
|
||||
vnf_instance_obj = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED)
|
||||
mock_get_by_id.return_value = vnf_instance_obj
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(vnf_id=vnf_instance_obj.id, status='ACTIVE')
|
||||
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnf_instances/%s/terminate' % uuidsentinel.vnf_instance_id)
|
||||
@ -856,7 +1015,11 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.ACCEPTED, resp.status_code)
|
||||
mock_terminate.assert_called_once()
|
||||
mock_get_vnf.assert_called_once()
|
||||
mock_notification_process.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@ddt.data(
|
||||
{'attribute': 'terminationType', 'value': "TEST",
|
||||
'expected_type': 'enum'},
|
||||
@ -869,9 +1032,10 @@ class TestController(base.TestCase):
|
||||
{'attribute': 'gracefulTerminationTimeout', 'value': "test",
|
||||
'expected_type': 'integer'}
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_terminate_with_invalid_request_body(
|
||||
self, attribute, value, expected_type):
|
||||
self, values, mock_get_service_plugins):
|
||||
attribute = values['attribute']
|
||||
value = values['value']
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnf_instances/%s/terminate' % uuidsentinel.vnf_instance_id)
|
||||
body = {'terminationType': 'GRACEFUL',
|
||||
@ -882,7 +1046,8 @@ class TestController(base.TestCase):
|
||||
req.method = 'POST'
|
||||
|
||||
expected_message = ("Invalid input for field/attribute {attribute}. "
|
||||
"Value: {value}.".format(value=value, attribute=attribute))
|
||||
"Value: {value}.".
|
||||
format(value=value, attribute=attribute))
|
||||
|
||||
exception = self.assertRaises(exceptions.ValidationError,
|
||||
self.controller.terminate,
|
||||
@ -901,7 +1066,7 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
self.assertEqual("'terminationType' is a required property",
|
||||
resp.json['badRequest']['message'])
|
||||
resp.json['badRequest']['message'])
|
||||
|
||||
@ddt.data('GET', 'HEAD', 'PUT', 'DELETE', 'PATCH')
|
||||
def test_terminate_invalid_http_method(self, method):
|
||||
@ -916,8 +1081,13 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code)
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
def test_terminate_non_existing_vnf_instance(self, mock_vnf_by_id):
|
||||
def test_terminate_non_existing_vnf_instance(self, mock_vnf_by_id,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
body = {'terminationType': 'GRACEFUL',
|
||||
'gracefulTerminationTimeout': 10}
|
||||
mock_vnf_by_id.side_effect = exceptions.VnfInstanceNotFound
|
||||
@ -931,11 +1101,17 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||
self.assertEqual("Can not find requested vnf instance: %s" %
|
||||
uuidsentinel.vnf_instance_id,
|
||||
resp.json['itemNotFound']['message'])
|
||||
uuidsentinel.vnf_instance_id,
|
||||
resp.json['itemNotFound']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
def test_terminate_incorrect_instantiation_state(self, mock_vnf_by_id):
|
||||
def test_terminate_incorrect_instantiation_state(self, mock_vnf_by_id,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
mock_vnf_by_id.return_value = fakes.return_vnf_instance()
|
||||
body = {"terminationType": "FORCEFUL"}
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
@ -951,10 +1127,16 @@ class TestController(base.TestCase):
|
||||
"NOT_INSTANTIATED. Cannot terminate while the vnf "
|
||||
"instance is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
resp.json['conflictingRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
def test_terminate_incorrect_task_state(self, mock_vnf_by_id):
|
||||
def test_terminate_incorrect_task_state(self, mock_vnf_by_id,
|
||||
mock_get_vnf, mock_get_service_plugins):
|
||||
vnf_instance = fakes.return_vnf_instance(
|
||||
instantiated_state=fields.VnfInstanceState.INSTANTIATED,
|
||||
task_state=fields.VnfInstanceTaskState.TERMINATING)
|
||||
@ -973,17 +1155,28 @@ class TestController(base.TestCase):
|
||||
expected_msg = ("Vnf instance %s in task_state TERMINATING. Cannot "
|
||||
"terminate while the vnf instance is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
resp.json['conflictingRequest']['message'])
|
||||
mock_get_vnf.assert_called_once()
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "heal")
|
||||
@ddt.data({'cause': 'healing'}, {})
|
||||
def test_heal(self, body, mock_rpc_heal, mock_save,
|
||||
mock_vnf_by_id):
|
||||
mock_vnf_by_id, mock_get_vnf,
|
||||
mock_heal_notif_process,
|
||||
mock_get_service_plugins):
|
||||
vnf_instance_obj = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED)
|
||||
mock_vnf_by_id.return_value = vnf_instance_obj
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(vnf_id=vnf_instance_obj.id, status='ACTIVE')
|
||||
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnf_instances/%s/heal' % uuidsentinel.vnf_instance_id)
|
||||
@ -1007,8 +1200,15 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
def test_heal_incorrect_instantiated_state(self, mock_vnf_by_id):
|
||||
def test_heal_incorrect_instantiated_state(self, mock_vnf_by_id,
|
||||
mock_get_vnf, mock_notif, mock_get_service_plugins):
|
||||
vnf_instance_obj = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.NOT_INSTANTIATED)
|
||||
mock_vnf_by_id.return_value = vnf_instance_obj
|
||||
@ -1023,13 +1223,20 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.CONFLICT, resp.status_code)
|
||||
expected_msg = ("Vnf instance %s in instantiation_state "
|
||||
"NOT_INSTANTIATED. Cannot heal while the vnf instance "
|
||||
"is in this state.")
|
||||
"NOT_INSTANTIATED. Cannot heal while the vnf instance "
|
||||
"is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
resp.json['conflictingRequest']['message'])
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
def test_heal_incorrect_task_state(self, mock_vnf_by_id):
|
||||
def test_heal_incorrect_task_state(self, mock_vnf_by_id, mock_get_vnf,
|
||||
mock_notif, mock_get_service_plugins):
|
||||
vnf_instance_obj = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED,
|
||||
task_state=fields.VnfInstanceTaskState.HEALING)
|
||||
@ -1045,16 +1252,25 @@ class TestController(base.TestCase):
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.CONFLICT, resp.status_code)
|
||||
expected_msg = ("Vnf instance %s in task_state "
|
||||
"HEALING. Cannot heal while the vnf instance "
|
||||
"is in this state.")
|
||||
"HEALING. Cannot heal while the vnf instance "
|
||||
"is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
resp.json['conflictingRequest']['message'])
|
||||
|
||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||
return_value={'VNFM': FakeVNFMPlugin()})
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._notification_process')
|
||||
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||
'VnfLcmController._get_vnf')
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
def test_heal_with_invalid_vnfc_id(self, mock_vnf_by_id):
|
||||
def test_heal_with_invalid_vnfc_id(self, mock_vnf_by_id,
|
||||
mock_get_vnf, mock_notif, mock_get_service_plugins):
|
||||
vnf_instance_obj = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED)
|
||||
mock_vnf_by_id.return_value = vnf_instance_obj
|
||||
mock_get_vnf.return_value = \
|
||||
self._get_dummy_vnf(vnf_id=vnf_instance_obj.id, status='ACTIVE')
|
||||
|
||||
body = {'vnfcInstanceId': [uuidsentinel.vnfc_instance_id]}
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
@ -1067,7 +1283,8 @@ class TestController(base.TestCase):
|
||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||
expected_msg = "Vnfc id %s not present in vnf instance %s"
|
||||
self.assertEqual(expected_msg % (uuidsentinel.vnfc_instance_id,
|
||||
uuidsentinel.vnf_instance_id), resp.json['badRequest']['message'])
|
||||
uuidsentinel.vnf_instance_id),
|
||||
resp.json['badRequest']['message'])
|
||||
|
||||
@ddt.data('HEAD', 'PUT', 'DELETE', 'PATCH', 'GET')
|
||||
def test_heal_invalid_http_method(self, method):
|
||||
@ -1171,8 +1388,8 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||
self.assertEqual("Can not find requested vnf instance: %s" %
|
||||
uuidsentinel.vnf_instance_id,
|
||||
resp.json['itemNotFound']['message'])
|
||||
uuidsentinel.vnf_instance_id,
|
||||
resp.json['itemNotFound']['message'])
|
||||
|
||||
def test_delete_with_invalid_uuid(self):
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
@ -1184,8 +1401,8 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
|
||||
self.assertEqual("Can not find requested vnf instance: %s" %
|
||||
constants.INVALID_UUID,
|
||||
resp.json['itemNotFound']['message'])
|
||||
constants.INVALID_UUID,
|
||||
resp.json['itemNotFound']['message'])
|
||||
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
def test_delete_with_incorrect_instantiation_state(self, mock_vnf_by_id):
|
||||
@ -1202,10 +1419,10 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.CONFLICT, resp.status_code)
|
||||
expected_msg = ("Vnf instance %s in instantiation_state "
|
||||
"INSTANTIATED. Cannot delete while the vnf instance "
|
||||
"is in this state.")
|
||||
"INSTANTIATED. Cannot delete while the vnf instance "
|
||||
"is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
resp.json['conflictingRequest']['message'])
|
||||
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
def test_delete_with_incorrect_task_state(self, mock_vnf_by_id):
|
||||
@ -1223,10 +1440,10 @@ class TestController(base.TestCase):
|
||||
|
||||
self.assertEqual(http_client.CONFLICT, resp.status_code)
|
||||
expected_msg = ("Vnf instance %s in task_state ERROR. "
|
||||
"Cannot delete while the vnf instance "
|
||||
"is in this state.")
|
||||
"Cannot delete while the vnf instance "
|
||||
"is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
resp.json['conflictingRequest']['message'])
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
|
@ -12,13 +12,13 @@
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import fixtures
|
||||
import os
|
||||
import shutil
|
||||
from unittest import mock
|
||||
|
||||
import fixtures
|
||||
from oslo_config import cfg
|
||||
|
||||
from tacker.common import exceptions
|
||||
from tacker.common import utils
|
||||
from tacker import context
|
||||
@ -32,6 +32,14 @@ from tacker.vnflcm import vnflcm_driver
|
||||
from tacker.vnfm import vim_client
|
||||
|
||||
|
||||
OPTS_INFRA_DRIVER = [
|
||||
cfg.ListOpt(
|
||||
'infra_driver', default=['noop', 'openstack', 'kubernetes'],
|
||||
help=_('Hosting vnf drivers tacker plugin will use')),
|
||||
]
|
||||
cfg.CONF.register_opts(OPTS_INFRA_DRIVER, 'tacker')
|
||||
|
||||
|
||||
class InfraDriverException(Exception):
|
||||
pass
|
||||
|
||||
@ -256,7 +264,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
def test_instantiate_vnf_infra_fails_to_wait_after_instantiate(
|
||||
self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create):
|
||||
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
|
||||
mock_create):
|
||||
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
|
||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
||||
|
@ -76,6 +76,211 @@ def _get_vnfd_dict(context, vnfd_id, flavour_id):
|
||||
return vnfd_dict
|
||||
|
||||
|
||||
def _build_affected_resources(vnf_instance,
|
||||
change_type=fields.ResourceChangeType.ADDED):
|
||||
'''build affected resources from vnf_instance instantiated info '''
|
||||
|
||||
affected_resources = {}
|
||||
instantiated_vnf_info = vnf_instance.instantiated_vnf_info
|
||||
if hasattr(instantiated_vnf_info, 'instance_id'):
|
||||
if instantiated_vnf_info.instance_id:
|
||||
|
||||
affected_resources['affectedVnfcs'] = []
|
||||
affected_resources['affectedVirtualLinks'] = []
|
||||
affected_resources['affectedVirtualStorages'] = []
|
||||
|
||||
# build AffectedVnfc
|
||||
vnfc_resource_info = \
|
||||
instantiated_vnf_info.vnfc_resource_info
|
||||
for vnfc_resource in vnfc_resource_info:
|
||||
data = {}
|
||||
data['id'] = vnfc_resource.id
|
||||
data['vduId'] = vnfc_resource.vdu_id
|
||||
data['changeType'] = change_type
|
||||
data['computeResource'] = \
|
||||
vnfc_resource.compute_resource.to_dict()
|
||||
data['metadata'] = vnfc_resource.metadata
|
||||
affected_resources['affectedVnfcs'].append(data)
|
||||
|
||||
# build AffectedVirtualLink
|
||||
vnf_virtual_link = \
|
||||
instantiated_vnf_info.vnf_virtual_link_resource_info
|
||||
for vnf_vl_info in vnf_virtual_link:
|
||||
data = {}
|
||||
data['id'] = vnf_vl_info.id
|
||||
data['vnfVirtualLinkDescId'] = \
|
||||
vnf_vl_info.vnf_virtual_link_desc_id
|
||||
data['changeType'] = change_type
|
||||
data['networkResource'] = \
|
||||
vnf_vl_info.network_resource.to_dict()
|
||||
data['metadata'] = {}
|
||||
affected_resources['affectedVirtualLinks'].append(data)
|
||||
|
||||
# build affectedVirtualStorages
|
||||
virtual_storage = \
|
||||
instantiated_vnf_info.virtual_storage_resource_info
|
||||
for vnf_storage_info in virtual_storage:
|
||||
data = {}
|
||||
data['id'] = vnf_storage_info.id
|
||||
data['virtualStorageDescId'] = \
|
||||
vnf_storage_info.virtual_storage_desc_id
|
||||
data['changeType'] = change_type
|
||||
data['storageResource'] = \
|
||||
vnf_storage_info.storage_resource.to_dict()
|
||||
data['metadata'] = {}
|
||||
affected_resources['affectedVirtualStorages'].append(data)
|
||||
|
||||
return utils.convert_snakecase_to_camelcase(affected_resources)
|
||||
|
||||
|
||||
def _get_affected_resources(old_vnf_instance=None,
|
||||
new_vnf_instance=None, extra_list=None):
|
||||
'''get_affected_resources
|
||||
|
||||
returns affected resources in new_vnf_instance not present
|
||||
in old_vnf_instance.
|
||||
if extra_list (list of physical resource ids) is present,
|
||||
included to affected resources
|
||||
'''
|
||||
def _get_affected_cpids(affected_vnfc, vnf_instance):
|
||||
affected_cpids = []
|
||||
instantiated_vnf_info = vnf_instance.instantiated_vnf_info
|
||||
for vnfc_resource in instantiated_vnf_info.vnfc_resource_info:
|
||||
if vnfc_resource.id == affected_vnfc['id']:
|
||||
for vnfc_cp in vnfc_resource.vnfc_cp_info:
|
||||
if vnfc_cp.cpd_id:
|
||||
affected_cpids.append(vnfc_cp.cpd_id)
|
||||
if vnfc_cp.vnf_ext_cp_id:
|
||||
affected_cpids.append(vnfc_cp.vnf_ext_cp_id)
|
||||
return affected_cpids
|
||||
|
||||
def _get_added_storageids(affected_vnfc, vnf_instance):
|
||||
affected_storage_ids = []
|
||||
instantiated_vnf_info = vnf_instance.instantiated_vnf_info
|
||||
for vnfc_resource in instantiated_vnf_info.vnfc_resource_info:
|
||||
if vnfc_resource.id == affected_vnfc['id']:
|
||||
for storage_resource_id in vnfc_resource.storage_resource_ids:
|
||||
virtual_storage = \
|
||||
instantiated_vnf_info.virtual_storage_resource_info
|
||||
for virt_storage_res_info in virtual_storage:
|
||||
if virt_storage_res_info.id == storage_resource_id:
|
||||
affected_storage_ids.append(
|
||||
virt_storage_res_info.virtual_storage_desc_id)
|
||||
return affected_storage_ids
|
||||
|
||||
def diff_list(old_list, new_list):
|
||||
diff = []
|
||||
for item in new_list:
|
||||
if item not in old_list:
|
||||
diff.append(item)
|
||||
return diff
|
||||
|
||||
affected_resources = {}
|
||||
affected_resources['affectedVnfcs'] = []
|
||||
affected_resources['affectedVirtualLinks'] = []
|
||||
affected_resources['affectedVirtualStorages'] = []
|
||||
|
||||
if not old_vnf_instance:
|
||||
affected_resources = _build_affected_resources(
|
||||
new_vnf_instance, fields.ResourceChangeType.ADDED)
|
||||
# add affected cpids and add added storageids
|
||||
for affected_vnfc in affected_resources['affectedVnfcs']:
|
||||
affected_vnfc['affectedVnfcCpIds'] = _get_affected_cpids(
|
||||
affected_vnfc, new_vnf_instance)
|
||||
affected_vnfc['addedStorageResourceIds'] = _get_added_storageids(
|
||||
affected_vnfc, new_vnf_instance)
|
||||
|
||||
elif not new_vnf_instance:
|
||||
affected_resources = _build_affected_resources(old_vnf_instance,
|
||||
fields.ResourceChangeType.REMOVED)
|
||||
# add affected cpids and add remove storageids
|
||||
for affected_vnfc in affected_resources['affectedVnfcs']:
|
||||
affected_vnfc['affectedVnfcCpIds'] = _get_affected_cpids(
|
||||
affected_vnfc, old_vnf_instance)
|
||||
affected_vnfc['removedStorageResourceIds'] = _get_added_storageids(
|
||||
affected_vnfc, old_vnf_instance)
|
||||
elif old_vnf_instance and new_vnf_instance:
|
||||
old_affected_resources = _build_affected_resources(old_vnf_instance)
|
||||
new_affected_resources = _build_affected_resources(new_vnf_instance,
|
||||
fields.ResourceChangeType.MODIFIED)
|
||||
|
||||
# get resource_ids
|
||||
old_vnfc_resource_ids = []
|
||||
for vnfc_resource in old_affected_resources.get('affectedVnfcs', []):
|
||||
old_vnfc_resource_ids.append(
|
||||
vnfc_resource['computeResource']['resourceId'])
|
||||
|
||||
# remove extra_list items in old_vnfc_resource_ids
|
||||
# so that this items will be considered new
|
||||
if extra_list:
|
||||
for item in extra_list:
|
||||
if item in old_vnfc_resource_ids:
|
||||
index = old_vnfc_resource_ids.index(item)
|
||||
old_vnfc_resource_ids.pop(index)
|
||||
|
||||
new_vnfc_resource_ids = []
|
||||
for vnfc_resource in new_affected_resources.get('affectedVnfcs', []):
|
||||
resource_id = vnfc_resource['computeResource']['resourceId']
|
||||
new_vnfc_resource_ids.append(resource_id)
|
||||
|
||||
old_vnf_vl_resource_ids = []
|
||||
for vnf_vl_info in old_affected_resources.get(
|
||||
'affectedVirtualLinks', []):
|
||||
resource_id = vnf_vl_info['networkResource']['resourceId']
|
||||
old_vnf_vl_resource_ids.append(resource_id)
|
||||
|
||||
new_vnf_vl_resource_ids = []
|
||||
for vnf_vl_info in new_affected_resources.get(
|
||||
'affectedVirtualLinks', []):
|
||||
resource_id = vnf_vl_info['networkResource']['resourceId']
|
||||
new_vnf_vl_resource_ids.append(resource_id)
|
||||
|
||||
old_vnf_storage_resource_ids = []
|
||||
for vnf_storage_info in old_affected_resources.get(
|
||||
'affectedVirtualStorages', []):
|
||||
resource_id = vnf_storage_info['storageResource']['resourceId']
|
||||
old_vnf_storage_resource_ids.append(resource_id)
|
||||
|
||||
new_vnf_storage_resource_ids = []
|
||||
for vnf_storage_info in new_affected_resources.get(
|
||||
'affectedVirtualStorages', []):
|
||||
resource_id = vnf_storage_info['storageResource']['resourceId']
|
||||
new_vnf_storage_resource_ids.append(resource_id)
|
||||
|
||||
# get difference between resource_ids
|
||||
vnfc_resource_ids = diff_list(old_vnfc_resource_ids,
|
||||
new_vnfc_resource_ids)
|
||||
vnf_vl_resource_ids = diff_list(old_vnf_vl_resource_ids,
|
||||
new_vnf_vl_resource_ids)
|
||||
vnf_storage_resource_ids = diff_list(old_vnf_storage_resource_ids,
|
||||
new_vnf_storage_resource_ids)
|
||||
|
||||
# return new affected resources
|
||||
for affected_vls in new_affected_resources['affectedVirtualLinks']:
|
||||
if (affected_vls['networkResource']
|
||||
['resourceId'] in vnf_vl_resource_ids):
|
||||
affected_resources['affectedVirtualLinks'].append(affected_vls)
|
||||
|
||||
affected_storages = new_affected_resources['affectedVirtualStorages']
|
||||
for affected_storage in affected_storages:
|
||||
if (affected_storage['storageResource']
|
||||
['resourceId'] in vnf_storage_resource_ids):
|
||||
affected_resources['affectedVirtualStorages'].append(
|
||||
affected_storage)
|
||||
|
||||
for affected_vnfc in new_affected_resources['affectedVnfcs']:
|
||||
if (affected_vnfc['computeResource']
|
||||
['resourceId'] in vnfc_resource_ids):
|
||||
|
||||
# update affected affectedVnfcCpIds
|
||||
affected_vnfc['affectedVnfcCpIds'] = _get_affected_cpids(
|
||||
affected_vnfc, new_vnf_instance)
|
||||
|
||||
affected_resources['affectedVnfcs'].append(affected_vnfc)
|
||||
|
||||
return affected_resources
|
||||
|
||||
|
||||
def _get_vnf_package_id(context, vnfd_id):
|
||||
vnf_package = objects.VnfPackageVnfd.get_by_id(context, vnfd_id)
|
||||
return vnf_package.package_uuid
|
||||
|
@ -28,6 +28,8 @@ import time
|
||||
import eventlet.wsgi
|
||||
# eventlet.patcher.monkey_patch(all=False, socket=True, thread=True)
|
||||
from oslo_config import cfg
|
||||
import tacker.conf
|
||||
|
||||
import oslo_i18n as i18n
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
@ -75,7 +77,7 @@ socket_opts = [
|
||||
"the server securely")),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF = tacker.conf.CONF
|
||||
CONF.register_opts(socket_opts)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user