Add Individual VNFLCMOpOcc API to GVNFM Adapter 25/65425/1
authorBharath Thiruveedula <bharath.thiruveedula@verizon.com>
Mon, 10 Sep 2018 04:24:27 +0000 (09:54 +0530)
committerBharath Thiruveedula <bharath.thiruveedula@verizon.com>
Mon, 10 Sep 2018 04:26:30 +0000 (09:56 +0530)
Signed-off-by: Bharath Thiruveedula<bharath.thiruveedula@verizon.com>
Change-Id: Ief7ef356ba527f22b58b3faa5670e9af6cd6aaf8
Issue-ID: VFC-1058

gvnfmadapter/driver/interfaces/serializers.py
gvnfmadapter/driver/interfaces/tests.py
gvnfmadapter/driver/interfaces/urls.py
gvnfmadapter/driver/interfaces/views.py

index 43b3110..457b0f0 100644 (file)
 from rest_framework import serializers
 
 
+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"
+]
+
+VNFCS_CHANGE_TYPES = [
+    "ADDED",
+    "REMOVED",
+    "MODIFIED",
+    "TEMPORARY"
+]
+
+
+STORAGES_CHANGE_TYPES = [
+    "ADDED",
+    "REMOVED",
+    "MODIFIED",
+    "TEMPORARY"
+]
+
+
+VLS_CHANGE_TYPES = [
+    "ADDED",
+    "REMOVED",
+    "MODIFIED",
+    "TEMPORARY",
+    "LINK_PORT_ADDED",
+    "LINK_PORT_REMOVED"
+]
+
+
 class AdditionalParams(serializers.Serializer):
     sdncontroller = serializers.CharField(help_text="sdncontroller", required=False)
     NatIpRange = serializers.CharField(help_text="NatIpRange", required=False)
@@ -130,3 +178,455 @@ class VnfNotifyReqSerializer(serializers.Serializer):
     vnfistanceid = serializers.CharField(help_text="VNF instance identifier.", required=True)
     eventtype = serializers.CharField(help_text="Event type.", required=True)
     vmlist = serializers.CharField(help_text="VM list.", required=True)
+
+
+class LinkSerializer(serializers.Serializer):
+    href = serializers.CharField(
+        help_text="URI of the referenced resource.",
+        required=True,
+        allow_null=False,
+        allow_blank=False)
+
+
+class VimConnectionInfoSerializer(serializers.Serializer):
+    id = serializers.CharField(
+        help_text="The identifier of the VIM Connection. This identifier is managed by the NFVO.",
+        max_length=255,
+        required=True,
+        allow_null=False,
+        allow_blank=False)
+    vimId = serializers.CharField(
+        help_text="The identifier of the VIM instance. This identifier is managed by the NFVO.",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    vimType = serializers.CharField(
+        help_text="Discriminator for the different types of the VIM information.",
+        max_length=255,
+        required=True,
+        allow_null=False,
+        allow_blank=False)
+    interfaceInfo = serializers.DictField(
+        help_text="Information about the interface or interfaces to the VIM",
+        child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+        required=False,
+        allow_null=True)
+    accessInfo = serializers.DictField(
+        help_text="Authentication credentials for accessing the VIM, and other access-related information",
+        child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+        required=False,
+        allow_null=True)
+    extra = serializers.DictField(
+        help_text="VIM type specific additional information. \
+        The applicable structure, and whether or not this attribute is available, is dependent on the content of vimType.",
+        child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+        required=False,
+        allow_null=True)
+
+
+class ResourceHandleSerializer(serializers.Serializer):
+    vimConnectionId = serializers.CharField(
+        help_text="Identifier of the VIM connection to manage the resource.",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    resourceProviderId = serializers.CharField(
+        help_text="Identifier of the entity responsible for the management of the resource.",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+    resourceId = serializers.CharField(
+        help_text="Identifier of the resource in the scope of the VIM or the resource provider.",
+        required=True,
+        max_length=255,
+        allow_null=False,
+        allow_blank=False)
+    vimLevelResourceType = serializers.CharField(
+        help_text="String, type of the resource in the scope of the VIM or the resource provider.",
+        max_length=255,
+        required=False,
+        allow_null=True,
+        allow_blank=True)
+
+
+class ProblemDetailsSerializer(serializers.Serializer):
+    type = serializers.CharField(help_text="Type", required=False, allow_null=True)
+    title = serializers.CharField(help_text="Title", required=False, allow_null=True)
+    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)
+
+
+class ExtlinkPortInfoSerializer(serializers.Serializer):
+    id = serializers.CharField(
+        help_text="Identifier of this link port as provided by the entity that has created the link port.",
+        max_length=255,
+        required=True,
+        allow_blank=False,
+        allow_null=False)
+    resourceHandle = ResourceHandleSerializer(
+        help_text="Reference to the virtualised resource realizing this link port.",
+        required=True,
+        allow_null=False)
+    id = serializers.CharField(
+        help_text="Identifier of the external CP of the VNF connected to this link port. \
+        There shall be at most one link port associated with any external connection point instance.",
+        max_length=255,
+        required=False,
+        allow_blank=True,
+        allow_null=True)
+
+
+class ExtVirtualLinkInfoSerializer(serializers.Serializer):
+    id = serializers.CharField(
+        help_text="Identifier of the external VL and the related external VL information instance. \
+        The identifier is assigned by the NFV-MANO entity that manages this VL instance.",
+        required=True,
+        max_length=255,
+        allow_null=False,
+        allow_blank=False)
+    resourceHandle = ResourceHandleSerializer(
+        help_text="Reference to the resource realizing this VL.",
+        required=True,
+        allow_null=False)
+    extlinkPorts = ExtlinkPortInfoSerializer(
+        help_text="Link ports of this VL.",
+        many=True,
+        required=False,
+        allow_null=True)
+
+
+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)
+
+
+class LcmOpLinkSerializer(serializers.Serializer):
+    self = LinkSerializer(
+        help_text="URI of this resource.",
+        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 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=VNFCS_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)
+
+
+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=STORAGES_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)
+
+
+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=VLS_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)
+
+
+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 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)
index 2e73623..c886be7 100644 (file)
@@ -538,3 +538,69 @@ class InterfacesTest(TestCase):
         mock_call_req.return_value = [1, json.JSONEncoder().encode(""), '200']
         resp = self.client.get("/api/gvnfmdriver/v1/vnfpackages")
         self.assertEqual(status.HTTP_500_INTERNAL_SERVER_ERROR, resp.status_code)
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_get_vnflcmopocc_with_id(self, mock_call_req):
+        vnfLcmOpOccId = "99442b18-a5c7-11e8-998c-bf1755941f16"
+        vnfm_info = {
+            "vnfmId": "19ecbb3a-3242-4fa3-9926-8dfb7ddc29ee",
+            "name": "g_vnfm",
+            "type": "gvnfmdriver",
+            "vimId": "",
+            "vendor": "ZTE",
+            "version": "v1.0",
+            "description": "vnfm",
+            "certificateUrl": "",
+            "url": "http://10.74.44.11",
+            "userName": "admin",
+            "password": "admin",
+            "createTime": "2016-07-06 15:33:18"
+        }
+        dummy_single_vnf_lcm_op = {
+            "id": vnfLcmOpOccId,
+            "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": {
+                    "href": "dem1o"
+                },
+                "vnfInstance": "demo"
+            }
+        }
+        mock_call_req.return_value = [0, json.JSONEncoder().encode(dummy_single_vnf_lcm_op), status.HTTP_200_OK]
+        resp = self.client.get("/api/gvnfmdriver/v1/%s/vnf_lcm_op_occs/%s" % (vnfm_info['vnfmId'], vnfLcmOpOccId))
+        self.assertEqual(dummy_single_vnf_lcm_op, resp.data)
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_get_vnflcmopocc_failed(self, mock_call_req):
+        vnfLcmOpOccId = "99442b18-a5c7-11e8-998c-bf1755941f16"
+        vnfm_info = {
+            "vnfmId": "19ecbb3a-3242-4fa3-9926-8dfb7ddc29ee",
+            "name": "g_vnfm",
+            "type": "gvnfmdriver",
+            "vimId": "",
+            "vendor": "ZTE",
+            "version": "v1.0",
+            "description": "vnfm",
+            "certificateUrl": "",
+            "url": "http://10.74.44.11",
+            "userName": "admin",
+            "password": "admin",
+            "createTime": "2016-07-06 15:33:18"
+        }
+        mock_call_req.return_value = [1, json.JSONEncoder().encode({}), status.HTTP_500_INTERNAL_SERVER_ERROR]
+        resp = self.client.get("/api/gvnfmdriver/v1/%s/vnf_lcm_op_occs/%s" % (vnfm_info['vnfmId'], vnfLcmOpOccId))
+        self.assertEqual(status.HTTP_500_INTERNAL_SERVER_ERROR, resp.status_code)
index 446e3fa..6adb6f9 100644 (file)
@@ -14,7 +14,7 @@
 
 from django.conf.urls import url
 from driver.interfaces.views import VnfInstInfo, VnfTermInfo, VnfQueryInfo, VnfOperInfo
-from driver.interfaces.views import VnfPkgsInfo, VnfGrantInfo, VnfNotifyInfo
+from driver.interfaces.views import VnfPkgsInfo, VnfGrantInfo, VnfNotifyInfo, QuerySingleVnfLcmOpOcc
 
 urlpatterns = [
     url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs$', VnfInstInfo.as_view()),
@@ -27,5 +27,7 @@ urlpatterns = [
     url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/vnfpackages$', VnfPkgsInfo.as_view()),
     url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/resource/grant$', VnfGrantInfo.as_view()),
     url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/vnfs/lifecyclechangesnotification$',
-        VnfNotifyInfo.as_view())
+        VnfNotifyInfo.as_view()),
+    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnf_lcm_op_occs/(?P<lcmopoccid>[0-9a-zA-Z_-]+)$',
+        QuerySingleVnfLcmOpOcc.as_view()),
 ]
index e3c107f..a2972ad 100644 (file)
@@ -29,7 +29,7 @@ from driver.pub.utils.restcall import req_by_msb
 from driver.interfaces.serializers import VnfInstReqParamsSerializer, ResponseSerializer
 from driver.interfaces.serializers import VnfTermReqSerializer, VnfQueryRespSerializer
 from driver.interfaces.serializers import VnfOperRespSerializer, VnfGrantReqSerializer, VnfGrantRespSerializer
-from driver.interfaces.serializers import VnfNotifyReqSerializer
+from driver.interfaces.serializers import VnfNotifyReqSerializer, VNFLCMOpOccSerializer
 
 logger = logging.getLogger(__name__)
 
@@ -306,6 +306,36 @@ class VnfPkgsInfo(APIView):
             logger.error(traceback.format_exc())
             return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 
+class QuerySingleVnfLcmOpOcc(APIView):
+    @swagger_auto_schema(
+        responses={
+            status.HTTP_200_OK: VNFLCMOpOccSerializer(),
+            status.HTTP_500_INTERNAL_SERVER_ERROR: ""
+        }
+    )
+    def get(self, request, vnfmtype, vnfmid, lcmopoccid):
+        logger.debug("[%s]LCMOpOccId = %s", fun_name(), lcmopoccid)
+        try:
+            vnfm_info = get_vnfminfo_from_nslcm(vnfmid)
+            logger.debug("[get lcm op occ] vnfm_info=[%s]", vnfm_info)
+            ret = call_vnfm("api/vnflcm/v1/vnf_lcm_op_occs/%s" % lcmopoccid, "GET", vnfm_info)
+            if ret[0] != 0:
+                logger.error("Status code is %s. detail is %s.", ret[2], ret[1])
+                raise GvnfmDriverException("Failed to query vnf lcm op occ %s" % lcmopoccid)
+            resp_data = json.JSONDecoder().decode(ret[1])
+            vnf_lcm_op_occ_serializer = VNFLCMOpOccSerializer(data=resp_data)
+            if vnf_lcm_op_occ_serializer.is_valid():
+                logger.debug("[%s]resp_data=%s" % (fun_name(), resp_data))
+                return Response(data=vnf_lcm_op_occ_serializer.data, status=status.HTTP_200_OK)
+            else:
+                raise GvnfmDriverException(vnf_lcm_op_occ_serializer.errors)
+        except GvnfmDriverException as e:
+            logger.error("Query vnflcmopocc failed, detail message: %s" % e.message)
+            return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        except:
+            logger.error(traceback.format_exc())
+            return Response(data={'error': traceback.format_exc()}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
 
 def call_vnfm(resource, method, vnfm_info, data=""):
     ret = restcall.call_req(