From db610a8280b3922b64eef965e3707444885f8002 Mon Sep 17 00:00:00 2001 From: maopengzhang Date: Mon, 17 Sep 2018 16:55:34 +0800 Subject: [PATCH] Support PNF In NSLCM Support PNF in NSLCM Change-Id: I0e1d28d8f574ca38c6e99c74617e6dc91c6403ad Issue-ID: VFC-1102 Signed-off-by: maopengzhang --- lcm/ns_pnfs/__init__.py | 13 ++++ lcm/ns_pnfs/biz/__init__.py | 13 ++++ lcm/ns_pnfs/biz/active_pnf.py | 27 +++++++ lcm/ns_pnfs/biz/create_pnf.py | 71 ++++++++++++++++++ lcm/ns_pnfs/biz/delete_pnf.py | 34 +++++++++ lcm/ns_pnfs/biz/get_pnf.py | 33 +++++++++ lcm/ns_pnfs/serializers/__init__.py | 13 ++++ lcm/ns_pnfs/serializers/pnf_serializer.py | 28 +++++++ lcm/ns_pnfs/tests/__init__.py | 13 ++++ lcm/ns_pnfs/tests/test_create_pnf.py | 90 ++++++++++++++++++++++ lcm/ns_pnfs/tests/test_delete_pnf.py | 58 +++++++++++++++ lcm/ns_pnfs/tests/test_get_pnf.py | 99 +++++++++++++++++++++++++ lcm/ns_pnfs/urls.py | 24 ++++++ lcm/ns_pnfs/views/__init__.py | 13 ++++ lcm/ns_pnfs/views/pnf_view.py | 119 ++++++++++++++++++++++++++++++ lcm/pub/database/models.py | 14 ++++ lcm/pub/msapi/emsdriver.py | 31 ++++++++ lcm/pub/msapi/extsys.py | 28 +++++++ lcm/pub/msapi/sdc_run_catalog.py | 12 +++ lcm/urls.py | 1 + 20 files changed, 734 insertions(+) create mode 100644 lcm/ns_pnfs/__init__.py create mode 100644 lcm/ns_pnfs/biz/__init__.py create mode 100644 lcm/ns_pnfs/biz/active_pnf.py create mode 100644 lcm/ns_pnfs/biz/create_pnf.py create mode 100644 lcm/ns_pnfs/biz/delete_pnf.py create mode 100644 lcm/ns_pnfs/biz/get_pnf.py create mode 100644 lcm/ns_pnfs/serializers/__init__.py create mode 100644 lcm/ns_pnfs/serializers/pnf_serializer.py create mode 100644 lcm/ns_pnfs/tests/__init__.py create mode 100644 lcm/ns_pnfs/tests/test_create_pnf.py create mode 100644 lcm/ns_pnfs/tests/test_delete_pnf.py create mode 100644 lcm/ns_pnfs/tests/test_get_pnf.py create mode 100644 lcm/ns_pnfs/urls.py create mode 100644 lcm/ns_pnfs/views/__init__.py create mode 100644 lcm/ns_pnfs/views/pnf_view.py create mode 100644 lcm/pub/msapi/emsdriver.py diff --git a/lcm/ns_pnfs/__init__.py b/lcm/ns_pnfs/__init__.py new file mode 100644 index 00000000..342c2a8c --- /dev/null +++ b/lcm/ns_pnfs/__init__.py @@ -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 index 00000000..342c2a8c --- /dev/null +++ b/lcm/ns_pnfs/biz/__init__.py @@ -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 index 00000000..3a7ff860 --- /dev/null +++ b/lcm/ns_pnfs/biz/active_pnf.py @@ -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 index 00000000..c9207135 --- /dev/null +++ b/lcm/ns_pnfs/biz/create_pnf.py @@ -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 index 00000000..513fd97e --- /dev/null +++ b/lcm/ns_pnfs/biz/delete_pnf.py @@ -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 index 00000000..a01abad6 --- /dev/null +++ b/lcm/ns_pnfs/biz/get_pnf.py @@ -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 index 00000000..342c2a8c --- /dev/null +++ b/lcm/ns_pnfs/serializers/__init__.py @@ -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 index 00000000..b3d7410b --- /dev/null +++ b/lcm/ns_pnfs/serializers/pnf_serializer.py @@ -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 index 00000000..342c2a8c --- /dev/null +++ b/lcm/ns_pnfs/tests/__init__.py @@ -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 index 00000000..c248ecb5 --- /dev/null +++ b/lcm/ns_pnfs/tests/test_create_pnf.py @@ -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 index 00000000..1cf431e6 --- /dev/null +++ b/lcm/ns_pnfs/tests/test_delete_pnf.py @@ -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 index 00000000..e5688733 --- /dev/null +++ b/lcm/ns_pnfs/tests/test_get_pnf.py @@ -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 index 00000000..8237b640 --- /dev/null +++ b/lcm/ns_pnfs/urls.py @@ -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[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 index 00000000..342c2a8c --- /dev/null +++ b/lcm/ns_pnfs/views/__init__.py @@ -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 index 00000000..0e1ae6fe --- /dev/null +++ b/lcm/ns_pnfs/views/pnf_view.py @@ -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) diff --git a/lcm/pub/database/models.py b/lcm/pub/database/models.py index f1aa57ab..1e70dbc7 100644 --- a/lcm/pub/database/models.py +++ b/lcm/pub/database/models.py @@ -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 index 00000000..a4188454 --- /dev/null +++ b/lcm/pub/msapi/emsdriver.py @@ -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]) diff --git a/lcm/pub/msapi/extsys.py b/lcm/pub/msapi/extsys.py index 9b6d0344..019f0825 100644 --- a/lcm/pub/msapi/extsys.py +++ b/lcm/pub/msapi/extsys.py @@ -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 diff --git a/lcm/pub/msapi/sdc_run_catalog.py b/lcm/pub/msapi/sdc_run_catalog.py index e12c2142..547a542b 100644 --- a/lcm/pub/msapi/sdc_run_catalog.py +++ b/lcm/pub/msapi/sdc_run_catalog.py @@ -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]) diff --git a/lcm/urls.py b/lcm/urls.py index 44b79f55..9c14ede8 100644 --- a/lcm/urls.py +++ b/lcm/urls.py @@ -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')), -- 2.16.6