Add GET /vnf_lcm_op_occs API in GVNFM 35/64435/3
authorBharath Thiruveedula <bharath.thiruveedula@verizon.com>
Tue, 4 Sep 2018 13:46:05 +0000 (19:16 +0530)
committerbharath <bharath_ves@hotmail.com>
Wed, 5 Sep 2018 02:44:36 +0000 (08:14 +0530)
Signed-off-by: Bharath Thiruveedula <bharath.thiruveedula@verizon.com>
Change-Id: I73f6be2d4c1ff130576ff3c0de2a6de0eb123a81
Issue-ID: VFC-997

12 files changed:
lcm/lcm/nf/biz/query_vnf_lcm_op_occ.py [new file with mode: 0644]
lcm/lcm/nf/serializers/affected_storages.py [new file with mode: 0644]
lcm/lcm/nf/serializers/affected_vls.py [new file with mode: 0644]
lcm/lcm/nf/serializers/affected_vnfcs.py [new file with mode: 0644]
lcm/lcm/nf/serializers/response.py
lcm/lcm/nf/serializers/vnf_info_modifications.py [new file with mode: 0644]
lcm/lcm/nf/serializers/vnf_lcm_op_occ.py [new file with mode: 0644]
lcm/lcm/nf/serializers/vnf_lcm_op_occs.py [new file with mode: 0644]
lcm/lcm/nf/tests/test_query_vnf_lcm_op.py [new file with mode: 0644]
lcm/lcm/nf/urls.py
lcm/lcm/nf/views/lcm_op_occs_view.py [new file with mode: 0644]
lcm/lcm/pub/database/models.py

diff --git a/lcm/lcm/nf/biz/query_vnf_lcm_op_occ.py b/lcm/lcm/nf/biz/query_vnf_lcm_op_occ.py
new file mode 100644 (file)
index 0000000..467dc4f
--- /dev/null
@@ -0,0 +1,72 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+import logging
+
+from lcm.pub.database.models import VNFLcmOpOccModel
+from lcm.pub.exceptions import NFLCMException
+
+logger = logging.getLogger(__name__)
+FILTERS = {
+    'id': 'id',
+    'operationState': 'operation_state',
+    'stateEnteredTime': 'state_entered_time',
+    'startTime': 'start_time',
+    'vnfInstanceId': 'vnf_instance_id',
+    'grantId': 'grant_id',
+    'operation': 'operation'
+}
+
+
+class QueryVnfLcmOpOcc:
+    def __init__(self, data, lcm_op_occ_id=''):
+        self.vnf_lcm_op_occ_id = lcm_op_occ_id
+        self.params = data
+
+    def query_multi_vnf_lcm_op_occ(self):
+        query_data = {}
+        logger.debug("QueryMultiVnfLcmOpOccs--get--biz::> Check for filters in query params" % self.params)
+        for query, value in self.params.iteritems():
+            if query in FILTERS:
+                query_data[FILTERS[query]] = value
+        # Query the database with filters if the request has fields in request params, else fetch all records
+        if query_data:
+            lcm_ops = VNFLcmOpOccModel.objects.filter(**query_data)
+        else:
+            lcm_ops = VNFLcmOpOccModel.objects.all()
+        if not lcm_ops.exists():
+            raise NFLCMException('LCM Operation Occurances do not exist')
+        return [self.fill_resp_data(lcm_op) for lcm_op in lcm_ops]
+
+    def fill_resp_data(self, lcm_op):
+        resp_data = {
+            'id': lcm_op.id,
+            'operationState': lcm_op.operation_state,
+            'stateEnteredTime': lcm_op.state_entered_time,
+            'startTime': lcm_op.start_time,
+            'vnfInstanceId': lcm_op.vnf_instance_id,
+            'grantId': None,
+            'operation': lcm_op.operation,
+            'isAutomaticInvocation': lcm_op.is_automatic_invocation,
+            'operationParams': json.loads(lcm_op.operation_params),
+            'isCancelPending': lcm_op.is_cancel_pending,
+            'cancelMode': lcm_op.cancel_mode,
+            'error': None if not lcm_op.error else json.loads(lcm_op.error),
+            'resourceChanges': None if not lcm_op.resource_changes else json.loads(lcm_op.resource_changes),
+            'changedInfo': None if not lcm_op.changed_info else json.loads(lcm_op.changed_info),
+            'changedExtConnectivity': None if not lcm_op.changed_ext_connectivity else json.loads(lcm_op.changed_ext_connectivity),
+            '_links': json.loads(lcm_op.links)
+        }
+        return resp_data
diff --git a/lcm/lcm/nf/serializers/affected_storages.py b/lcm/lcm/nf/serializers/affected_storages.py
new file mode 100644 (file)
index 0000000..de66f28
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from rest_framework import serializers
+
+from resource_handle import ResourceHandleSerializer
+
+CHANGE_TYPES = [
+    "ADDED",
+    "REMOVED",
+    "MODIFIED",
+    "TEMPORARY"
+]
+
+
+class AffectedStoragesSerializer(serializers.Serializer):
+    id = serializers.UUIDField(
+        help_text="Identifier of the Storage instance, identifying the " +
+        "applicable 'virtualStorageResourceInfo' entry in the 'VnfInstance' data type",
+        required=True
+    )
+    virtualStorageDescId = serializers.UUIDField(
+        help_text="Identifier of the related VirtualStorage descriptor " +
+        "in the VNFD. ",
+        required=True
+    )
+    changeType = serializers.ChoiceField(
+        help_text="Signals the type of change",
+        required=True,
+        choices=CHANGE_TYPES
+    )
+    metadata = serializers.DictField(
+        help_text="Metadata about this resource. ",
+        required=False,
+        allow_null=True)
+    storageResource = ResourceHandleSerializer(
+        help_text="Reference to the VirtualStorage resource.",
+        required=True,
+        allow_null=False)
diff --git a/lcm/lcm/nf/serializers/affected_vls.py b/lcm/lcm/nf/serializers/affected_vls.py
new file mode 100644 (file)
index 0000000..7bd362e
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from rest_framework import serializers
+
+from resource_handle import ResourceHandleSerializer
+
+CHANGE_TYPES = [
+    "ADDED",
+    "REMOVED",
+    "MODIFIED",
+    "TEMPORARY",
+    "LINK_PORT_ADDED",
+    "LINK_PORT_REMOVED"
+]
+
+
+class AffectedVLsSerializer(serializers.Serializer):
+    id = serializers.UUIDField(
+        help_text="Identifier of the virtual link instance, identifying " +
+        "the applicable 'vnfVirtualLinkResourceInfo' ",
+        required=True
+    )
+    virtualLinkDescId = serializers.UUIDField(
+        help_text="Identifier of the related VLD in the VNFD.",
+        required=True
+    )
+    changeType = serializers.ChoiceField(
+        help_text="Signals the type of change",
+        required=True,
+        choices=CHANGE_TYPES
+    )
+    metadata = serializers.DictField(
+        help_text="Metadata about this resource. ",
+        required=False,
+        allow_null=True)
+    networkResource = ResourceHandleSerializer(
+        help_text="Reference to the VirtualNetwork resource.",
+        required=True,
+        allow_null=False)
diff --git a/lcm/lcm/nf/serializers/affected_vnfcs.py b/lcm/lcm/nf/serializers/affected_vnfcs.py
new file mode 100644 (file)
index 0000000..85b8364
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from rest_framework import serializers
+
+from resource_handle import ResourceHandleSerializer
+
+CHANGE_TYPES = [
+    "ADDED",
+    "REMOVED",
+    "MODIFIED",
+    "TEMPORARY"
+]
+
+
+class AffectedVnfcsSerializer(serializers.Serializer):
+    id = serializers.UUIDField(
+        help_text="Identifier of the Vnfc instance, identifying the " +
+        "applicable 'vnfcResourceInfo' entry in the 'VnfInstance' data type",
+        required=True
+    )
+    vduId = serializers.UUIDField(
+        help_text="Identifier of the related VDU in the VNFD.",
+        required=True
+    )
+    changeType = serializers.ChoiceField(
+        help_text="Signals the type of change",
+        required=True,
+        choices=CHANGE_TYPES
+    )
+    affectedVnfcCpIds = serializers.ListField(
+        help_text="Identifiers of CP(s) of the VNFC instance that " +
+        "were affected by the change",
+        required=False,
+        child=serializers.UUIDField(required=True)
+    )
+    addedStorageResourceIds = serializers.ListField(
+        help_text="References to VirtualStorage resources that " +
+        "have been added",
+        required=False,
+        child=serializers.UUIDField()
+    )
+    removedStorageResourceIds = serializers.ListField(
+        help_text="References to VirtualStorage resources that " +
+        "have been removed.",
+        required=False,
+        child=serializers.UUIDField()
+    )
+    metadata = serializers.DictField(
+        help_text="Metadata about this resource. ",
+        required=False,
+        allow_null=True)
+    computeResource = ResourceHandleSerializer(
+        help_text="Reference to the VirtualCompute resource.",
+        required=True,
+        allow_null=False)
index 81f5ed5..132788a 100644 (file)
@@ -21,3 +21,8 @@ class ProblemDetailsSerializer(serializers.Serializer):
     status = serializers.IntegerField(help_text="Status", required=True)
     detail = serializers.CharField(help_text="Detail", required=True, allow_null=True)
     instance = serializers.CharField(help_text="Instance", required=False, allow_null=True)
+    additional_details = serializers.ListField(
+        help_text="Any number of additional attributes, as defined in a " +
+        "specification or by an implementation.",
+        required=False,
+        allow_null=True)
diff --git a/lcm/lcm/nf/serializers/vnf_info_modifications.py b/lcm/lcm/nf/serializers/vnf_info_modifications.py
new file mode 100644 (file)
index 0000000..8098a6c
--- /dev/null
@@ -0,0 +1,99 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from rest_framework import serializers
+
+from vim_connection_info import VimConnectionInfoSerializer
+
+
+class VnfInfoModificationsSerializer(serializers.Serializer):
+    vnfInstanceName = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfInstanceName' attribute in 'VnfInstance'",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    vnfInstanceDescription = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfInstanceDescription' attribute in 'VnfInstance'",
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    vnfdId = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfdId' attribute in 'VnfInstance'",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    vnfProvider = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfProvider'  attribute in 'VnfInstance'",
+        max_length=255,
+        required=False,
+        allow_null=True)
+    vnfProductName = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfProductName' attribute in 'vnfInstance'",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    vnfSoftwareVersion = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfSoftwareVersion' attribute in 'VnfInstance'.",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    vnfdVersion = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfdVersion' attribute in 'VnfInstance'. ",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=False)
+    vnfPkgId = serializers.CharField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfPkgId' attribute in 'VnfInstance'.",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=False)
+    vnfConfigurableProperties = serializers.DictField(
+        help_text="If present, this attribute signals modifications of the " +
+        "'vnfConfigurableProperties'  attribute in 'VnfInstance'. ",
+        child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+        required=False,
+        allow_null=True,)
+    vimConnectionInfo = VimConnectionInfoSerializer(
+        help_text="If present, this attribute signals modifications of certain" +
+        "entries in the 'vimConnectionInfo'",
+        required=False,
+        many=True,
+        allow_null=True)
+    metadata = serializers.DictField(
+        help_text="If present, this attribute signals modifications of certain" +
+        "'metadata' attribute in 'vnfInstance'.",
+        child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+        required=False,
+        allow_null=True)
+    extensions = serializers.DictField(
+        help_text="If present, this attribute signals modifications of certain" +
+        "'extensions' attribute in 'vnfInstance'.",
+        child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+        required=False,
+        allow_null=True)
diff --git a/lcm/lcm/nf/serializers/vnf_lcm_op_occ.py b/lcm/lcm/nf/serializers/vnf_lcm_op_occ.py
new file mode 100644 (file)
index 0000000..f2ef664
--- /dev/null
@@ -0,0 +1,200 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from rest_framework import serializers
+
+from affected_vnfcs import AffectedVnfcsSerializer
+from affected_vls import AffectedVLsSerializer
+from affected_storages import AffectedStoragesSerializer
+from response import ProblemDetailsSerializer
+from ext_virtual_link_info import ExtVirtualLinkInfoSerializer
+from vnf_info_modifications import VnfInfoModificationsSerializer
+
+
+LCM_OPERATION_TYPES = [
+    "INSTANTIATE",
+    "SCALE",
+    "SCALE_TO_LEVEL",
+    "CHANGE_FLAVOUR",
+    "TERMINATE",
+    "HEAL",
+    "OPERATE",
+    "CHANGE_EXT_CONN",
+    "MODIFY_INFO"
+]
+
+LCM_OPERATION_STATE_TYPES = [
+    "STARTING",
+    "PROCESSING",
+    "COMPLETED",
+    "FAILED_TEMP",
+    "FAILED",
+    "ROLLING_BACK",
+    "ROLLED_BACK"
+]
+
+
+class ResourceChangesSerializer(serializers.Serializer):
+    affectedVnfcs = AffectedVnfcsSerializer(
+        help_text="Information about VNFC instances that were affected " +
+        "during the lifecycle operation.",
+        required=False,
+        many=True
+    )
+    affectedVirtualLinks = AffectedVLsSerializer(
+        help_text="Information about VL instances that were affected " +
+        "during the lifecycle operation. ",
+        required=False,
+        many=True
+    )
+    affectedVirtualStorages = AffectedStoragesSerializer(
+        help_text="Information about virtualised storage instances that " +
+        "were affected during the lifecycle operation",
+        required=False,
+        many=True
+    )
+
+
+class LcmOpLinkSerializer(serializers.Serializer):
+    self = serializers.CharField(
+        help_text="URI of this resource.",
+        max_length=255,
+        required=True,
+        allow_null=False)
+    vnfInstance = serializers.CharField(
+        help_text="Link to the VNF instance that the operation applies to.",
+        required=True)
+    grant = serializers.CharField(
+        help_text="Link to the grant for this operation, if one exists.",
+        required=False)
+    cancel = serializers.CharField(
+        help_text="Link to the task resource that represents the 'cancel' " +
+        "operation for this VNF LCM operation occurrence.",
+        required=False)
+    retry = serializers.CharField(
+        help_text="Link to the task resource that represents the 'retry' " +
+        "operation for this VNF LCM operation occurrence, if" +
+        " retrying is currently allowed",
+        required=False)
+    rollback = serializers.CharField(
+        help_text="Link to the task resource that represents the 'cancel' " +
+        "operation for this VNF LCM operation occurrence.",
+        required=False)
+    fail = serializers.CharField(
+        help_text="Link to the task resource that represents the 'fail' " +
+        "operation for this VNF LCM operation occurrence.",
+        required=False)
+
+
+class VNFLCMOpOccSerializer(serializers.Serializer):
+    id = serializers.CharField(
+        help_text="Identifier of this VNF lifecycle management operation" +
+        "occurrence,",
+        max_length=255,
+        required=True,
+        allow_null=False
+    )
+    operationState = serializers.ChoiceField(
+        help_text="The state of the VNF LCM operation occurrence. ",
+        required=True,
+        choices=LCM_OPERATION_STATE_TYPES
+    )
+    stateEnteredTime = serializers.CharField(
+        help_text="Date-time when the current state was entered.",
+        max_length=50
+    )
+    startTime = serializers.CharField(
+        help_text="Date-time of the start of the operation.",
+        max_length=50
+    )
+    vnfInstanceId = serializers.UUIDField(
+        help_text="Identifier of the VNF instance to which the operation" +
+        "applies"
+    )
+    grantId = serializers.UUIDField(
+        help_text="Identifier of the grant related to this VNF LCM operation " +
+                  "occurrence, if such grant exists.",
+        allow_null=True
+    )
+    operation = serializers.ChoiceField(
+        help_text="The lifecycle management operation",
+        required=True,
+        choices=LCM_OPERATION_TYPES
+    )
+    isAutomaticInvocation = serializers.BooleanField(
+        help_text="Set to true if this VNF LCM operation occurrence has " +
+        "been triggered by an automated procedure inside the VNFM. " +
+        "Set to False otherwise.",
+        default=False
+    )
+    operationParams = serializers.DictField(
+        help_text="Input parameters of the LCM operation. This attribute " +
+        "shall be formatted according to the request data type of the " +
+        "related LCM operation. The following mapping between operationType and the " +
+        "data type of this attribute shall apply: " +
+        "1. INSTANTIATE: InstantiateVnfRequest" +
+        "2. SCALE: ScaleVnfRequest " +
+        "3. SCALE_TO_LEVEL: ScaleVnfToLevelRequest " +
+        "4. CHANGE_FLAVOUR: ChangeVnfFlavourRequest " +
+        "5. OPERATE: OperateVnfRequest " +
+        "6. HEAL: HealVnfRequest " +
+        "7. CHANGE_EXT_CONN: ChangeExtVnfConnectivityRequest " +
+        "8. TERMINATE: TerminateVnfRequest " +
+        "9. MODIFY_INFO: VnfInfoModifications",
+        required=True,
+        allow_null=False
+    )
+    isCancelPending = serializers.BooleanField(
+        help_text="If the VNF LCM operation occurrence is in 'STARTING'" +
+        "'PROCESSING' or 'ROLLING_BACK' state and the operation is being" +
+        " cancelled, this attribute shall be set to True. Otherwise, " +
+        " it shall be set to False.",
+        required=True
+    )
+    cancelMode = serializers.CharField(
+        help_text="The mode of an ongoing cancellation. Shall be present " +
+        "when isCancelPending=true, and shall be None otherwise.",
+        allow_null=True,
+        required=False
+    )
+    error = ProblemDetailsSerializer(
+        help_text="If 'operationState' is 'FAILED_TEMP' or 'FAILED' or " +
+        "'PROCESSING' or 'ROLLING_BACK' and previous value of 'operationState' " +
+        "was 'FAILED_TEMP'  this attribute shall be present ",
+        allow_null=True,
+        required=False
+    )
+    resourceChanges = ResourceChangesSerializer(
+        help_text="It contains information about the cumulative changes " +
+        "to virtualised resources that were performed so far by the LCM " +
+        "operation since its start, if applicable.",
+        required=False,
+        allow_null=True)
+    changedInfo = VnfInfoModificationsSerializer(
+        help_text="Information about the changed VNF instance information, " +
+        "including VNF configurable properties",
+        required=False,
+        allow_null=True)
+    changedExtConnectivity = ExtVirtualLinkInfoSerializer(
+        help_text="Information about changed external connectivity, if this " +
+        "notification represents the result of a lifecycle operation occurrence. " +
+        "Shall be present if the 'notificationStatus' is set to 'RESULT' and the " +
+        "'operation' is set to 'CHANGE_EXT_CONN'. Shall be absent otherwise.",
+        many=True,
+        required=False,
+        allow_null=True)
+    _links = LcmOpLinkSerializer(
+        help_text="Links to resources related to this resource.",
+        required=True)
diff --git a/lcm/lcm/nf/serializers/vnf_lcm_op_occs.py b/lcm/lcm/nf/serializers/vnf_lcm_op_occs.py
new file mode 100644 (file)
index 0000000..6cb7090
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+from vnf_lcm_op_occ import VNFLCMOpOccSerializer
+
+
+class VNFLCMOpOccsSerializer(serializers.ListSerializer):
+    child = VNFLCMOpOccSerializer()
diff --git a/lcm/lcm/nf/tests/test_query_vnf_lcm_op.py b/lcm/lcm/nf/tests/test_query_vnf_lcm_op.py
new file mode 100644 (file)
index 0000000..2e1c15a
--- /dev/null
@@ -0,0 +1,159 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+
+from django.test import TestCase, Client
+from rest_framework import status
+
+from lcm.pub.database.models import VNFLcmOpOccModel
+
+
+class TestVNFLcmOpOccs(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.vnf_lcm_op_occ_id = "99442b18-a5c7-11e8-998c-bf1755941f16"
+        VNFLcmOpOccModel.objects.all().delete()
+        self.test_single_vnf_lcm_op = [{
+            "id": "99442b18-a5c7-11e8-998c-bf1755941f16",
+            "operationState": "STARTING",
+            "stateEnteredTime": "2018-07-09",
+            "startTime": "2018-07-09",
+            "vnfInstanceId": "cd552c9c-ab6f-11e8-b354-236c32aa91a1",
+            "grantId": None,
+            "operation": "SCALE",
+            "isAutomaticInvocation": False,
+            "operationParams": {},
+            "isCancelPending": False,
+            "cancelMode": None,
+            "error": None,
+            "resourceChanges": None,
+            "changedInfo": None,
+            "changedExtConnectivity": None,
+            "_links": {
+                "self": "demo",
+                "vnfInstance": "demo"
+            }
+        }]
+        self.test_vnflcmop_with_exclude_default = [{
+            "id": "99442b18-a5c7-11e8-998c-bf1755941f16",
+            "operationState": "STARTING",
+            "stateEnteredTime": "2018-07-09",
+            "startTime": "2018-07-09",
+            "vnfInstanceId": "cd552c9c-ab6f-11e8-b354-236c32aa91a1",
+            "grantId": None,
+            "operation": "SCALE",
+            "isAutomaticInvocation": False,
+            "isCancelPending": False,
+            "cancelMode": None,
+            "_links": {
+                "self": "demo",
+                "vnfInstance": "demo"
+            }
+        }]
+
+        self.test_multiple_vnf_lcm_op = [{
+            "id": "a6b9415c-ab99-11e8-9d37-dbb5e0378955",
+            "operationState": "STARTING",
+            "stateEnteredTime": "2018-07-09",
+            "startTime": "2018-07-09",
+            "vnfInstanceId": "cd552c9c-ab6f-11e8-b354-236c32aa91a1",
+            "grantId": None,
+            "operation": "INSTANTIATE",
+            "isAutomaticInvocation": False,
+            "operationParams": {},
+            "isCancelPending": False,
+            "cancelMode": None,
+            "error": None,
+            "resourceChanges": None,
+            "changedInfo": None,
+            "changedExtConnectivity": None,
+            "_links": {
+                "self": "demo",
+                "vnfInstance": "demo"
+            }
+        }]
+        self.test_multiple_vnf_lcm_op.append(
+            self.test_single_vnf_lcm_op[0])
+
+    def tearDown(self):
+        pass
+
+    def test_get_vnflcmopocc(self):
+        lcm_op_id = "99442b18-a5c7-11e8-998c-bf1755941f16"
+        vnf_instance_id = "cd552c9c-ab6f-11e8-b354-236c32aa91a1"
+        VNFLcmOpOccModel(id=lcm_op_id, operation_state="STARTING",
+                         state_entered_time="2018-07-09", start_time="2018-07-09",
+                         vnf_instance_id=vnf_instance_id,
+                         grant_id=None, operation="SCALE", is_automatic_invocation=False,
+                         operation_params='{}', is_cancel_pending=False, cancel_mode=None,
+                         error=None, resource_changes=None, changed_ext_connectivity=None,
+                         links=json.dumps({"self": "demo", "vnfInstance": "demo"})).save()
+        response = self.client.get("/api/vnflcm/v1/vnf_lcm_op_occs", format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(self.test_single_vnf_lcm_op, response.data)
+
+    def test_get_vnflcmopocc_with_id_not_exist(self):
+        response = self.client.get("/api/vnflcm/v1/vnf_lcm_op_occs?id=dummy", format='json')
+        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+        expected_data = {
+            "status": 500,
+            "detail": "LCM Operation Occurances do not exist"
+        }
+        self.assertEqual(expected_data, response.data)
+
+    def test_get_vnflcmopocc_with_filters(self):
+        lcm_op_id = "a6b9415c-ab99-11e8-9d37-dbb5e0378955"
+        vnf_instance_id = "cd552c9c-ab6f-11e8-b354-236c32aa91a1"
+        VNFLcmOpOccModel(id=lcm_op_id, operation_state="STARTING",
+                         state_entered_time="2018-07-09", start_time="2018-07-09",
+                         vnf_instance_id=vnf_instance_id,
+                         grant_id=None, operation="INSTANTIATE", is_automatic_invocation=False,
+                         operation_params='{}', is_cancel_pending=False, cancel_mode=None,
+                         error=None, resource_changes=None, changed_ext_connectivity=None,
+                         links=json.dumps({"self": "demo", "vnfInstance": "demo"})).save()
+
+        lcm_op_id = "99442b18-a5c7-11e8-998c-bf1755941f16"
+        VNFLcmOpOccModel(id=lcm_op_id, operation_state="STARTING",
+                         state_entered_time="2018-07-09", start_time="2018-07-09",
+                         vnf_instance_id=vnf_instance_id,
+                         grant_id=None, operation="SCALE", is_automatic_invocation=False,
+                         operation_params='{}', is_cancel_pending=False, cancel_mode=None,
+                         error=None, resource_changes=None, changed_ext_connectivity=None,
+                         links=json.dumps({"self": "demo", "vnfInstance": "demo"})).save()
+        response = self.client.get("/api/vnflcm/v1/vnf_lcm_op_occs", format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(self.test_multiple_vnf_lcm_op, response.data)
+
+        response = self.client.get("/api/vnflcm/v1/vnf_lcm_op_occs?operation=SCALE", format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(self.test_single_vnf_lcm_op, response.data)
+
+        response = self.client.get("/api/vnflcm/v1/vnf_lcm_op_occs?vnfInstanceId=%s" % vnf_instance_id, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(self.test_multiple_vnf_lcm_op, response.data)
+
+    def test_get_vnflcmopocc_with_extra_flags(self):
+        lcm_op_id = "99442b18-a5c7-11e8-998c-bf1755941f16"
+        vnf_instance_id = "cd552c9c-ab6f-11e8-b354-236c32aa91a1"
+        VNFLcmOpOccModel(id=lcm_op_id, operation_state="STARTING",
+                         state_entered_time="2018-07-09", start_time="2018-07-09",
+                         vnf_instance_id=vnf_instance_id,
+                         grant_id=None, operation="SCALE", is_automatic_invocation=False,
+                         operation_params='{}', is_cancel_pending=False, cancel_mode=None,
+                         error=None, resource_changes=None, changed_ext_connectivity=None,
+                         links=json.dumps({"self": "demo", "vnfInstance": "demo"})).save()
+        response = self.client.get("/api/vnflcm/v1/vnf_lcm_op_occs?exclude_default", format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(self.test_vnflcmop_with_exclude_default, response.data)
index b73cb02..7377c08 100644 (file)
@@ -19,6 +19,7 @@ from lcm.nf.views.instantiate_vnf_view import InstantiateVnfView
 from lcm.nf.views.terminate_vnf_view import TerminateVnfView
 from lcm.nf.views.subscriptions_view import SubscriptionsView
 from lcm.nf.views.operate_vnf_view import OperateVnfView
+from lcm.nf.views.lcm_op_occs_view import QueryMultiVnfLcmOpOccs
 
 urlpatterns = [
     url(r'^api/vnflcm/v1/subscriptions$', SubscriptionsView.as_view()),
@@ -27,4 +28,5 @@ urlpatterns = [
     url(r'^api/vnflcm/v1/vnf_instances/(?P<instanceid>[0-9a-zA-Z_-]+)$', DeleteVnfAndQueryVnf.as_view()),
     url(r'^api/vnflcm/v1/vnf_instances/(?P<instanceid>[0-9a-zA-Z_-]+)/terminate$', TerminateVnfView.as_view()),
     url(r'^api/vnflcm/v1/vnf_instances/(?P<instanceid>[0-9a-zA-Z_-]+)/operate$', OperateVnfView.as_view()),
+    url(r'^api/vnflcm/v1/vnf_lcm_op_occs$', QueryMultiVnfLcmOpOccs.as_view()),
 ]
diff --git a/lcm/lcm/nf/views/lcm_op_occs_view.py b/lcm/lcm/nf/views/lcm_op_occs_view.py
new file mode 100644 (file)
index 0000000..c49b64c
--- /dev/null
@@ -0,0 +1,82 @@
+# Copyright (C) 2018 Verizon. All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import traceback
+
+from drf_yasg.utils import swagger_auto_schema
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from lcm.nf.biz.query_vnf_lcm_op_occ import QueryVnfLcmOpOcc
+from lcm.nf.serializers.response import ProblemDetailsSerializer
+from lcm.nf.serializers.vnf_lcm_op_occs import VNFLCMOpOccsSerializer
+from lcm.pub.exceptions import NFLCMException
+
+logger = logging.getLogger(__name__)
+EXCLUDE_DEFAULT = ['operationParams', 'error', 'resourceChanges', 'changedInfo', 'changedExtConnectivity']
+VALID_FILTERS = ["all_fields", "fields", "exclude_fields", "exclude_default",
+                 "id", "operationState", "stateEnteredTime", "startTime",
+                 "vnfInstanceId", "grantId", "operation"]
+
+
+def get_problem_details_serializer(status_code, error_message):
+    problem_details = {
+        "status": status_code,
+        "detail": error_message
+    }
+    problem_details_serializer = ProblemDetailsSerializer(data=problem_details)
+    problem_details_serializer.is_valid()
+    return problem_details_serializer
+
+
+class QueryMultiVnfLcmOpOccs(APIView):
+    @swagger_auto_schema(
+        responses={
+            status.HTTP_200_OK: VNFLCMOpOccsSerializer(),
+            status.HTTP_400_BAD_REQUEST: ProblemDetailsSerializer(),
+            status.HTTP_500_INTERNAL_SERVER_ERROR: ProblemDetailsSerializer()
+        }
+    )
+    def get(self, request):
+        logger.debug("QueryMultiVnfLcmOpOccs--get::> %s" % request.query_params)
+        try:
+            if request.query_params and not set(request.query_params).issubset(set(VALID_FILTERS)):
+                problem_details_serializer = get_problem_details_serializer(status.HTTP_400_BAD_REQUEST, "Not a valid filter")
+                return Response(data=problem_details_serializer.data, status=status.HTTP_400_BAD_REQUEST)
+            resp_data = QueryVnfLcmOpOcc(request.query_params).query_multi_vnf_lcm_op_occ()
+
+            vnf_lcm_op_occs_serializer = VNFLCMOpOccsSerializer(data=resp_data)
+            if not vnf_lcm_op_occs_serializer.is_valid():
+                raise NFLCMException(vnf_lcm_op_occs_serializer.errors)
+
+            logger.debug("QueryMultiVnfLcmOpOccs--get::> Remove default fields if exclude_default" +
+                         " is specified")
+            # TODO(bharath): Add support for "fields", "exclude_fields" in query parameters
+            if 'exclude_default' in request.query_params.keys():
+                for field in EXCLUDE_DEFAULT:
+                    for lcm_op in vnf_lcm_op_occs_serializer.data:
+                        del lcm_op[field]
+            return Response(data=vnf_lcm_op_occs_serializer.data, status=status.HTTP_200_OK)
+        except NFLCMException as e:
+            logger.error(e.message)
+            problem_details_serializer = get_problem_details_serializer(status.HTTP_500_INTERNAL_SERVER_ERROR, e.message)
+            return Response(data=problem_details_serializer.data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+        except Exception as e:
+            logger.error(e.message)
+            logger.error(traceback.format_exc())
+            problem_details_serializer = get_problem_details_serializer(status.HTTP_500_INTERNAL_SERVER_ERROR, e.message)
+            return Response(data=problem_details_serializer.data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
index 57de616..cbdd85c 100644 (file)
@@ -311,3 +311,25 @@ class SubscriptionModel(models.Model):
     vnf_instance_filter = models.TextField(db_column='VNFINSTANCEFILTER',
                                            null=True)
     links = models.TextField(db_column='LINKS', max_length=20000)
+
+
+class VNFLcmOpOccModel(models.Model):
+    class Meta:
+        db_table = 'VNFLCMOPOCCS'
+
+    id = models.CharField(db_column='ID', max_length=255, primary_key=True)
+    operation_state = models.CharField(db_column='OPERATIONSTATE', null=False, max_length=30)
+    state_entered_time = models.CharField(db_column='STATEENTEREDTIME', null=False, max_length=30)
+    start_time = models.CharField(db_column='STARTTIME', null=False, max_length=30)
+    vnf_instance_id = models.CharField(db_column='VNFINSTANCEID', null=False, max_length=255)
+    grant_id = models.CharField(db_column='GRANTID', null=True, max_length=255)
+    operation = models.CharField(db_column='OPERATION', null=False, max_length=30)
+    is_automatic_invocation = models.CharField(db_column='ISAUTOMATICINVOCATION', null=False, max_length=5)
+    operation_params = models.TextField(db_column='OPERATIONPARAMS', null=False)
+    is_cancel_pending = models.CharField(db_column='ISCANCELPENDING', null=False, max_length=5)
+    cancel_mode = models.TextField(db_column='CANCELMODE', null=True)
+    error = models.TextField(db_column='ERROR', null=True)
+    resource_changes = models.TextField(db_column='RESOURCECHANGES', null=True)
+    changed_info = models.TextField(db_column='CHANGEDINFO', null=True)
+    changed_ext_connectivity = models.TextField(db_column='CHANGEDEXTCONNECTIVITY', null=True)
+    links = models.TextField(db_column='LINKS', null=False)