Support PNF In NSLCM 23/66923/4
authormaopengzhang <zhang.maopeng1@zte.com.cn>
Mon, 17 Sep 2018 08:55:34 +0000 (16:55 +0800)
committermaopengzhang <zhang.maopeng1@zte.com.cn>
Mon, 17 Sep 2018 12:52:00 +0000 (20:52 +0800)
Support PNF in NSLCM

Change-Id: I0e1d28d8f574ca38c6e99c74617e6dc91c6403ad
Issue-ID: VFC-1102
Signed-off-by: maopengzhang <zhang.maopeng1@zte.com.cn>
20 files changed:
lcm/ns_pnfs/__init__.py [new file with mode: 0644]
lcm/ns_pnfs/biz/__init__.py [new file with mode: 0644]
lcm/ns_pnfs/biz/active_pnf.py [new file with mode: 0644]
lcm/ns_pnfs/biz/create_pnf.py [new file with mode: 0644]
lcm/ns_pnfs/biz/delete_pnf.py [new file with mode: 0644]
lcm/ns_pnfs/biz/get_pnf.py [new file with mode: 0644]
lcm/ns_pnfs/serializers/__init__.py [new file with mode: 0644]
lcm/ns_pnfs/serializers/pnf_serializer.py [new file with mode: 0644]
lcm/ns_pnfs/tests/__init__.py [new file with mode: 0644]
lcm/ns_pnfs/tests/test_create_pnf.py [new file with mode: 0644]
lcm/ns_pnfs/tests/test_delete_pnf.py [new file with mode: 0644]
lcm/ns_pnfs/tests/test_get_pnf.py [new file with mode: 0644]
lcm/ns_pnfs/urls.py [new file with mode: 0644]
lcm/ns_pnfs/views/__init__.py [new file with mode: 0644]
lcm/ns_pnfs/views/pnf_view.py [new file with mode: 0644]
lcm/pub/database/models.py
lcm/pub/msapi/emsdriver.py [new file with mode: 0644]
lcm/pub/msapi/extsys.py
lcm/pub/msapi/sdc_run_catalog.py
lcm/urls.py

diff --git a/lcm/ns_pnfs/__init__.py b/lcm/ns_pnfs/__init__.py
new file mode 100644 (file)
index 0000000..342c2a8
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/ns_pnfs/biz/__init__.py b/lcm/ns_pnfs/biz/__init__.py
new file mode 100644 (file)
index 0000000..342c2a8
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/ns_pnfs/biz/active_pnf.py b/lcm/ns_pnfs/biz/active_pnf.py
new file mode 100644 (file)
index 0000000..3a7ff86
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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 lcm.pub.msapi.emsdriver import send_active_pnf_request
+
+
+class ActivePnf(object):
+    def __init__(self, ems_id, pnf_id, active_data):
+        self.ems_id = ems_id
+        self.pnf_id = pnf_id
+        self.data = active_data
+
+    def do_biz(self):
+        self.active_pnf()
+
+    def active_pnf(self):
+        return send_active_pnf_request(self.ems_id, self.pnf_id, self.data)
diff --git a/lcm/ns_pnfs/biz/create_pnf.py b/lcm/ns_pnfs/biz/create_pnf.py
new file mode 100644 (file)
index 0000000..c920713
--- /dev/null
@@ -0,0 +1,71 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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
+from lcm.pub.database.models import PNFInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi.sdc_run_catalog import query_pnf_descriptor
+from lcm.ns_pnfs.biz.get_pnf import GetPnf
+
+logger = logging.getLogger(__name__)
+
+
+class CreatePnf(object):
+    def __init__(self, data):
+        self.pnfId = data.get("pnfId"),
+        self.pnfName = data.get("pnfName"),
+        self.pnfdId = data.get("pnfdId"),
+        self.pnfdInfoId = data.get("pnfdInfoId"),
+        self.pnfProfileId = data.get("pnfProfileId"),
+        self.cpInfo = data.get("cpInfo", "")
+        self.emsId = data.get("emsId", "")
+        self.nsInstances = data.get("nsInstances")
+
+    def do_biz(self):
+        self.check_pnfd_valid()
+        self.build_cpInfo()
+        self.build_emsId()
+        self.create_pnf_inst()
+        logger.debug("CreatePnf::do_biz::pnfId=%s" % self.pnfId)
+        return GetPnf({"pnfId": self.pnfId}, True).do_biz()
+
+    def check_pnfd_valid(self):
+        pnf_package_info = query_pnf_descriptor({"pnfId": self.pnfdInfoId})
+        if not pnf_package_info:
+            raise NSLCMException("Pnfd(%s) does not exist." % self.pnfdInfoId)
+
+    def build_cpInfo(self):
+        # todo
+        pass
+
+    def build_emsId(self):
+        # todo
+        pass
+
+    def create_pnf_inst(self):
+        pnfInstances = PNFInstModel.objects.filter(pnfId=self.pnfId)
+        if pnfInstances:
+            if not pnfInstances.filter(nsInstances__contains=self.nsInstances):
+                for pnfInstance in pnfInstances:
+                    new_nsInstances = pnfInstance.nsInstances + "," + self.nsInstances
+                    pnfInstance.update(nsInstances=new_nsInstances)
+        else:
+            PNFInstModel(pnfId=self.pnfId,
+                         pnfName=self.pnfName,
+                         pnfdId=self.pnfdId,
+                         pnfdInfoId=self.pnfdInfoId,
+                         pnfProfileId=self.pnfProfileId,
+                         cpInfo=self.cpInfo,
+                         emsId=self.emsId,
+                         nsInstances=self.nsInstances).save()
diff --git a/lcm/ns_pnfs/biz/delete_pnf.py b/lcm/ns_pnfs/biz/delete_pnf.py
new file mode 100644 (file)
index 0000000..513fd97
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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
+from lcm.pub.database.models import PNFInstModel
+
+logger = logging.getLogger(__name__)
+
+
+class DeletePnf(object):
+    def __init__(self, pnf_id):
+        self.pnfId = pnf_id
+
+    def do_biz(self):
+        self.check_pnf_used()
+        self.delete_pnf()
+
+    def check_pnf_used(self):
+        pass  # todo check whether the PNF is used in NS Instances
+
+    def delete_pnf(self):
+        logger.debug("delele PnfInstModel(%s)", self.pnfId)
+        PNFInstModel.objects.filter(pnfId=self.pnfId).delete()
diff --git a/lcm/ns_pnfs/biz/get_pnf.py b/lcm/ns_pnfs/biz/get_pnf.py
new file mode 100644 (file)
index 0000000..a01abad
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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 lcm.pub.database.models import PNFInstModel
+
+
+class GetPnf(object):
+    def __init__(self, filter=None, isIndividual=False):
+        self.filter = filter
+        self.isIndividual = isIndividual
+
+    def do_biz(self):
+        if self.filter and "pnfId" in self.filter:
+            pnf_instances = PNFInstModel.objects.filter(pnfId=self.filter["pnfId"])
+            if pnf_instances and self.isIndividual:
+                return pnf_instances[0]
+            else:
+                return pnf_instances
+        elif self.filter and "nsInstanceId" in self.filter:
+            return PNFInstModel.objects.filter(nsInstances__contains=self.filter["nsInstanceId"])
+        else:
+            return PNFInstModel.objects.all()
diff --git a/lcm/ns_pnfs/serializers/__init__.py b/lcm/ns_pnfs/serializers/__init__.py
new file mode 100644 (file)
index 0000000..342c2a8
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/ns_pnfs/serializers/pnf_serializer.py b/lcm/ns_pnfs/serializers/pnf_serializer.py
new file mode 100644 (file)
index 0000000..b3d7410
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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
+
+
+class PnfInstanceSerializer(serializers.Serializer):
+    pnfId = serializers.CharField(help_text="Identifier of the PNF.", required=True, allow_null=False)
+    pnfName = serializers.CharField(help_text="Name of the PNF.", required=True, allow_null=True)
+    pnfdId = serializers.CharField(help_text="Identifier of the PNFD on which the PNF is based.", required=True, allow_null=True)
+    pnfdInfoId = serializers.CharField(help_text="Identifier of the PNFD information object related to this PNF.", required=True, allow_null=True)
+    pnfProfileId = serializers.CharField(help_text="Identifier of the related PnfProfile in the NSD on which the PNF is based.", required=True, allow_null=True)
+    cpInfo = serializers.CharField(help_text="Information on the external CP of the PNF.", required=True, allow_null=True)
+
+
+class PnfInstancesSerializer(serializers.ListSerializer):
+    child = PnfInstanceSerializer()
diff --git a/lcm/ns_pnfs/tests/__init__.py b/lcm/ns_pnfs/tests/__init__.py
new file mode 100644 (file)
index 0000000..342c2a8
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/ns_pnfs/tests/test_create_pnf.py b/lcm/ns_pnfs/tests/test_create_pnf.py
new file mode 100644 (file)
index 0000000..c248ecb
--- /dev/null
@@ -0,0 +1,90 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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 uuid
+import mock
+import json
+from django.test import TestCase, Client
+from rest_framework import status
+from lcm.ns_pnfs.biz.create_pnf import CreatePnf
+from lcm.pub.utils import restcall
+
+
+class TestCreatePnfViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+
+    def tearDown(self):
+        pass
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_do_biz(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            'id': str(uuid.uuid4()),
+            'pnfdId': 'test',
+            'pnfdName': 'test',
+            'pnfdVersion': 'v1.1.0',
+            'pnfdProvider': 'ZTE',
+            'pnfdInvariantId': str(uuid.uuid4())
+        }), '200']
+        id = str(uuid.uuid4())
+        data = {
+            "pnfId": id,
+            "pnfName": "Test PNF",
+            "pnfdId": str(uuid.uuid4()),
+            "pnfdInfoId": str(uuid.uuid4()),
+            "pnfProfileId": str(uuid.uuid4()),
+            "cpInfo": [
+                {
+                    "cpInstanceId": str(uuid.uuid4()),
+                    "cpdId": "pnf_ext_cp01",
+                    "cpProtocolData": []
+                }
+            ],
+            "emsId": str(uuid.uuid4()),
+            "nsInstances": str(uuid.uuid4()) + "," + str(uuid.uuid4())
+        }
+        ret = CreatePnf(data).do_biz()
+        self.assertIsNotNone(ret)
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_rest_api(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            'id': str(uuid.uuid4()),
+            'pnfdId': 'test',
+            'pnfdName': 'test',
+            'pnfdVersion': 'v1.1.0',
+            'pnfdProvider': 'ZTE',
+            'pnfdInvariantId': str(uuid.uuid4())
+        }), '200']
+        id = str(uuid.uuid4())
+        data = {
+            "pnfId": id,
+            "pnfName": "Test PNF",
+            "pnfdId": str(uuid.uuid4()),
+            "pnfdInfoId": str(uuid.uuid4()),
+            "pnfProfileId": str(uuid.uuid4()),
+            "cpInfo": [
+                {
+                    "cpInstanceId": str(uuid.uuid4()),
+                    "cpdId": "pnf_ext_cp01",
+                    "cpProtocolData": []
+                }
+            ],
+            "emsId": str(uuid.uuid4()),
+            "nsInstances": str(uuid.uuid4()) + "," + str(uuid.uuid4())
+        }
+
+        response = self.client.post("/api/nslcm/v1/pnfs", data=data, format='json')
+        self.assertEqual(status.HTTP_201_CREATED, response.status_code)
diff --git a/lcm/ns_pnfs/tests/test_delete_pnf.py b/lcm/ns_pnfs/tests/test_delete_pnf.py
new file mode 100644 (file)
index 0000000..1cf431e
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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 uuid
+from django.test import TestCase, Client
+from rest_framework import status
+from lcm.ns_pnfs.biz.delete_pnf import DeletePnf
+from lcm.pub.database.models import PNFInstModel
+
+
+class TestDeletePnfViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+
+    def tearDown(self):
+        pass
+
+    def test_do_biz(self):
+        pnfId = str(uuid.uuid4())
+        PNFInstModel(pnfId=pnfId,
+                     pnfName="Test PNF",
+                     pnfdId=str(uuid.uuid4()),
+                     pnfdInfoId=str(uuid.uuid4()),
+                     pnfProfileId=str(uuid.uuid4()),
+                     cpInfo=[{
+                         "cpInstanceId": str(uuid.uuid4()),
+                         "cpdId": "pnf_ext_cp01",
+                         "cpProtocolData": []
+                     }]).save()
+        DeletePnf(pnfId).do_biz()
+        pnfInst = PNFInstModel.objects.filter(pnfId=pnfId)
+        self.assertEqual(0, len(pnfInst))
+
+    def test_rest_api(self):
+        pnfId = str(uuid.uuid4())
+        PNFInstModel(pnfId=pnfId,
+                     pnfName="Test PNF",
+                     pnfdId=str(uuid.uuid4()),
+                     pnfdInfoId=str(uuid.uuid4()),
+                     pnfProfileId=str(uuid.uuid4()),
+                     cpInfo=[{
+                         "cpInstanceId": str(uuid.uuid4()),
+                         "cpdId": "pnf_ext_cp01",
+                         "cpProtocolData": []
+                     }]).save()
+        response = self.client.delete("/api/nslcm/v1/pnfs/%s" % pnfId)
+        self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
diff --git a/lcm/ns_pnfs/tests/test_get_pnf.py b/lcm/ns_pnfs/tests/test_get_pnf.py
new file mode 100644 (file)
index 0000000..e568873
--- /dev/null
@@ -0,0 +1,99 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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 uuid
+from django.test import TestCase, Client
+from rest_framework import status
+from lcm.ns_pnfs.biz.get_pnf import GetPnf
+from lcm.pub.database.models import PNFInstModel
+
+
+class TestGetPnfViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+
+    def tearDown(self):
+        pass
+
+    def test_pnfid_filter(self):
+        pnfId = str(uuid.uuid4())
+        PNFInstModel(pnfId=pnfId,
+                     pnfName="Test PNF",
+                     pnfdId=str(uuid.uuid4()),
+                     pnfdInfoId=str(uuid.uuid4()),
+                     pnfProfileId=str(uuid.uuid4()),
+                     cpInfo=[{
+                         "cpInstanceId": str(uuid.uuid4()),
+                         "cpdId": "pnf_ext_cp01",
+                         "cpProtocolData": []
+                     }]).save()
+        pnfInst = GetPnf({"pnfId": pnfId}).do_biz()
+        self.assertEqual("Test PNF", pnfInst[0].pnfName)
+
+    def test_nsInstanceid_filter(self):
+        pnfId = str(uuid.uuid4())
+        nsInstanceId = str(uuid.uuid4())
+        PNFInstModel(pnfId=pnfId,
+                     pnfName="Test PNF",
+                     pnfdId=str(uuid.uuid4()),
+                     pnfdInfoId=str(uuid.uuid4()),
+                     pnfProfileId=str(uuid.uuid4()),
+                     cpInfo=[{
+                         "cpInstanceId": str(uuid.uuid4()),
+                         "cpdId": "pnf_ext_cp01",
+                         "cpProtocolData": []
+                     }],
+                     emsId=str(uuid.uuid4()),
+                     nsInstances=nsInstanceId
+                     ).save()
+        pnfInst = GetPnf({"nsInstanceId": nsInstanceId}).do_biz()
+        self.assertEqual("Test PNF", pnfInst[0].pnfName)
+
+    def test_get_instances_restapi(self):
+        pnfId = str(uuid.uuid4())
+        nsInstanceId = str(uuid.uuid4())
+        PNFInstModel(pnfId=pnfId,
+                     pnfName="Test PNF",
+                     pnfdId=str(uuid.uuid4()),
+                     pnfdInfoId=str(uuid.uuid4()),
+                     pnfProfileId=str(uuid.uuid4()),
+                     cpInfo=[{
+                         "cpInstanceId": str(uuid.uuid4()),
+                         "cpdId": "pnf_ext_cp01",
+                         "cpProtocolData": []
+                     }],
+                     emsId=str(uuid.uuid4()),
+                     nsInstances=nsInstanceId
+                     ).save()
+        response = self.client.get("/api/nslcm/v1/pnfs")
+        self.assertEqual(status.HTTP_200_OK, response.status_code)
+
+    def test_get_individual_instance_restapi(self):
+        pnfId = str(uuid.uuid4())
+        nsInstanceId = str(uuid.uuid4())
+        PNFInstModel(pnfId=pnfId,
+                     pnfName="Test PNF",
+                     pnfdId=str(uuid.uuid4()),
+                     pnfdInfoId=str(uuid.uuid4()),
+                     pnfProfileId=str(uuid.uuid4()),
+                     cpInfo=[{
+                         "cpInstanceId": str(uuid.uuid4()),
+                         "cpdId": "pnf_ext_cp01",
+                         "cpProtocolData": []
+                     }],
+                     emsId=str(uuid.uuid4()),
+                     nsInstances=nsInstanceId
+                     ).save()
+        response = self.client.get("/api/nslcm/v1/pnfs/%s" % pnfId)
+        self.assertEqual(status.HTTP_200_OK, response.status_code)
diff --git a/lcm/ns_pnfs/urls.py b/lcm/ns_pnfs/urls.py
new file mode 100644 (file)
index 0000000..8237b64
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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 django.conf.urls import url
+from rest_framework.urlpatterns import format_suffix_patterns
+from lcm.ns_pnfs.views.pnf_view import PnfView, IndividualPnfView
+
+urlpatterns = [
+    url(r'^api/nslcm/v1/pnfs$', PnfView.as_view()),
+    url(r'^api/nslcm/v1/pnfs/(?P<pnf_id>[0-9a-zA-Z_-]+)$', IndividualPnfView.as_view()),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns_pnfs/views/__init__.py b/lcm/ns_pnfs/views/__init__.py
new file mode 100644 (file)
index 0000000..342c2a8
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/ns_pnfs/views/pnf_view.py b/lcm/ns_pnfs/views/pnf_view.py
new file mode 100644 (file)
index 0000000..0e1ae6f
--- /dev/null
@@ -0,0 +1,119 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.ns_pnfs.serializers.pnf_serializer import PnfInstanceSerializer, PnfInstancesSerializer
+from lcm.ns_pnfs.biz.create_pnf import CreatePnf
+from lcm.ns_pnfs.biz.delete_pnf import DeletePnf
+from lcm.ns_pnfs.biz.get_pnf import GetPnf
+from lcm.pub.exceptions import NSLCMException
+
+logger = logging.getLogger(__name__)
+
+
+class PnfView(APIView):
+    @swagger_auto_schema(
+        request_body=PnfInstanceSerializer(),
+        responses={
+            status.HTTP_201_CREATED: PnfInstanceSerializer()
+        }
+    )
+    def post(self, request):
+        logger.debug("PnfView--post::> %s" % request.data)
+
+        req_serializer = PnfInstanceSerializer(data=request.data)
+        if not req_serializer.is_valid():
+            logger.error(req_serializer.errors)
+            resp = {"result": 1, "detail": req_serializer.errors, "pnfId": ""}
+            return Response(data=resp, status=status.HTTP_201_CREATED)
+
+        pnfInstData = CreatePnf(request.data).do_biz()
+        resp_serializer = PnfInstanceSerializer(data=pnfInstData.__dict__)
+        if not resp_serializer.is_valid():
+            logger.error(resp_serializer.errors)
+            resp = {"result": 1, "detail": resp_serializer.errors, "pnfId": ""}
+            return Response(data=resp, status=status.HTTP_201_CREATED)
+
+        return Response(data=resp_serializer.data, status=status.HTTP_201_CREATED)
+
+    @swagger_auto_schema(
+        request_body="None",
+        responses={
+            status.HTTP_200_OK: PnfInstancesSerializer(help_text="Pnf instances", many=True),
+            status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+        }
+    )
+    def get(self, request):
+        try:
+            logger.debug("PnfView::get")
+            pnfInstDataSet = GetPnf().do_biz()
+            logger.debug("PnfView::get::ret=%s", pnfInstDataSet)
+            resp_serializer = PnfInstancesSerializer(data=[pnfInstData.__dict__ for pnfInstData in pnfInstDataSet])
+            if not resp_serializer.is_valid():
+                raise NSLCMException(resp_serializer.errors)
+            return Response(data=resp_serializer.data, status=status.HTTP_200_OK)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            logger.error("Exception in GetPnf: %s", e.message)
+            return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class IndividualPnfView(APIView):
+    @swagger_auto_schema(
+        request_body="None",
+        responses={
+            status.HTTP_204_NO_CONTENT: 'successful',
+            status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+        }
+    )
+    def delete(self, request, pnf_id):
+        try:
+            logger.debug("Enter IndividualPnfView::delete pnf(%s)", pnf_id)
+            DeletePnf(pnf_id).do_biz()
+            return Response(data={}, status=status.HTTP_204_NO_CONTENT)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            logger.error("Exception in delete pnf: %s", e.message)
+            return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+    @swagger_auto_schema(
+        request_body="None",
+        responses={
+            status.HTTP_200_OK: PnfInstanceSerializer(help_text="Pnf instance", many=True),
+            status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error",
+            status.HTTP_404_NOT_FOUND: "Pnf instance does not exist"
+        }
+    )
+    def get(self, request, pnf_id):
+        try:
+            logger.debug("Enter IndividualPnfView::get pnf(%s)", pnf_id)
+            pnf_filter = {"pnfId": pnf_id}
+            pnfInstData = GetPnf(pnf_filter, True).do_biz()
+            if not pnfInstData:
+                return Response(status=status.HTTP_404_NOT_FOUND)
+            logger.debug("Leave IndividualPnfView::get::ret=%s", pnfInstData)
+            resp_serializer = PnfInstanceSerializer(data=pnfInstData.__dict__)
+            if not resp_serializer.is_valid():
+                raise NSLCMException(resp_serializer.errors)
+            return Response(data=resp_serializer.data, status=status.HTTP_200_OK)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            logger.error("Exception in IndividualPnfView: %s", e.message)
+            return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
index f1aa57a..1e70dbc 100644 (file)
@@ -343,3 +343,17 @@ class SubscriptionModel(models.Model):
     operation_states = models.TextField(db_column='OPERATIONSTATES', null=True)
     callback_uri = models.CharField(db_column='CALLBACKURI', max_length=255)
     links = models.TextField(db_column='LINKS', max_length=20000)
+
+
+class PNFInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_PNFINST'
+
+    pnfId = models.CharField(db_column='PNFID', primary_key=True, max_length=255)
+    pnfName = models.CharField(db_column='PNFNAME', max_length=255)
+    pnfdId = models.CharField(db_column='PNFDID', max_length=50)
+    pnfdInfoId = models.CharField(db_column='PNFDINFOID', max_length=100)
+    pnfProfileId = models.CharField(db_column='PNFPROFILEID', max_length=255)
+    cpInfo = models.TextField(db_column='CPINFO', max_length=255, null=True, blank=True)
+    emsId = models.CharField(db_column='EMSID', null=True, max_length=255)
+    nsInstances = models.TextField(db_column='NSINSTANCES', max_length=1000, null=True, blank=True)
diff --git a/lcm/pub/msapi/emsdriver.py b/lcm/pub/msapi/emsdriver.py
new file mode 100644 (file)
index 0000000..a418845
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.exceptions import NSLCMException
+from lcm.pub.msapi.extsys import get_ems_by_id
+from lcm.pub.utils.restcall import req_by_msb
+
+logger = logging.getLogger(__name__)
+
+
+def send_active_pnf_request(ems_inst_id, pnf_id, req_param):
+    ems = get_ems_by_id(ems_inst_id)
+    uri = '/api/%s/v1/%s/pnfs/%s/active' % (ems["type"], ems_inst_id, pnf_id)
+    ret = req_by_msb(uri, "POST", req_param)
+    if ret[0] != 0:
+        logger.error("Failed to send nf init req:%s,%s", ret[2], ret[1])
+        raise NSLCMException('Failed to send nf init request to VNFM(%s)' % ems_inst_id)
+    return json.JSONDecoder().decode(ret[1])
index 9b6d034..019f082 100644 (file)
@@ -173,3 +173,31 @@ def select_vnfm(vnfm_type, vim_id):
         if vnfmtype == vnfm_type and vimid == vim_id:
             return vnfm_info
     raise NSLCMException('No vnfm found with %s in vim(%s)' % (vnfm_type, vim_id))
+
+
+def get_ems_by_id(ems_inst_id):
+    uri = "/external-system/esr-ems-list/esr-ems/%s?depth=all" % ems_inst_id
+    ret = call_aai(uri, "GET")
+    if ret[0] > 0:
+        logger.error('Send get EMS information request to extsys failed.')
+        raise NSLCMException('Send get EMS information request to extsys failed.')
+    # convert vnfm_info_aai to internal vnfm_info
+    ems_info_aai = json.JSONDecoder().decode(ret[1])
+    ems_info = convert_ems_info(ems_info_aai)
+    logger.debug("ems_inst_id=%s, ems_info=%s", ems_inst_id, ems_info)
+    return ems_info
+
+
+def convert_ems_info(ems_info_aai):
+    esr_system_info = ignore_case_get(ignore_case_get(ems_info_aai, "esr-system-info-list"), "esr-system-info")
+    ems_info_aai = {
+        "emsId": ems_info_aai["ems-id"],
+        "type": ignore_case_get(esr_system_info[0], "type"),
+        "vendor": ignore_case_get(esr_system_info[0], "vendor"),
+        "version": ignore_case_get(esr_system_info[0], "version"),
+        "url": ignore_case_get(esr_system_info[0], "service-url"),
+        "userName": ignore_case_get(esr_system_info[0], "user-name"),
+        "password": ignore_case_get(esr_system_info[0], "password"),
+        "createTime": ""
+    }
+    return ems_info_aai
index e12c214..547a542 100644 (file)
@@ -55,3 +55,15 @@ def query_vnfpackage_by_id(csar_id):
         logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
         raise NSLCMException("Failed to query vnf CSAR(%s) from catalog." % csar_id)
     return json.JSONDecoder().decode(ret[1])
+
+
+def query_pnf_descriptor(filter=None):
+    if filter:
+        pnfdInfoId = filter.get("pnfdInfoId")
+        ret = req_by_msb("/api/catalog/v1/pnf_descriptors/%s" % pnfdInfoId, "GET")
+    else:
+        ret = req_by_msb("/api/catalog/v1/pnf_descriptors", "GET")
+    if ret[0] != 0:
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        raise NSLCMException("Failed to query pnf descriptor(%s) from catalog." % pnfdInfoId)
+    return json.JSONDecoder().decode(ret[1])
index 44b79f5..9c14ede 100644 (file)
@@ -21,6 +21,7 @@ from lcm.pub.config.config import REG_TO_MSB_WHEN_START, REG_TO_MSB_REG_URL, REG
 urlpatterns = [
     url(r'^', include('lcm.samples.urls')),
     url(r'^', include('lcm.ns_vnfs.urls')),
+    url(r'^', include('lcm.ns_pnfs.urls')),
     url(r'^', include('lcm.ns_vls.urls')),
     url(r'^', include('lcm.ns_sfcs.urls')),
     url(r'^', include('lcm.ns.urls')),