Merge "Enhancement of get VNF LCM operation occurrence"
This commit is contained in:
commit
b01e9f5d3a
|
@ -0,0 +1,82 @@
|
|||
[
|
||||
{
|
||||
"id": "d85c6ae4-af16-42c0-96fc-82f7c014c468",
|
||||
"operationState": "COMPLETED",
|
||||
"stateEnteredTime": "2020-08-02T06:50:50.883373",
|
||||
"startTime": "2020-08-02T06:41:34.883483",
|
||||
"vnfInstanceId": "0b7b95a9-21d5-4ac4-80c8-9ae9f7323787",
|
||||
"grantId": "3432cebe-db0a-11e8-9023-005056317abe",
|
||||
"operation": "INSTANTIATE",
|
||||
"isAutomaticInvocation": false,
|
||||
"operationParams": "{
|
||||
'flavourId': 'default',
|
||||
'instantiationLevelId': 'vnf-min',
|
||||
}",
|
||||
"isCancelPending": false,
|
||||
"resourceChanges": {
|
||||
"affectedVnfcs": [
|
||||
{
|
||||
"id": "36e24439-829c-4803-a413-385cd658d544",
|
||||
"vduId": "VDU",
|
||||
"changeType": "ADDED",
|
||||
"computeResource": {
|
||||
"vimConnectionId": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resourceId": "e0510ba9-3a53-4fcf-9dcc-58dea5c048b0",
|
||||
"vimLevelResourceType": "OS::Nova::Server",
|
||||
},
|
||||
"affectedVnfcCpIds": [
|
||||
"VDU1_CP0",
|
||||
"VDU1_CP1"
|
||||
],
|
||||
"addedStorageResourceIds": [
|
||||
"81ae44f6-b65b-47aa-a578-e53b7a50a574"
|
||||
]
|
||||
}
|
||||
],
|
||||
"affectedVirtualLinks": [
|
||||
{
|
||||
"id": "9836f7f2-5af4-4df5-a89f-933479448ef7",
|
||||
"vnfVirtualLinkDescId": "internalNW",
|
||||
"changeType": "ADDED",
|
||||
"networkResource": {
|
||||
"vimConnectionId": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resourceId": "400692e5-b2db-478e-acb1-b77a92635ec6",
|
||||
"vimLevelResourceType": "OS::Neutron::Net"
|
||||
}
|
||||
}
|
||||
],
|
||||
"affectedVirtualStorages": [
|
||||
{
|
||||
"id": "81ae44f6-b65b-47aa-a578-e53b7a50a574",
|
||||
"virtualStorageDescId": "Storage",
|
||||
"changeType": "ADDED",
|
||||
"storageResource": {
|
||||
"vimConnectionId": "f26f181d-7891-4720-b022-b074ec1733ef",
|
||||
"resourceId": "842f527e-0092-4f11-aede-f981ba4fd884",
|
||||
"vimLevelResourceType": "OS::Cinder::Volume"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "http://sample.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468"
|
||||
},
|
||||
"vnfInstance": {
|
||||
"href": "http://sample.com/vnflcm/v1/vnf_instances/0b7b95a9-21d5-4ac4-80c8-9ae9f7323787"
|
||||
},
|
||||
"grant":{
|
||||
"href":"http://sample.com/grant/v1/grants/3432cebe-db0a-11e8-9023-005056317abe"
|
||||
},
|
||||
"retry":{
|
||||
"href":"http://sample1.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468/retry"
|
||||
},
|
||||
"rollback":{
|
||||
"href":"http://sample1.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468/rollback"
|
||||
},
|
||||
"fail":{
|
||||
"href":"http://sample1.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468/fail"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
|
@ -4,6 +4,7 @@
|
|||
"stateEnteredTime": "2020-08-02T06:50:50.883373",
|
||||
"startTime": "2020-08-02T06:41:34.883483",
|
||||
"vnfInstanceId": "0b7b95a9-21d5-4ac4-80c8-9ae9f7323787",
|
||||
"grantId": "3432cebe-db0a-11e8-9023-005056317abe",
|
||||
"operation": "INSTANTIATE",
|
||||
"isAutomaticInvocation": false,
|
||||
"operationParams": "{
|
||||
|
@ -65,6 +66,15 @@
|
|||
},
|
||||
"grant": {
|
||||
"href": "/grant/v1/grants/3432cebe-db0a-11e8-9023-005056317abe"
|
||||
},
|
||||
"retry":{
|
||||
"href":"http://sample1.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468/retry"
|
||||
},
|
||||
"rollback":{
|
||||
"href":"http://sample1.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468/rollback"
|
||||
},
|
||||
"fail":{
|
||||
"href":"http://sample1.com/vnflcm/v1/vnf_lcm_op_occs/d85c6ae4-af16-42c0-96fc-82f7c014c468/fail"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -712,6 +712,116 @@ Response Parameters
|
|||
- stateEnteredTime: state_entered_time
|
||||
- startTime: start_time
|
||||
- vnfInstanceId: vnf_lcm_vnf_instance_id
|
||||
- grantId: grant_id
|
||||
- operation: operation
|
||||
- isAutomaticInvocation: is_automatic_invocation
|
||||
- operationParams: operation_params
|
||||
- isCancelPending: is_cancel_pending
|
||||
- error: error
|
||||
- title: error_title
|
||||
- status: error_status
|
||||
- detail: error_detail
|
||||
- resourceChanges: resource_changes
|
||||
- affectedVnfcs: affected_vnfcs
|
||||
- id: affected_vnfcs_id
|
||||
- vduId: affected_vnfcs_vdu_id
|
||||
- changeType: affected_vnfcs_change_type
|
||||
- computeResource: vnfc_resource_info_compute_resource
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- affectedVnfcCpIds: affected_vnfc_cp_ids
|
||||
- addedStorageResourceIds: added_storage_resource_ids
|
||||
- removedStorageResourceIds: removed_storage_resource_ids
|
||||
- affectedVirtualLinks: affected_virtual_links
|
||||
- id: affected_virtual_links_id
|
||||
- vnfVirtualLinkDescId: vnf_virtual_link_resource_info_vnf_virtual_link_desc_id
|
||||
- changeType: affected_virtual_links_change_type
|
||||
- networkResource: vnf_virtual_link_resource_info_network_resource
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- affectedVirtualStorages: affected_virtual_storages
|
||||
- id: affected_virtual_storages_id
|
||||
- virtualStorageDescId: affected_virtual_storages_virtual_storage_desc_id
|
||||
- changeType: affected_virtual_storages_change_type
|
||||
- storageResource: virtual_storage_resource_info_storage_resource
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- changedInfo: changed_info
|
||||
- vnfInstanceName: changed_info_vnf_instance_name
|
||||
- vnfInstanceDescription: changed_info_vnf_instance_description
|
||||
- metadata: changed_info_metadata
|
||||
- vimConnectionInfo: changed_info_vim_connection_info
|
||||
- id: vim_connection_info_id
|
||||
- vimId: vim_connection_info_vim_id
|
||||
- vimType: vim_connection_info_vim_type
|
||||
- interfaceInfo: vim_connection_info_interface_info
|
||||
- endpoint: vim_connection_info_interface_info_endpoint
|
||||
- accessInfo: vim_connection_info_access_info
|
||||
- username: vim_connection_info_access_info_username
|
||||
- region: vim_connection_info_access_info_region
|
||||
- password: vim_connection_info_access_info_password
|
||||
- tenant: vim_connection_info_access_info_tenant
|
||||
- vnfPkgId: changed_info_vnf_pkg_id
|
||||
- vnfdId: changed_info_vnfd_id
|
||||
- vnfProvider: changed_info_vnf_provider
|
||||
- vnfProductName: changed_info_vnf_product_name
|
||||
- vnfSotwareVersion: changed_info_vnf_sotware_version
|
||||
- vnfdVersion: changed_info_vnfd_version
|
||||
- changedExtConnectivity: changed_ext_connectivity
|
||||
- id: changed_ext_connectivity_id
|
||||
- resourceHandle: resource_handle
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- extLinkPorts: ext_link_ports
|
||||
- id: ext_link_port_id
|
||||
- resourceHandle: resource_handle
|
||||
- vimConnectionId: vim_connection_id
|
||||
- resourceId: resource_handle_resource_id
|
||||
- vimLevelResourceType: resource_handle_vim_level_resource_type
|
||||
- cpInstanceId: cp_instance_id
|
||||
- _links: vnf_instance_links
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: samples/vnflcm/show-vnflcm-operation-occurrence-response.json
|
||||
:language: javascript
|
||||
|
||||
List VNF LCM operation occurrence
|
||||
=================================
|
||||
|
||||
.. rest_method:: GET /vnflcm/v1/vnf_lcm_op_occs
|
||||
|
||||
The API consumer can use this method to query status information about multiple VNF lifecycle management operation
|
||||
occurrences.
|
||||
|
||||
Response Codes
|
||||
--------------
|
||||
|
||||
.. rest_status_code:: success status.yaml
|
||||
|
||||
- 200
|
||||
|
||||
.. rest_status_code:: error status.yaml
|
||||
|
||||
- 400
|
||||
- 403
|
||||
|
||||
Response Parameters
|
||||
-------------------
|
||||
|
||||
.. rest_parameters:: parameters_vnflcm.yaml
|
||||
|
||||
- id: vnf_lcm_op_occ_id_response
|
||||
- operationState: operation_state
|
||||
- stateEnteredTime: state_entered_time
|
||||
- startTime: start_time
|
||||
- vnfInstanceId: vnf_lcm_vnf_instance_id
|
||||
- grantId: grant_id
|
||||
- operation: operation
|
||||
- isAutomaticInvocation: is_automatic_invocation
|
||||
- operationParams: operation_params
|
||||
|
@ -774,7 +884,7 @@ Response Parameters
|
|||
Response Example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: samples/vnflcm/show-vnflcm-operation-occurrence-response.json
|
||||
.. literalinclude:: samples/vnflcm/list-vnflcm-operation-occurrence-response.json
|
||||
:language: javascript
|
||||
|
||||
Roll back a VNF lifecycle operation
|
||||
|
|
|
@ -163,6 +163,18 @@ def _parse_filter(filter_rule):
|
|||
try:
|
||||
tokens = filter_rule.split(',')
|
||||
filter_type = None
|
||||
|
||||
# TODO(esto-aln): This condition and the lines below will be removed
|
||||
# if JSON will be supported via OR Mapping. Currently this condition
|
||||
# allows support of JSON strings '"{...}"' for filtering
|
||||
if (tokens[2].startswith("'\"{") and
|
||||
tokens[len(tokens) - 1].endswith("}\"'")):
|
||||
tokens[2] = ','.join(tokens[2:])
|
||||
|
||||
# retain first 3 indices and remove the rest
|
||||
# to process as string
|
||||
tokens = tokens[0:3]
|
||||
|
||||
if len(tokens) >= 3:
|
||||
if tokens[0] in _filters.SUPPORTED_OP_ONE:
|
||||
filter_type = 'simple_filter_expr_one'
|
||||
|
|
|
@ -89,6 +89,8 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
|
||||
return vim_connections
|
||||
|
||||
# TODO(esto-aln): This method will be transferred to
|
||||
# tacker/api/views/vnf_lcm_op_occs.py in the future
|
||||
def _get_lcm_op_occs_links(self, vnf_lcm_op_occs):
|
||||
_links = {
|
||||
"self": {
|
||||
|
@ -101,6 +103,12 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.vnf_instance_id}
|
||||
},
|
||||
"retry": {
|
||||
"href":
|
||||
'%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/retry'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"rollback": {
|
||||
"href":
|
||||
'%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/rollback'
|
||||
|
@ -111,6 +119,12 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
"href": '%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/grant'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"fail": {
|
||||
"href":
|
||||
'%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/fail'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,11 +143,13 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
vnf_instance_dict.update(links)
|
||||
return vnf_instance_dict
|
||||
|
||||
# TODO(esto-aln): This method will be transferred to
|
||||
# tacker/api/views/vnf_lcm_op_occs.py in the future
|
||||
def _get_vnf_lcm_op_occs(self, vnf_lcm_op_occs):
|
||||
vnf_lcm_op_occs_dict = vnf_lcm_op_occs.to_dict()
|
||||
vnf_lcm_op_occs_dict.pop('error_point')
|
||||
vnf_lcm_op_occs_dict = utils.convert_snakecase_to_camelcase(
|
||||
vnf_lcm_op_occs_dict)
|
||||
vnf_lcm_op_occs_dict.pop('errorPoint')
|
||||
|
||||
links = self._get_lcm_op_occs_links(vnf_lcm_op_occs)
|
||||
|
||||
|
@ -257,5 +273,7 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||
def subscription_show(self, vnf_lcm_subscriptions):
|
||||
return self._get_vnf_lcm_subscription(vnf_lcm_subscriptions)
|
||||
|
||||
# TODO(esto-aln): This method will be transferred to
|
||||
# tacker/api/views/vnf_lcm_op_occs.py in the future
|
||||
def show_lcm_op_occs(self, vnf_lcm_op_occs):
|
||||
return self._get_vnf_lcm_op_occs(vnf_lcm_op_occs)
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
# 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 oslo_log import log as logging
|
||||
|
||||
from tacker.api import views as base
|
||||
from tacker.common import utils
|
||||
import tacker.conf
|
||||
from tacker.objects import vnf_lcm_op_occs as _vnf_lcm_op_occs
|
||||
|
||||
CONF = tacker.conf.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ViewBuilder(base.BaseViewBuilder):
|
||||
|
||||
FLATTEN_ATTRIBUTES = _vnf_lcm_op_occs.VnfLcmOpOcc.FLATTEN_ATTRIBUTES
|
||||
COMPLEX_ATTRIBUTES = _vnf_lcm_op_occs.VnfLcmOpOcc.COMPLEX_ATTRIBUTES
|
||||
FLATTEN_COMPLEX_ATTRIBUTES = [key for key in FLATTEN_ATTRIBUTES.keys()
|
||||
if '/' in key]
|
||||
|
||||
def _get_lcm_op_occs_links(self, vnf_lcm_op_occs):
|
||||
_links = {
|
||||
"self": {
|
||||
"href": '%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"vnfInstance": {
|
||||
"href": '%(endpoint)s/vnflcm/v1/vnf_instances/%(id)s'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.vnf_instance_id}
|
||||
},
|
||||
"retry": {
|
||||
"href":
|
||||
'%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/retry'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"rollback": {
|
||||
"href":
|
||||
'%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/rollback'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"grant": {
|
||||
"href": '%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/grant'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
},
|
||||
"fail": {
|
||||
"href":
|
||||
'%(endpoint)s/vnflcm/v1/vnf_lcm_op_occs/%(id)s/fail'
|
||||
% {"endpoint": CONF.vnf_lcm.endpoint_url,
|
||||
"id": vnf_lcm_op_occs.id}
|
||||
}
|
||||
}
|
||||
|
||||
return {"_links": _links}
|
||||
|
||||
def _get_vnf_lcm_op_occs_list(self, vnf_lcm_op_occs, include_fields=None):
|
||||
vnf_lcm_op_occs_dict = vnf_lcm_op_occs.to_dict(
|
||||
include_fields=include_fields)
|
||||
|
||||
vnf_lcm_op_occs_dict = utils.convert_snakecase_to_camelcase(
|
||||
vnf_lcm_op_occs_dict)
|
||||
vnf_lcm_op_occs_dict.pop('errorPoint', None)
|
||||
|
||||
links = self._get_lcm_op_occs_links(vnf_lcm_op_occs)
|
||||
|
||||
vnf_lcm_op_occs_dict.update(links)
|
||||
return vnf_lcm_op_occs_dict
|
||||
|
||||
def index(self, request, vnf_lcm_op_occs, all_fields=True,
|
||||
exclude_fields=None, fields=None, exclude_default=False):
|
||||
|
||||
# Find out which fields are to be returned in the response.
|
||||
if all_fields:
|
||||
include_fields = set(self.FLATTEN_ATTRIBUTES.keys())
|
||||
if fields:
|
||||
fields = set(fields.split(','))
|
||||
attributes = set(self.COMPLEX_ATTRIBUTES).intersection(fields)
|
||||
for attribute in attributes:
|
||||
add_fields = set([key for key in self.FLATTEN_ATTRIBUTES.
|
||||
keys() if key.startswith(attribute)])
|
||||
fields = fields.union(add_fields)
|
||||
|
||||
include_fields = set(
|
||||
_vnf_lcm_op_occs.VnfLcmOpOcc.SIMPLE_ATTRIBUTES).union(fields)
|
||||
elif exclude_default:
|
||||
include_fields = set(
|
||||
_vnf_lcm_op_occs.VnfLcmOpOcc.SIMPLE_ATTRIBUTES)
|
||||
elif exclude_fields:
|
||||
exclude_fields = set(exclude_fields.split(','))
|
||||
exclude_additional_attributes = set(
|
||||
self.COMPLEX_ATTRIBUTES).intersection(exclude_fields)
|
||||
for attribute in exclude_additional_attributes:
|
||||
fields = set([key for key in self.FLATTEN_ATTRIBUTES.keys()
|
||||
if key.startswith(attribute)])
|
||||
exclude_fields = exclude_fields.union(fields)
|
||||
|
||||
include_fields = set(self.FLATTEN_ATTRIBUTES.keys()) - \
|
||||
exclude_fields
|
||||
|
||||
return [
|
||||
self._get_vnf_lcm_op_occs_list(
|
||||
vnf_lcm_op_occ, include_fields=include_fields)
|
||||
for vnf_lcm_op_occ in vnf_lcm_op_occs]
|
|
@ -42,6 +42,7 @@ from tacker._i18n import _
|
|||
from tacker.api.schemas import vnf_lcm
|
||||
from tacker.api import validation
|
||||
from tacker.api.views import vnf_lcm as vnf_lcm_view
|
||||
from tacker.api.views import vnf_lcm_op_occs as vnf_op_occs_view
|
||||
from tacker.api.vnflcm.v1 import sync_resource
|
||||
from tacker.common import exceptions
|
||||
from tacker.common import utils
|
||||
|
@ -52,6 +53,7 @@ from tacker.extensions import vnfm
|
|||
from tacker import manager
|
||||
from tacker import objects
|
||||
from tacker.objects import fields
|
||||
from tacker.objects import vnf_lcm_op_occs as vnf_lcm_op_occs_obj
|
||||
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
|
||||
|
@ -185,6 +187,7 @@ class VnfLcmController(wsgi.Controller):
|
|||
super(VnfLcmController, self).__init__()
|
||||
self.rpc_api = vnf_lcm_rpc.VNFLcmRPCAPI()
|
||||
self._vnfm_plugin = manager.TackerManager.get_service_plugins()['VNFM']
|
||||
self._view_builder_op_occ = vnf_op_occs_view.ViewBuilder()
|
||||
|
||||
def _get_vnf_instance_href(self, vnf_instance):
|
||||
return '/vnflcm/v1/vnf_instances/%s' % vnf_instance.id
|
||||
|
@ -1503,6 +1506,40 @@ class VnfLcmController(wsgi.Controller):
|
|||
return self._make_problem_detail(error_msg,
|
||||
500, title='Internal Server Error')
|
||||
|
||||
@wsgi.response(http_client.OK)
|
||||
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.BAD_REQUEST))
|
||||
def list_lcm_op_occs(self, request):
|
||||
context = request.environ['tacker.context']
|
||||
context.can(vnf_lcm_policies.VNFLCM % 'list_lcm_op_occs')
|
||||
|
||||
all_fields = request.GET.get('all_fields')
|
||||
exclude_default = request.GET.get('exclude_default')
|
||||
fields = request.GET.get('fields')
|
||||
exclude_fields = request.GET.get('exclude_fields')
|
||||
filters = request.GET.get('filter')
|
||||
if not (all_fields or fields or exclude_fields):
|
||||
exclude_default = True
|
||||
|
||||
self._view_builder_op_occ.validate_attribute_fields(
|
||||
all_fields=all_fields, fields=fields,
|
||||
exclude_fields=exclude_fields,
|
||||
exclude_default=exclude_default)
|
||||
|
||||
filters = self._view_builder_op_occ.validate_filter(filters)
|
||||
|
||||
try:
|
||||
vnf_lcm_op_occs = \
|
||||
vnf_lcm_op_occs_obj.VnfLcmOpOccList.get_by_filters(
|
||||
request.context, read_deleted='no', filters=filters)
|
||||
except Exception as e:
|
||||
LOG.exception(traceback.format_exc())
|
||||
return self._make_problem_detail(
|
||||
str(e), 500, title='Internal Server Error')
|
||||
|
||||
return self._view_builder_op_occ.index(request, vnf_lcm_op_occs,
|
||||
all_fields=all_fields, exclude_fields=exclude_fields,
|
||||
fields=fields, exclude_default=exclude_default)
|
||||
|
||||
def _make_problem_detail(
|
||||
self,
|
||||
detail,
|
||||
|
|
|
@ -138,3 +138,15 @@ class VnflcmAPIRouter(wsgi.Router):
|
|||
methods = {"GET": "subscription_show", "DELETE": "delete_subscription"}
|
||||
self._setup_route(mapper, "/subscriptions/{subscriptionId}",
|
||||
methods, controller, default_resource)
|
||||
|
||||
# {apiRoot}/vnflcm/v1/vnf_lcm_op_occs/{vnfLcmOpOccId}/retry resource
|
||||
methods = {"POST": "retry"}
|
||||
self._setup_route(mapper,
|
||||
"/vnf_lcm_op_occs/{id}/retry",
|
||||
methods, controller, default_resource)
|
||||
|
||||
# Allowed methods on
|
||||
# {apiRoot}/vnflcm/v1/vnf_lcm_op_occs resource
|
||||
methods = {"GET": "list_lcm_op_occs"}
|
||||
self._setup_route(mapper, "/vnf_lcm_op_occs",
|
||||
methods, controller, default_resource)
|
||||
|
|
|
@ -305,6 +305,7 @@ class VnfLcmOpOccs(model_base.BASE, models.SoftDeleteMixin,
|
|||
vnf_instance_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('vnf_instances.id'),
|
||||
nullable=False)
|
||||
grant_id = sa.Column(sa.String(36), nullable=True)
|
||||
state_entered_time = sa.Column(sa.DateTime(), nullable=False)
|
||||
start_time = sa.Column(sa.DateTime(), nullable=False)
|
||||
operation_state = sa.Column(sa.String(length=255), nullable=False)
|
||||
|
@ -315,6 +316,7 @@ class VnfLcmOpOccs(model_base.BASE, models.SoftDeleteMixin,
|
|||
error = sa.Column(sa.JSON(), nullable=True)
|
||||
resource_changes = sa.Column(sa.JSON(), nullable=True)
|
||||
changed_info = sa.Column(sa.JSON(), nullable=True)
|
||||
changed_ext_connectivity = sa.Column(sa.JSON(), nullable=True)
|
||||
error_point = sa.Column(sa.Integer, nullable=False)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
# flake8: noqa: E402
|
||||
|
||||
"""add_column_to_vnf_lcm_op_occs
|
||||
|
||||
Revision ID: 3adac34764da
|
||||
Revises: 62d18199909e
|
||||
Create Date: 2021-02-16 16:19:12.100380
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '3adac34764da'
|
||||
down_revision = '7186440a306b'
|
||||
|
||||
from alembic import op
|
||||
|
||||
import sqlalchemy as sa
|
||||
from tacker.db import migration
|
||||
|
||||
|
||||
def upgrade(active_plugins=None, options=None):
|
||||
op.add_column('vnf_lcm_op_occs',
|
||||
sa.Column('grant_id', sa.VARCHAR(length=36), nullable=True))
|
||||
op.add_column('vnf_lcm_op_occs',
|
||||
sa.Column('changed_ext_connectivity', sa.JSON(), nullable=True))
|
|
@ -1 +1 @@
|
|||
7186440a306b
|
||||
3adac34764da
|
||||
|
|
|
@ -225,8 +225,7 @@ class LcmOccsOperationState(BaseTackerEnum):
|
|||
FAILED_TEMP = 'FAILED_TEMP'
|
||||
FAILED = 'FAILED'
|
||||
|
||||
ALL = (STARTING, PROCESSING, COMPLETED,
|
||||
FAILED_TEMP, FAILED)
|
||||
ALL = (STARTING, PROCESSING, COMPLETED, FAILED_TEMP, FAILED)
|
||||
|
||||
|
||||
class LcmOccsOperationType(BaseTackerEnum):
|
||||
|
|
|
@ -15,10 +15,13 @@ from datetime import datetime
|
|||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
from oslo_versionedobjects import base as ovoo_base
|
||||
from sqlalchemy import exc
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy_filters import apply_filters
|
||||
|
||||
from tacker.common import exceptions
|
||||
from tacker.common import utils
|
||||
from tacker.db import api as db_api
|
||||
from tacker.db.db_sqlalchemy import api
|
||||
from tacker.db.db_sqlalchemy import models
|
||||
|
@ -55,11 +58,34 @@ def _vnf_lcm_op_occ_update(context, values):
|
|||
if values.changed_info:
|
||||
update.update({'changed_info': jsonutils.dumps(
|
||||
values.changed_info.to_dict())})
|
||||
if 'changed_ext_connectivity' in values:
|
||||
if values.changed_ext_connectivity:
|
||||
update.update({'changed_ext_connectivity': jsonutils.dumps(
|
||||
[chg_ext_conn.to_dict() for chg_ext_conn in
|
||||
values.changed_ext_connectivity])})
|
||||
api.model_query(context, models.VnfLcmOpOccs). \
|
||||
filter_by(id=values.id). \
|
||||
update(update, synchronize_session=False)
|
||||
|
||||
|
||||
def _make_vnf_lcm_op_occs_list(context, op_occ_list,
|
||||
db_op_occ_list):
|
||||
lcm_op_occ_class = VnfLcmOpOcc
|
||||
|
||||
op_occ_list.objects = []
|
||||
for db_op_occ in db_op_occ_list:
|
||||
if(db_op_occ['changed_info'] and
|
||||
isinstance(db_op_occ['changed_info'], str)):
|
||||
db_op_occ['changed_info'] = jsonutils.loads(
|
||||
db_op_occ['changed_info'])
|
||||
vnf_lcm_op_occ_obj = lcm_op_occ_class._from_db_object(
|
||||
context, lcm_op_occ_class(context), db_op_occ)
|
||||
op_occ_list.objects.append(vnf_lcm_op_occ_obj)
|
||||
|
||||
op_occ_list.obj_reset_changes()
|
||||
return op_occ_list
|
||||
|
||||
|
||||
@db_api.context_manager.reader
|
||||
def _vnf_lcm_op_occs_get_by_id(context, vnf_lcm_op_occ_id):
|
||||
|
||||
|
@ -91,6 +117,19 @@ def _vnf_lcm_op_occs_get_by_vnf_instance_id(context, vnf_instance_id):
|
|||
return result
|
||||
|
||||
|
||||
@db_api.context_manager.reader
|
||||
def _vnf_lcm_op_occs_get_by_filters(context, read_deleted=None,
|
||||
filters=None):
|
||||
|
||||
query = api.model_query(context, models.VnfLcmOpOccs,
|
||||
read_deleted=read_deleted, project_only=True)
|
||||
|
||||
if filters:
|
||||
query = apply_filters(query, filters)
|
||||
|
||||
return query.all()
|
||||
|
||||
|
||||
@db_api.context_manager.reader
|
||||
def _vnf_notify_get_by_id(context, vnf_instance_id, columns_to_join=None):
|
||||
|
||||
|
@ -170,6 +209,7 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
'state_entered_time': fields.DateTimeField(nullable=False),
|
||||
'start_time': fields.DateTimeField(nullable=False),
|
||||
'vnf_instance_id': fields.StringField(nullable=False),
|
||||
'grant_id': fields.StringField(nullable=True),
|
||||
'operation': fields.StringField(nullable=False),
|
||||
'is_automatic_invocation': fields.BooleanField(default=False),
|
||||
'operation_params': fields.StringField(nullable=True),
|
||||
|
@ -180,9 +220,40 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
'ResourceChanges', nullable=True, default=None),
|
||||
'changed_info': fields.ObjectField(
|
||||
'VnfInfoModifications', nullable=True, default=None),
|
||||
'changed_ext_connectivity': fields.ListOfObjectsField(
|
||||
'ExtVirtualLinkInfo', nullable=True, default=[]),
|
||||
'error_point': fields.IntegerField(nullable=True, default=0)
|
||||
}
|
||||
|
||||
ALL_ATTRIBUTES = {
|
||||
'id': ('id', 'string', 'VnfLcmOpOccs'),
|
||||
'operationState': ('operation_state', 'string', 'VnfLcmOpOccs'),
|
||||
'stateEnteredTime':
|
||||
('state_entered_time', 'datetime', 'VnfLcmOpOccs'),
|
||||
'startTime': ('start_time', 'datetime', 'VnfLcmOpOccs'),
|
||||
'vnfInstanceId': ('vnf_instance_id', 'string', 'VnfLcmOpOccs'),
|
||||
'grantId': ('grant_id', 'string', 'VnfLcmOpOccs'),
|
||||
'operation': ('operation', 'string', 'VnfLcmOpOccs'),
|
||||
'isAutomaticInvocation':
|
||||
('is_automatic_invocation', 'boolean', 'VnfLcmOpOccs'),
|
||||
'isCancelPending': ('is_cancel_pending', 'string', 'VnfLcmOpOccs'),
|
||||
'errorPoint': ('error_point', 'number', 'VnfLcmOpOccs'),
|
||||
'operationParams': ('operation_params', 'string', 'VnfLcmOpOccs'),
|
||||
'error': ('error', 'string', 'VnfLcmOpOccs'),
|
||||
'resourceChanges': ('resource_changes', 'string', 'VnfLcmOpOccs'),
|
||||
'changedInfo': ('changed_info', 'string', 'VnfLcmOpOccs')
|
||||
}
|
||||
|
||||
FLATTEN_ATTRIBUTES = utils.flatten_dict(ALL_ATTRIBUTES.copy())
|
||||
|
||||
SIMPLE_ATTRIBUTES = ['id', 'operationState', 'stateEnteredTime',
|
||||
'startTime', 'vnfInstanceId', 'grantId', 'operation',
|
||||
'isAutomaticInvocation',
|
||||
'isCancelPending', 'errorPoint']
|
||||
|
||||
COMPLEX_ATTRIBUTES = ['error', 'resourceChanges', 'changedInfo',
|
||||
'operationParams', 'changedExtConnectivity']
|
||||
|
||||
@base.remotable
|
||||
def create(self):
|
||||
updates = self.obj_clone()
|
||||
|
@ -197,7 +268,9 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
def _from_db_object(context, vnf_lcm_op_occ_obj, db_vnf_lcm_op_occ):
|
||||
|
||||
special_fields = ['error',
|
||||
'resource_changes', 'changed_info']
|
||||
'resource_changes',
|
||||
'changed_info',
|
||||
'changed_ext_connectivity']
|
||||
for key in vnf_lcm_op_occ_obj.fields:
|
||||
if key in special_fields:
|
||||
continue
|
||||
|
@ -214,6 +287,12 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
changed_info = VnfInfoModifications.obj_from_primitive(
|
||||
db_vnf_lcm_op_occ['changed_info'], context)
|
||||
vnf_lcm_op_occ_obj.changed_info = changed_info
|
||||
if db_vnf_lcm_op_occ['changed_ext_connectivity']:
|
||||
changed_ext_conn = \
|
||||
[objects.ExtVirtualLinkInfo.obj_from_primitive(
|
||||
chg_ext_conn, context) for chg_ext_conn in
|
||||
db_vnf_lcm_op_occ['changed_ext_connectivity']]
|
||||
vnf_lcm_op_occ_obj.changed_ext_connectivity = changed_ext_conn
|
||||
|
||||
vnf_lcm_op_occ_obj._context = context
|
||||
vnf_lcm_op_occ_obj.obj_reset_changes()
|
||||
|
@ -238,6 +317,11 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
obj_data = VnfInfoModifications._from_dict(
|
||||
primitive.get('changed_info'))
|
||||
primitive.update({'changed_info': obj_data})
|
||||
if 'changed_ext_connectivity' in primitive.keys():
|
||||
obj_data = [objects.ExtVirtualLinkInfo.obj_from_primitive(
|
||||
chg_ext_conn, context) for chg_ext_conn in
|
||||
primitive.get('changed_ext_connectivity')]
|
||||
primitive.update({'changed_ext_connectivity': obj_data})
|
||||
vnf_lcm_op_occ = VnfLcmOpOcc._from_dict(primitive)
|
||||
|
||||
return vnf_lcm_op_occ
|
||||
|
@ -252,6 +336,7 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
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')
|
||||
grant_id = data_dict.get('grant_id')
|
||||
operation = data_dict.get('operation')
|
||||
is_automatic_invocation = data_dict.get('is_automatic_invocation')
|
||||
operation_params = data_dict.get('operation_params')
|
||||
|
@ -259,12 +344,14 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
error = data_dict.get('error')
|
||||
resource_changes = data_dict.get('resource_changes')
|
||||
changed_info = data_dict.get('changed_info')
|
||||
changed_ext_connectivity = data_dict.get('changed_ext_connectivity')
|
||||
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,
|
||||
grant_id=grant_id,
|
||||
operation=operation,
|
||||
is_automatic_invocation=is_automatic_invocation,
|
||||
operation_params=operation_params,
|
||||
|
@ -272,28 +359,76 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
error=error,
|
||||
resource_changes=resource_changes,
|
||||
changed_info=changed_info,
|
||||
changed_ext_connectivity=changed_ext_connectivity,
|
||||
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}
|
||||
def _get_error(self, include_fields=None):
|
||||
key = 'error'
|
||||
if key in include_fields:
|
||||
return {key: self.error.to_dict()}
|
||||
|
||||
def _get_resource_changes(self, include_fields=None):
|
||||
key = 'resourceChanges'
|
||||
if key in include_fields:
|
||||
return {key: self.resource_changes.to_dict()}
|
||||
|
||||
def _get_changed_info(self, include_fields=None):
|
||||
key = 'changedInfo'
|
||||
if key in include_fields:
|
||||
return {key: self.changed_info.to_dict()}
|
||||
|
||||
def _get_operation_params(self, include_fields=None):
|
||||
key = 'operationParams'
|
||||
if key in include_fields:
|
||||
return {key: self.operation_params}
|
||||
|
||||
def _get_changed_ext_connectivity(self, include_fields=None):
|
||||
key = 'changedExtConnectivity'
|
||||
return {key: [chg_ext_conn.to_dict() for chg_ext_conn in
|
||||
self.changed_ext_connectivity]}
|
||||
|
||||
def to_dict(self, include_fields=None):
|
||||
data = dict()
|
||||
if not include_fields:
|
||||
include_fields = set(self.FLATTEN_ATTRIBUTES.keys())
|
||||
|
||||
# add simple fields
|
||||
to_fields = set(self.SIMPLE_ATTRIBUTES).intersection(include_fields)
|
||||
for field in to_fields:
|
||||
data[field] = getattr(self, self.FLATTEN_ATTRIBUTES[field][0])
|
||||
|
||||
# add complex attributes
|
||||
if self.error:
|
||||
data.update({'error': self.error.to_dict()})
|
||||
error = self._get_error(include_fields=include_fields)
|
||||
if error:
|
||||
data.update(error)
|
||||
|
||||
if self.resource_changes:
|
||||
data.update({'resource_changes': self.resource_changes.to_dict()})
|
||||
resource_changes = self._get_resource_changes(
|
||||
include_fields=include_fields)
|
||||
if resource_changes:
|
||||
data.update(resource_changes)
|
||||
|
||||
if self.changed_info:
|
||||
data.update({'changed_info': self.changed_info.to_dict()})
|
||||
changed_info = self._get_changed_info(
|
||||
include_fields=include_fields)
|
||||
if changed_info:
|
||||
data.update(changed_info)
|
||||
|
||||
if self.operation_params:
|
||||
operation_params = self._get_operation_params(
|
||||
include_fields=include_fields)
|
||||
if operation_params:
|
||||
data.update(operation_params)
|
||||
|
||||
if self.changed_ext_connectivity:
|
||||
changed_ext_connectivity = self._get_changed_ext_connectivity(
|
||||
include_fields=include_fields)
|
||||
if changed_ext_connectivity:
|
||||
data.update(changed_ext_connectivity)
|
||||
|
||||
return data
|
||||
|
||||
|
@ -309,6 +444,22 @@ class VnfLcmOpOcc(base.TackerObject, base.TackerObjectDictCompat,
|
|||
return cls._from_db_object(context, cls(), db_vnf_lcm_op_occs)
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class VnfLcmOpOccList(ovoo_base.ObjectListBase, base.TackerObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'objects': fields.ListOfObjectsField('VnfLcmOpOcc')
|
||||
}
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_filters(cls, context, read_deleted=None, filters=None):
|
||||
db_vnf_lcm_op_occs = _vnf_lcm_op_occs_get_by_filters(
|
||||
context, read_deleted=read_deleted, filters=filters)
|
||||
return _make_vnf_lcm_op_occs_list(context, cls(), db_vnf_lcm_op_occs)
|
||||
|
||||
|
||||
@base.TackerObjectRegistry.register
|
||||
class ResourceChanges(base.TackerObject,
|
||||
base.TackerPersistentObject):
|
||||
|
|
|
@ -99,6 +99,17 @@ rules = [
|
|||
}
|
||||
]
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=VNFLCM % 'list_lcm_op_occs',
|
||||
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||
description="Query VNF LCM operation occurrence",
|
||||
operations=[
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/vnflcm/v1/vnf_lcm_op_occs'
|
||||
}
|
||||
]
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=VNFLCM % 'index',
|
||||
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||
|
|
|
@ -487,6 +487,14 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
|||
|
||||
return resp, response_body
|
||||
|
||||
def _list_op_occs(self, filter_string=''):
|
||||
show_url = os.path.join(
|
||||
self.base_vnf_lcm_op_occs_url)
|
||||
resp, response_body = self.http_client.do_request(
|
||||
show_url + filter_string, "GET")
|
||||
|
||||
return resp, response_body
|
||||
|
||||
def _wait_terminate_vnf_instance(self, id, timeout=None):
|
||||
start_time = int(time.time())
|
||||
|
||||
|
|
|
@ -778,6 +778,8 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
- Get vnflcmOpOccId to retry.
|
||||
- Retry instantiation operation.
|
||||
- Get opOccs information.
|
||||
- Get opOccs list.
|
||||
- Delete VNF instance.
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
|
@ -855,6 +857,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||
self._assert_occ_show(resp, op_occs_info)
|
||||
|
||||
# occ-list
|
||||
resp, op_occs_info = self._list_op_occs()
|
||||
self._assert_occ_list(resp, op_occs_info)
|
||||
|
||||
# Delete VNF
|
||||
resp, _ = self._delete_vnf_instance(vnf_instance_id)
|
||||
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||
|
@ -877,7 +883,9 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
- Get vnfcmOpOccId to retry.
|
||||
- Retry Scale-Out operation.
|
||||
- Get opOccs information.
|
||||
- Terminate VNF.
|
||||
- Get opOccs list.
|
||||
- Terminate VNF instance.
|
||||
- Delete VNF instance.
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
|
@ -964,6 +972,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||
self._assert_occ_show(resp, op_occs_info)
|
||||
|
||||
# occ-list
|
||||
resp, op_occs_info = self._list_op_occs()
|
||||
self._assert_occ_list(resp, op_occs_info)
|
||||
|
||||
# Terminate VNF
|
||||
stack = self._get_heat_stack(vnf_instance_id)
|
||||
resources_list = self._get_heat_resource_list(stack.id)
|
||||
|
@ -1000,6 +1012,7 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
- Get vnflcmOpOccId to rollback.
|
||||
- Rollback instantiation operation.
|
||||
- Get opOccs information.
|
||||
- Get opOccs list
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
|
@ -1072,6 +1085,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||
self._assert_occ_show(resp, op_occs_info)
|
||||
|
||||
# occ-list
|
||||
resp, op_occs_info = self._list_op_occs()
|
||||
self._assert_occ_list(resp, op_occs_info)
|
||||
|
||||
# Delete VNF
|
||||
resp, _ = self._delete_vnf_instance(vnf_instance_id)
|
||||
self._wait_lcm_done(vnf_instance_id=vnf_instance_id)
|
||||
|
@ -1094,6 +1111,7 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
- Get vnfcmOpOccId to rollback.
|
||||
- Rollback Scale-Out operation.
|
||||
- Get opOccs information.
|
||||
- get opOccs List.
|
||||
- Terminate VNF.
|
||||
- Delete subscription.
|
||||
"""
|
||||
|
@ -1176,6 +1194,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||
self._assert_occ_show(resp, op_occs_info)
|
||||
|
||||
# occ-list
|
||||
resp, op_occs_info = self._list_op_occs()
|
||||
self._assert_occ_list(resp, op_occs_info)
|
||||
|
||||
# Terminate VNF
|
||||
stack = self._get_heat_stack(vnf_instance_id)
|
||||
resources_list = self._get_heat_resource_list(stack.id)
|
||||
|
@ -1283,6 +1305,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||
self._assert_occ_show(resp, op_occs_info)
|
||||
|
||||
# occ-list
|
||||
resp, op_occs_info = self._list_op_occs()
|
||||
self._assert_occ_list(resp, op_occs_info)
|
||||
|
||||
# Delete Stack
|
||||
stack = self._get_heat_stack(vnf_instance_id)
|
||||
self._delete_heat_stack(stack.id)
|
||||
|
@ -1391,6 +1417,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id)
|
||||
self._assert_occ_show(resp, op_occs_info)
|
||||
|
||||
# occ-list
|
||||
resp, op_occs_info = self._list_op_occs()
|
||||
self._assert_occ_list(resp, op_occs_info)
|
||||
|
||||
# Terminate VNF
|
||||
stack = self._get_heat_stack(vnf_instance_id)
|
||||
resources_list = self._get_heat_resource_list(stack.id)
|
||||
|
@ -1562,3 +1592,24 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
|||
self.assertIsNotNone(_links.get('vnfInstance').get('href'))
|
||||
self.assertIsNotNone(_links.get('grant'))
|
||||
self.assertIsNotNone(_links.get('grant').get('href'))
|
||||
|
||||
def _assert_occ_list(self, resp, op_occs_list):
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Only check required parameters.
|
||||
for op_occs_info in op_occs_list:
|
||||
self.assertIsNotNone(op_occs_info.get('id'))
|
||||
self.assertIsNotNone(op_occs_info.get('operationState'))
|
||||
self.assertIsNotNone(op_occs_info.get('stateEnteredTime'))
|
||||
self.assertIsNotNone(op_occs_info.get('vnfInstanceId'))
|
||||
self.assertIsNotNone(op_occs_info.get('operation'))
|
||||
self.assertIsNotNone(op_occs_info.get('isAutomaticInvocation'))
|
||||
self.assertIsNotNone(op_occs_info.get('isCancelPending'))
|
||||
|
||||
_links = op_occs_info.get('_links')
|
||||
self.assertIsNotNone(_links.get('self'))
|
||||
self.assertIsNotNone(_links.get('self').get('href'))
|
||||
self.assertIsNotNone(_links.get('vnfInstance'))
|
||||
self.assertIsNotNone(_links.get('vnfInstance').get('href'))
|
||||
self.assertIsNotNone(_links.get('grant'))
|
||||
self.assertIsNotNone(_links.get('grant').get('href'))
|
||||
|
|
|
@ -512,3 +512,23 @@ def get_vnf(vnfd_id, vim_id):
|
|||
'placement_attr': "test_placement_attr",
|
||||
'vim_id': vim_id
|
||||
}
|
||||
|
||||
|
||||
def get_changed_ext_conn_data():
|
||||
return [{
|
||||
"id": uuidsentinel.change_ext_conn_id,
|
||||
"resource_handle": {
|
||||
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||
"resource_id": uuidsentinel.vl_resource_id,
|
||||
"vim_level_resource_type": "OS::Neutron::Net",
|
||||
},
|
||||
"ext_link_ports": [{
|
||||
"id": uuidsentinel.ext_link_ports_id,
|
||||
"resource_handle": {
|
||||
"vim_connection_id": uuidsentinel.vim_connection_id,
|
||||
"resource_id": uuidsentinel.port_resource_id,
|
||||
"vim_level_resource_type": "OS::Neutron::Port",
|
||||
},
|
||||
"cp_instance_id": uuidsentinel.cp_instance_id,
|
||||
}]
|
||||
}]
|
||||
|
|
|
@ -90,10 +90,13 @@ class TestVnfLcmOpOcc(SqlTestCase):
|
|||
problem_obj.detail = 'test_err'
|
||||
changed_info = objects.vnf_lcm_op_occs.VnfInfoModifications(
|
||||
context=self.context, **fakes.get_changed_info_data())
|
||||
changed_ext_conn = [objects.ExtVirtualLinkInfo.obj_from_primitive(
|
||||
i, self.context) for i in fakes.get_changed_ext_conn_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.changed_ext_connectivity = changed_ext_conn
|
||||
vnf_lcm_op_occs.save()
|
||||
|
||||
self.assertEqual('FAILED_TEMP', vnf_lcm_op_occs.operation_state)
|
||||
|
|
|
@ -1265,20 +1265,28 @@ VNFLCMOPOCC_RESPONSE = {
|
|||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_instances/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef'
|
||||
},
|
||||
"retry": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_lcm_op_occs/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef/retry'
|
||||
},
|
||||
"rollback": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_lcm_op_occs/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef/rollback'
|
||||
},
|
||||
"grant": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_lcm_op_occs/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef/grant'
|
||||
}},
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef/grant',
|
||||
},
|
||||
"fail": {
|
||||
"href": CONF.vnf_lcm.endpoint_url + '/vnflcm/v1/vnf_lcm_op_occs/'
|
||||
'f26f181d-7891-4720-b022-b074ec1733ef/fail'}},
|
||||
'operationState': 'COMPLETED',
|
||||
'stateEnteredTime': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.UTC),
|
||||
'startTime': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.UTC),
|
||||
'vnfInstanceId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'grantId': 'f26f181d-7891-4720-b022-b074ec1733ef',
|
||||
'operation': 'MODIFY_INFO',
|
||||
'isAutomaticInvocation': False,
|
||||
'operationParams': '{"is_reverse": False, "is_auto": False}',
|
||||
|
@ -1336,7 +1344,24 @@ VNFLCMOPOCC_RESPONSE = {
|
|||
'vnfProductName': 'fake_vnf_product_name',
|
||||
'vnfSoftwareVersion': 'fake_vnf_software_version',
|
||||
'vnfdVersion': 'fake_vnfd_version'
|
||||
}
|
||||
},
|
||||
"changedExtConnectivity": [{
|
||||
"id": constants.UUID,
|
||||
"resourceHandle": {
|
||||
"vimConnectionId": constants.UUID,
|
||||
"resourceId": constants.UUID,
|
||||
"vimLevelResourceType": "OS::Neutron::Net",
|
||||
},
|
||||
"extLinkPorts": [{
|
||||
"id": constants.UUID,
|
||||
"resourceHandle": {
|
||||
"vimConnectionId": constants.UUID,
|
||||
"resourceId": constants.UUID,
|
||||
"vimLevelResourceType": "OS::Neutron::Port",
|
||||
},
|
||||
"cpInstanceId": constants.UUID,
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
VNFLCMOPOCC_INDEX_RESPONSE = [VNFLCMOPOCC_RESPONSE]
|
||||
|
@ -1436,6 +1461,28 @@ def fake_vnf_lcm_op_occs():
|
|||
}
|
||||
changed_info_obj = objects.VnfInfoModifications(**changed_info)
|
||||
|
||||
changed_ext_connectivity = [{
|
||||
"id": constants.UUID,
|
||||
"resource_handle": {
|
||||
"vim_connection_id": constants.UUID,
|
||||
"resource_id": constants.UUID,
|
||||
"vim_level_resource_type": "OS::Neutron::Net",
|
||||
},
|
||||
"ext_link_ports": [{
|
||||
"id": constants.UUID,
|
||||
"resource_handle": {
|
||||
"vim_connection_id": constants.UUID,
|
||||
"resource_id": constants.UUID,
|
||||
"vim_level_resource_type": "OS::Neutron::Port",
|
||||
},
|
||||
"cp_instance_id": constants.UUID,
|
||||
}]
|
||||
}]
|
||||
changed_ext_connectivity_obj = \
|
||||
[objects.ExtVirtualLinkInfo.obj_from_primitive(
|
||||
chg_ext_conn, context) for chg_ext_conn in
|
||||
changed_ext_connectivity]
|
||||
|
||||
dt = datetime.datetime(1900, 1, 1, 1, 1, 1, tzinfo=iso8601.UTC)
|
||||
vnf_lcm_op_occs = {
|
||||
'id': constants.UUID,
|
||||
|
@ -1443,13 +1490,15 @@ def fake_vnf_lcm_op_occs():
|
|||
'state_entered_time': dt,
|
||||
'start_time': dt,
|
||||
'vnf_instance_id': constants.UUID,
|
||||
'grant_id': constants.UUID,
|
||||
'operation': 'MODIFY_INFO',
|
||||
'is_automatic_invocation': False,
|
||||
'operation_params': '{"is_reverse": False, "is_auto": False}',
|
||||
'is_cancel_pending': False,
|
||||
'error': error_obj,
|
||||
'resource_changes': resource_changes_obj,
|
||||
'changed_info': changed_info_obj
|
||||
'changed_info': changed_info_obj,
|
||||
'changed_ext_connectivity': changed_ext_connectivity_obj,
|
||||
}
|
||||
|
||||
return vnf_lcm_op_occs
|
||||
|
@ -1484,3 +1533,10 @@ def vnf_data(status='ACTIVE'):
|
|||
name='test',
|
||||
status=status,
|
||||
vim_id=uuidsentinel.vim_id)
|
||||
|
||||
|
||||
def return_vnf_lcm_opoccs_list():
|
||||
vnf_lcm_op_occs = fake_vnf_lcm_op_occs()
|
||||
obj = objects.VnfLcmOpOcc(**vnf_lcm_op_occs)
|
||||
|
||||
return [obj]
|
||||
|
|
|
@ -3366,3 +3366,141 @@ class TestController(base.TestCase):
|
|||
|
||||
resp = req.get_response(self.app)
|
||||
self.assertEqual(http_client.INTERNAL_SERVER_ERROR, resp.status_code)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
|
||||
def test_op_occ_list(self, mock_op_occ_list):
|
||||
req = fake_request.HTTPRequest.blank('/vnflcm/v1/vnf_lcm_op_occs')
|
||||
|
||||
complex_attributes = [
|
||||
'error',
|
||||
'resourceChanges',
|
||||
'operationParams',
|
||||
'changedInfo']
|
||||
|
||||
vnf_lcm_op_occ = fakes.return_vnf_lcm_opoccs_list()
|
||||
expected_result = fakes.index_response(
|
||||
remove_attrs=complex_attributes)
|
||||
mock_op_occ_list.return_value = vnf_lcm_op_occ
|
||||
res_dict = self.controller.list_lcm_op_occs(req)
|
||||
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': '(eq,id,f26f181d-7891-4720-b022-b074ec1733ef)'},
|
||||
{'filter': '(neq,operationState,COMPLETED)'},
|
||||
{'filter': '(gte,stateEnteredTime,2020-03-14 04:10:15+00:00)'},
|
||||
{'filter': '(eq,isAutomaticInvocation,False)'},
|
||||
{'filter': '(lt,errorPoint,4)'},
|
||||
{'filter':
|
||||
"""(eq,error,'"{"title": "ERROR",
|
||||
"status": 500, "detail": "ERROR"}"')"""},
|
||||
{'filter':
|
||||
"""(in,changedInfo,'"{"vnfInstanceName": "test"}"')"""},
|
||||
{'filter':
|
||||
"""(neq,operationParams,'"{"terminationType": "FORCEFUL"}"')"""},
|
||||
)
|
||||
def test_op_occ_filter_attributes(self, filter_params,
|
||||
mock_op_occ_list):
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
|
||||
|
||||
complex_attributes = [
|
||||
'error',
|
||||
'resourceChanges',
|
||||
'operationParams',
|
||||
'changedInfo']
|
||||
|
||||
vnf_lcm_op_occ = fakes.return_vnf_lcm_opoccs_list()
|
||||
expected_result = fakes.index_response(
|
||||
remove_attrs=complex_attributes)
|
||||
mock_op_occ_list.return_value = vnf_lcm_op_occ
|
||||
res_dict = self.controller.list_lcm_op_occs(req)
|
||||
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
|
||||
def test_op_occ_filter_attributes_invalid_filter(self, mock_op_occ_list):
|
||||
query = urllib.parse.urlencode({'filter': '(lt,non_existing,4)'})
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
|
||||
|
||||
vnf_lcm_op_occ = fakes.return_vnf_lcm_opoccs_list()
|
||||
mock_op_occ_list.return_value = vnf_lcm_op_occ
|
||||
self.assertRaises(
|
||||
exceptions.ValidationError, self.controller.list_lcm_op_occs, req)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
|
||||
def test_op_occ_attribute_selector_all_fields(self, mock_op_occ_list):
|
||||
params = {'all_fields': 'True'}
|
||||
query = urllib.parse.urlencode(params)
|
||||
req = fake_request.HTTPRequest.blank('/vnflcm/v1/vnf_lcm_op_occs?' +
|
||||
query)
|
||||
|
||||
vnf_lcm_op_occ = fakes.return_vnf_lcm_opoccs_list()
|
||||
expected_result = fakes.index_response()
|
||||
mock_op_occ_list.return_value = vnf_lcm_op_occ
|
||||
res_dict = self.controller.list_lcm_op_occs(req)
|
||||
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'fields': 'error'},
|
||||
{'fields': 'resourceChanges'},
|
||||
{'fields': 'operationParams'},
|
||||
{'fields': 'changedInfo'}
|
||||
)
|
||||
def test_op_occ_attribute_selector_fields(self, filter_params,
|
||||
mock_op_occ_list):
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
|
||||
|
||||
complex_attributes = [
|
||||
'error',
|
||||
'resourceChanges',
|
||||
'operationParams',
|
||||
'changedInfo']
|
||||
|
||||
remove_attributes = [
|
||||
x for x in complex_attributes if x != filter_params['fields']]
|
||||
|
||||
vnf_lcm_op_occ = fakes.return_vnf_lcm_opoccs_list()
|
||||
expected_result = fakes.index_response(remove_attrs=remove_attributes)
|
||||
mock_op_occ_list.return_value = vnf_lcm_op_occ
|
||||
res_dict = self.controller.list_lcm_op_occs(req)
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'exclude_fields': 'error'},
|
||||
{'exclude_fields': 'resourceChanges'},
|
||||
{'exclude_fields': 'operationParams'},
|
||||
{'exclude_fields': 'changedInfo'}
|
||||
)
|
||||
def test_op_occ_attribute_selector_exclude_fields(self, filter_params,
|
||||
mock_op_occ_list):
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
|
||||
|
||||
remove_attributes = [filter_params['exclude_fields']]
|
||||
|
||||
vnf_lcm_op_occ = fakes.return_vnf_lcm_opoccs_list()
|
||||
expected_result = fakes.index_response(remove_attrs=remove_attributes)
|
||||
mock_op_occ_list.return_value = vnf_lcm_op_occ
|
||||
res_dict = self.controller.list_lcm_op_occs(req)
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
|
||||
def test_op_occ_attribute_selector_fields_error(self, mock_op_occ_list):
|
||||
query = urllib.parse.urlencode({'fields': 'non_existent_column'})
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
|
||||
|
||||
vnf_lcm_op_occ = fakes.return_vnf_lcm_opoccs_list()
|
||||
mock_op_occ_list.return_value = vnf_lcm_op_occ
|
||||
self.assertRaises(
|
||||
exceptions.ValidationError, self.controller.list_lcm_op_occs, req)
|
||||
|
|
Loading…
Reference in New Issue