Add seed codes of nfvo 79/5679/1
authorfujinhua <fu.jinhua@zte.com.cn>
Thu, 6 Jul 2017 01:14:50 +0000 (09:14 +0800)
committerfujinhua <fu.jinhua@zte.com.cn>
Thu, 6 Jul 2017 01:14:50 +0000 (09:14 +0800)
Change-Id: Ib788826e983b75b1800ea9fc7715dc8b8044d38d
Issue-Id: VFC-52
Signed-off-by: fujinhua <fu.jinhua@zte.com.cn>
152 files changed:
.gitignore [new file with mode: 0644]
README.md [new file with mode: 0644]
assembly.xml [new file with mode: 0644]
initialize.sh [new file with mode: 0644]
lcm/__init__.py [new file with mode: 0644]
lcm/jobs/__init__.py [new file with mode: 0644]
lcm/jobs/job_get.py [new file with mode: 0644]
lcm/jobs/tests/__init__.py [new file with mode: 0644]
lcm/jobs/tests/tests.py [new file with mode: 0644]
lcm/jobs/urls.py [new file with mode: 0644]
lcm/jobs/views.py [new file with mode: 0644]
lcm/ns/__init__.py [new file with mode: 0644]
lcm/ns/const.py [new file with mode: 0644]
lcm/ns/data/file.json [new file with mode: 0644]
lcm/ns/data/init/deploy.xml [new file with mode: 0644]
lcm/ns/data/init/init.bpel [new file with mode: 0644]
lcm/ns/data/init/init.wsdl [new file with mode: 0644]
lcm/ns/data/init/invoker.wsdl [new file with mode: 0644]
lcm/ns/data/init/invoker.xsd [new file with mode: 0644]
lcm/ns/data/scalemapping.json [new file with mode: 0644]
lcm/ns/ns_create.py [new file with mode: 0644]
lcm/ns/ns_get.py [new file with mode: 0644]
lcm/ns/ns_instant.py [new file with mode: 0644]
lcm/ns/ns_manual_scale.py [new file with mode: 0644]
lcm/ns/ns_terminate.py [new file with mode: 0644]
lcm/ns/sfcs/__init__.py [new file with mode: 0644]
lcm/ns/sfcs/create_flowcla.py [new file with mode: 0644]
lcm/ns/sfcs/create_port_chain.py [new file with mode: 0644]
lcm/ns/sfcs/create_portpairgp.py [new file with mode: 0644]
lcm/ns/sfcs/create_sfc_worker.py [new file with mode: 0644]
lcm/ns/sfcs/delete_sfcs.py [new file with mode: 0644]
lcm/ns/sfcs/detail_views.py [new file with mode: 0644]
lcm/ns/sfcs/get_sfcs.py [new file with mode: 0644]
lcm/ns/sfcs/sfc_instance.py [new file with mode: 0644]
lcm/ns/sfcs/urls.py [new file with mode: 0644]
lcm/ns/sfcs/utils.py [new file with mode: 0644]
lcm/ns/sfcs/views.py [new file with mode: 0644]
lcm/ns/swagger.json [new file with mode: 0644]
lcm/ns/tests/__init__.py [new file with mode: 0644]
lcm/ns/tests/sfcs/__init__.py [new file with mode: 0644]
lcm/ns/tests/sfcs/test_create_flow_classifier.py [new file with mode: 0644]
lcm/ns/tests/sfcs/test_create_port_chain.py [new file with mode: 0644]
lcm/ns/tests/sfcs/test_create_port_pair_group.py [new file with mode: 0644]
lcm/ns/tests/sfcs/test_data.py [new file with mode: 0644]
lcm/ns/tests/sfcs/test_sfc.py [new file with mode: 0644]
lcm/ns/tests/sfcs/test_sfc_instance.py [new file with mode: 0644]
lcm/ns/tests/sfcs/test_sfcdetailview.py [new file with mode: 0644]
lcm/ns/tests/sfcs/tests.py [new file with mode: 0644]
lcm/ns/tests/test_ns_create.py [new file with mode: 0644]
lcm/ns/tests/test_ns_instant.py [new file with mode: 0644]
lcm/ns/tests/test_ns_manual_scale.py [new file with mode: 0644]
lcm/ns/tests/tests_ns_terminate.py [new file with mode: 0644]
lcm/ns/tests/vls/__init__.py [new file with mode: 0644]
lcm/ns/tests/vls/tests.py [new file with mode: 0644]
lcm/ns/tests/vnfs/__init__.py [new file with mode: 0644]
lcm/ns/tests/vnfs/tests.py [new file with mode: 0644]
lcm/ns/tests/vnfs/verify_test.py [new file with mode: 0644]
lcm/ns/urls.py [new file with mode: 0644]
lcm/ns/views.py [new file with mode: 0644]
lcm/ns/vls/__init__.py [new file with mode: 0644]
lcm/ns/vls/create_vls.py [new file with mode: 0644]
lcm/ns/vls/delete_vls.py [new file with mode: 0644]
lcm/ns/vls/get_vls.py [new file with mode: 0644]
lcm/ns/vls/urls.py [new file with mode: 0644]
lcm/ns/vls/views.py [new file with mode: 0644]
lcm/ns/vnfs/__init__.py [new file with mode: 0644]
lcm/ns/vnfs/const.py [new file with mode: 0644]
lcm/ns/vnfs/create_vnfs.py [new file with mode: 0644]
lcm/ns/vnfs/get_vnfs.py [new file with mode: 0644]
lcm/ns/vnfs/grant_vnfs.py [new file with mode: 0644]
lcm/ns/vnfs/notify_lcm.py [new file with mode: 0644]
lcm/ns/vnfs/scale_vnfs.py [new file with mode: 0644]
lcm/ns/vnfs/terminate_nfs.py [new file with mode: 0644]
lcm/ns/vnfs/urls.py [new file with mode: 0644]
lcm/ns/vnfs/verify_vnfs.py [new file with mode: 0644]
lcm/ns/vnfs/verify_vnfs_config.json [new file with mode: 0644]
lcm/ns/vnfs/views.py [new file with mode: 0644]
lcm/ns/vnfs/wait_job.py [new file with mode: 0644]
lcm/packages/__init__.py [new file with mode: 0644]
lcm/packages/nf_package.py [new file with mode: 0644]
lcm/packages/ns_package.py [new file with mode: 0644]
lcm/packages/tests/__init__.py [new file with mode: 0644]
lcm/packages/tests/test_nf.py [new file with mode: 0644]
lcm/packages/tests/test_ns.py [new file with mode: 0644]
lcm/packages/urls.py [new file with mode: 0644]
lcm/packages/views.py [new file with mode: 0644]
lcm/pub/__init__.py [new file with mode: 0644]
lcm/pub/config/__init__.py [new file with mode: 0644]
lcm/pub/config/config.py [new file with mode: 0644]
lcm/pub/database/__init__.py [new file with mode: 0644]
lcm/pub/database/models.py [new file with mode: 0644]
lcm/pub/exceptions.py [new file with mode: 0644]
lcm/pub/msapi/__init__.py [new file with mode: 0644]
lcm/pub/msapi/catalog.py [new file with mode: 0644]
lcm/pub/msapi/extsys.py [new file with mode: 0644]
lcm/pub/msapi/nslcm.py [new file with mode: 0644]
lcm/pub/msapi/resmgr.py [new file with mode: 0644]
lcm/pub/msapi/sdncdriver.py [new file with mode: 0644]
lcm/pub/msapi/tosca.py [new file with mode: 0644]
lcm/pub/msapi/vnfmdriver.py [new file with mode: 0644]
lcm/pub/msapi/wso2bpel.py [new file with mode: 0644]
lcm/pub/nfvi/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/multivim/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/multivim/api.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/api.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/auth.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/glancebase.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/image.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/network.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/neutronbase.py [new file with mode: 0644]
lcm/pub/nfvi/vim/api/openstack/project.py [new file with mode: 0644]
lcm/pub/nfvi/vim/const.py [new file with mode: 0644]
lcm/pub/nfvi/vim/lib/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/lib/syscomm.py [new file with mode: 0644]
lcm/pub/nfvi/vim/lib/vimexception.py [new file with mode: 0644]
lcm/pub/nfvi/vim/test/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/test/openstack/__init__.py [new file with mode: 0644]
lcm/pub/nfvi/vim/test/openstack/pub.py [new file with mode: 0644]
lcm/pub/nfvi/vim/test/openstack/test_image.py [new file with mode: 0644]
lcm/pub/nfvi/vim/test/openstack/test_network.py [new file with mode: 0644]
lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2 [new file with mode: 0644]
lcm/pub/nfvi/vim/vimadaptor.py [new file with mode: 0644]
lcm/pub/utils/__init__.py [new file with mode: 0644]
lcm/pub/utils/enumutil.py [new file with mode: 0644]
lcm/pub/utils/fileutil.py [new file with mode: 0644]
lcm/pub/utils/idutil.py [new file with mode: 0644]
lcm/pub/utils/jobutil.py [new file with mode: 0644]
lcm/pub/utils/restcall.py [new file with mode: 0644]
lcm/pub/utils/scaleaspect.py [new file with mode: 0644]
lcm/pub/utils/share_lock.py [new file with mode: 0644]
lcm/pub/utils/syscomm.py [new file with mode: 0644]
lcm/pub/utils/timeutil.py [new file with mode: 0644]
lcm/pub/utils/toscautil.py [new file with mode: 0644]
lcm/pub/utils/toscautil_new.py [new file with mode: 0644]
lcm/pub/utils/values.py [new file with mode: 0644]
lcm/samples/__init__.py [new file with mode: 0644]
lcm/samples/tests.py [new file with mode: 0644]
lcm/samples/urls.py [new file with mode: 0644]
lcm/samples/views.py [new file with mode: 0644]
lcm/settings.py [new file with mode: 0644]
lcm/urls.py [new file with mode: 0644]
lcm/wsgi.py [new file with mode: 0644]
logs/empty.txt [new file with mode: 0644]
manage.py [new file with mode: 0644]
pom.xml [new file with mode: 0644]
requirements.txt [new file with mode: 0644]
run.sh [new file with mode: 0644]
stop.sh [new file with mode: 0644]
tox.ini [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..821f62a
--- /dev/null
@@ -0,0 +1,2 @@
+logs/*.log
+*.pyc
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..7b59118
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# Copyright 2016 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.
+
+# Micro service of network service life cycle management.
diff --git a/assembly.xml b/assembly.xml
new file mode 100644 (file)
index 0000000..07de679
--- /dev/null
@@ -0,0 +1,56 @@
+<!--
+    Copyright 2016 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.
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+    <id>lcm</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+    <fileSets>
+        <fileSet>
+            <directory>lcm</directory>
+            <outputDirectory>/lcm</outputDirectory>
+            <includes>
+                <include>**/*.py</include>
+                <include>**/*.json</include>
+                <include>**/*.xml</include>
+                <include>**/*.wsdl</include>
+                <include>**/*.xsd</include>
+                <include>**/*.bpel</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>logs</directory>
+            <outputDirectory>/logs</outputDirectory>
+            <includes>
+                <include>*.txt</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>.</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>*.py</include>
+                <include>*.txt</include>
+                <include>*.sh</include>
+                <include>*.ini</include>
+                <include>*.md</include>
+            </includes>
+        </fileSet>
+    </fileSets>
+    <baseDirectory>nfvo/lcm</baseDirectory>
+</assembly>
diff --git a/initialize.sh b/initialize.sh
new file mode 100644 (file)
index 0000000..8f6a000
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright 2016 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.
+
+pip install -r requirements.txt
diff --git a/lcm/__init__.py b/lcm/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/jobs/__init__.py b/lcm/jobs/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/jobs/job_get.py b/lcm/jobs/job_get.py
new file mode 100644 (file)
index 0000000..a85bf8f
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright 2016 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.utils.jobutil import JobUtil
+
+logger = logging.getLogger(__name__)
+
+
+class GetJobInfoService(object):
+    def __init__(self, job_id, response_id=0):
+        self.job_id = job_id
+        self.response_id = response_id if response_id else 0
+
+    def do_biz(self):
+        #logger.info("get job info, job_id=:%s, response_id=:%s" % (self.job_id, self.response_id))
+        jobs = JobUtil.query_job_status(self.job_id, self.response_id)
+        if not jobs:
+            return {"jobId": self.job_id}
+        ret = {
+            "jobId": self.job_id,
+            "responseDescriptor": {
+                "status": jobs[0].status,
+                "progress": jobs[0].progress,
+                "statusDescription": jobs[0].descp,
+                "errorCode": jobs[0].errcode,
+                "responseId": jobs[0].indexid,
+                "responseHistoryList": [
+                    {
+                        "status": job.status,
+                        "progress": job.progress,
+                        "statusDescription": job.descp,
+                        "errorCode": job.errcode,
+                        "responseId": job.indexid} for job in jobs[1:]]}}
+        return ret
diff --git a/lcm/jobs/tests/__init__.py b/lcm/jobs/tests/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/jobs/tests/tests.py b/lcm/jobs/tests/tests.py
new file mode 100644 (file)
index 0000000..76f9a8d
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright 2016 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.test import TestCase, Client
+from rest_framework import status
+
+from lcm.pub.database.models import JobModel, JobStatusModel
+
+
+class JobsViewTest(TestCase):
+    def setUp(self):
+        self.job_id = 'test_job_id'
+        self.client = Client()
+
+    def tearDown(self):
+        JobModel.objects.all().delete()
+
+    def test_job(self):
+        JobModel(jobid=self.job_id, jobtype='VNF', jobaction='INST', resid='1').save()
+        JobStatusModel(indexid=1, jobid=self.job_id, status='inst', progress=20, descp='inst').save()
+        response = self.client.get("/openoapi/nslcm/v1/jobs/%s" % self.job_id)
+        self.failUnlessEqual(status.HTTP_200_OK, response.status_code)
diff --git a/lcm/jobs/urls.py b/lcm/jobs/urls.py
new file mode 100644 (file)
index 0000000..2a163db
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2016 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 patterns, url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from lcm.jobs.views import JobView
+
+urlpatterns = patterns('',
+                       url(r'^openoapi/nslcm/v1/jobs/(?P<job_id>[0-9a-zA-Z_-]+)$', JobView.as_view()),
+                       )
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/jobs/views.py b/lcm/jobs/views.py
new file mode 100644 (file)
index 0000000..2c971d4
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright 2016 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 rest_framework.response import Response
+from rest_framework.views import APIView
+
+from lcm.jobs.job_get import GetJobInfoService
+from lcm.pub.utils.jobutil import JobUtil
+from lcm.pub.utils.values import ignore_case_get
+
+logger = logging.getLogger(__name__)
+
+class JobView(APIView):
+    def get(self, request, job_id):
+        response_id = ignore_case_get(request.META, 'responseId')
+        ret = GetJobInfoService(job_id, response_id).do_biz()
+        return Response(data=ret)
+
+    def post(self, request, job_id):
+        try:
+            logger.debug("Enter JobView:post, %s, %s ", job_id, request.data)
+            jobs = JobUtil.query_job_status(job_id)
+            if len(jobs) > 0 and jobs[-1].errcode == '255':
+                return Response(data={'result': 'ok'})
+            progress = request.data.get('progress')
+            desc = request.data.get('desc', '%s' % progress)
+            errcode = '0' if request.data.get('errcode') in ('true', 'active') else '255'
+            logger.debug("errcode=%s", errcode)
+            JobUtil.add_job_status(job_id, progress, desc, error_code=errcode)
+            return Response(data={'result': 'ok'})
+        except Exception as e:
+            return Response(data={'result': 'error', 'msg': e.message})
diff --git a/lcm/ns/__init__.py b/lcm/ns/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/const.py b/lcm/ns/const.py
new file mode 100644 (file)
index 0000000..a0e9973
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright 2016-2017 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.utils.enumutil import enum
+
+OWNER_TYPE = enum(VNF=0, VNFM=1, NS=2)
+
+NS_INST_STATUS = enum(EMPTY='empty', INSTANTIATING='instantiating', TERMINATING='terminating',
+                      ACTIVE='active', FAILED='failed', INACTIVE='inactive', UPDATING='updating', SCALING='scaling')
diff --git a/lcm/ns/data/file.json b/lcm/ns/data/file.json
new file mode 100644 (file)
index 0000000..520f334
--- /dev/null
@@ -0,0 +1,821 @@
+[
+    {
+        "connections": [],
+        "type": "",
+        "id": "element4"
+    },
+    {
+        "name": "createVL",
+        "position": {
+            "left": 141.5,
+            "top": 157
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element169"
+        ],
+        "id": "element7",
+        "publicInterface": "vls Resource.2",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/ns/vls",
+        "path": {},
+        "query": {},
+        "body": {
+            "vnfInstanceData": {
+                "type": "string",
+                "value": ""
+            },
+            "additionalParamForVnf": {
+                "type": "plan",
+                "value": "StartEvent.object_additionalParamForVnf"
+            },
+            "nsInstanceId": {
+                "type": "plan",
+                "value": "StartEvent.nsInstanceId"
+            },
+            "flavourId": {
+                "type": "string",
+                "value": ""
+            },
+            "pnfInfo": {
+                "type": "string",
+                "value": ""
+            },
+            "extNSVirtualLink": {
+                "type": "string",
+                "value": ""
+            },
+            "additionalParamForNs": {
+                "type": "plan",
+                "value": "StartEvent.object_additionalParamForNs"
+            },
+            "context": {
+                "type": "plan",
+                "value": "StartEvent.object_context"
+            },
+            "sapData": {
+                "type": "string",
+                "value": ""
+            },
+            "nestedNsInstanceId": {
+                "type": "string",
+                "value": ""
+            },
+            "jobId": {
+                "type": "string",
+                "value": ""
+            },
+            "locationConstraints": {
+                "type": "string",
+                "value": ""
+            },
+            "vlIndex": {
+                "type": "plan",
+                "value": "StartEvent.vl_index"
+            }
+        },
+        "output": {
+            "vlId": {
+                "type": "topology",
+                "value": ""
+            },
+            "result": {
+                "type": "plan",
+                "value": "StartEvent.vl_status"
+            },
+            "detail": {
+                "type": "topology",
+                "value": ""
+            }
+        }
+    },
+    {
+        "name": "StartEvent",
+        "position": {
+            "left": 64,
+            "top": 74
+        },
+        "type": "StartEvent",
+        "connections": [
+            "element173"
+        ],
+        "id": "element27",
+        "output": {
+            "vlCount": {
+                "type": "string",
+                "value": ""
+            },
+            "vnfCount": {
+                "type": "string",
+                "value": ""
+            },
+            "sfcCount": {
+                "type": "string",
+                "value": ""
+            },
+            "object_context": {
+                "type": "string",
+                "value": ""
+            },
+            "nsInstanceId": {
+                "type": "string",
+                "value": ""
+            },
+            "object_additionalParamForNs": {
+                "type": "string",
+                "value": ""
+            },
+            "object_additionalParamForVnf": {
+                "type": "string",
+                "value": ""
+            },
+            "jobId": {
+                "type": "string",
+                "value": ""
+            },
+            "sdnControllerId": {
+                "type": "string",
+                "value": ""
+            }
+        },
+        "variable": {
+            "vl_index": {
+                "type": "string",
+                "value": "1"
+            },
+            "vnf_index": {
+                "type": "string",
+                "value": "1"
+            },
+            "sfc_index": {
+                "type": "string",
+                "value": "1"
+            },
+            "vnf_status": {
+                "type": "string",
+                "value": "active"
+            },
+            "sfc_status": {
+                "type": "string",
+                "value": "active"
+            },
+            "vl_status": {
+                "type": "string",
+                "value": "active"
+            },
+            "exec_status": {
+                "type": "string",
+                "value": "active"
+            }
+        }
+    },
+    {
+        "name": "EndEvent",
+        "position": {
+            "left": 872.5,
+            "top": 183
+        },
+        "type": "EndEvent",
+        "connections": [],
+        "id": "element31"
+    },
+    {
+        "name": "Variable",
+        "position": {
+            "left": 321,
+            "top": 112
+        },
+        "type": "Variable",
+        "connections": [],
+        "id": "element166"
+    },
+    {
+        "name": "Assign_vl_index",
+        "position": {
+            "left": 124.5,
+            "top": 257
+        },
+        "type": "Assign",
+        "connections": [
+            "element177"
+        ],
+        "id": "element169",
+        "params": {
+            "StartEvent.vl_index": {
+                "type": "expression",
+                "value": "$vl_index+1",
+                "extension": ""
+            },
+            "StartEvent.vl_status": {
+                "type": "expression",
+                "value": "concat(translate($vl_status,'0',''), 'active')",
+                "extension": ""
+            }
+        }
+    },
+    {
+        "name": "While",
+        "position": {
+            "left": 164.5,
+            "top": 74
+        },
+        "type": "While",
+        "connections": [
+            "element7"
+        ],
+        "id": "element173",
+        "condition": "$vl_index&lt;=$vlCount and $vl_status='active'"
+    },
+    {
+        "name": "End",
+        "position": {
+            "left": 164.5,
+            "top": 337
+        },
+        "type": "Loop",
+        "connections": [
+            "element150"
+        ],
+        "id": "element177"
+    },
+    {
+        "name": "While",
+        "position": {
+            "left": 273.5,
+            "top": 110
+        },
+        "type": "While",
+        "connections": [
+            "element23"
+        ],
+        "id": "element19",
+        "condition": "$vnf_index&lt;=$vnfCount and $vl_status='active' and $vnf_status='active'"
+    },
+    {
+        "name": "createVNF",
+        "position": {
+            "left": 358.5,
+            "top": 106
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element45"
+        ],
+        "id": "element23",
+        "publicInterface": "vnfs Resource.1",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/ns/vnfs",
+        "path": {},
+        "query": {},
+        "body": {
+            "vnfInstanceData": {
+                "type": "string",
+                "value": ""
+            },
+            "vnfIndex": {
+                "type": "plan",
+                "value": "StartEvent.vnf_index"
+            },
+            "additionalParamForVnf": {
+                "type": "plan",
+                "value": "StartEvent.object_additionalParamForVnf"
+            },
+            "nsInstanceId": {
+                "type": "plan",
+                "value": "StartEvent.nsInstanceId"
+            },
+            "flavourId": {
+                "type": "string",
+                "value": ""
+            },
+            "pnfInfo": {
+                "type": "string",
+                "value": ""
+            },
+            "extNSVirtualLink": {
+                "type": "string",
+                "value": ""
+            },
+            "additionalParamForNs": {
+                "type": "plan",
+                "value": "StartEvent.object_additionalParamForNs"
+            },
+            "context": {
+                "type": "plan",
+                "value": "StartEvent.object_context"
+            },
+            "sapData": {
+                "type": "string",
+                "value": ""
+            },
+            "nestedNsInstanceId": {
+                "type": "string",
+                "value": ""
+            },
+            "jobId": {
+                "type": "string",
+                "value": ""
+            },
+            "locationConstraints": {
+                "type": "string",
+                "value": ""
+            }
+        },
+        "output": {
+            "vnfInstId": {
+                "type": "topology",
+                "value": ""
+            },
+            "jobId": {
+                "type": "topology",
+                "value": ""
+            }
+        }
+    },
+    {
+        "name": "Assign_vnf_index",
+        "position": {
+            "left": 342,
+            "top": 389.5
+        },
+        "type": "Assign",
+        "connections": [
+            "element53"
+        ],
+        "id": "element39",
+        "params": {
+            "StartEvent.vnf_index": {
+                "type": "expression",
+                "value": "$vnf_index+1",
+                "extension": ""
+            }
+        }
+    },
+    {
+        "name": "RepeatUntil",
+        "position": {
+            "left": 385,
+            "top": 183
+        },
+        "type": "RepeatUntil",
+        "connections": [
+            "element57"
+        ],
+        "id": "element45",
+        "condition": "$vnf_status='active' or $vnf_status='failed'"
+    },
+    {
+        "name": "End",
+        "position": {
+            "left": 385,
+            "top": 337
+        },
+        "type": "Loop",
+        "connections": [
+            "element39"
+        ],
+        "id": "element49"
+    },
+    {
+        "name": "End",
+        "position": {
+            "left": 385,
+            "top": 447
+        },
+        "type": "Loop",
+        "connections": [
+            "element318"
+        ],
+        "id": "element53"
+    },
+    {
+        "name": "query_vnf nslcm",
+        "position": {
+            "left": 345,
+            "top": 257
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element49"
+        ],
+        "id": "element57",
+        "publicInterface": "vnfs Resource.3",
+        "method": "GET",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/ns/vnfs/{vnfInstId}",
+        "path": {
+            "vnfInstId": {
+                "type": "plan",
+                "value": "createVNF.vnfInstId"
+            }
+        },
+        "query": {},
+        "body": {},
+        "output": {
+            "vnfInstId": {
+                "type": "topology",
+                "value": ""
+            },
+            "vnfName": {
+                "type": "topology",
+                "value": ""
+            },
+            "vnfStatus": {
+                "type": "plan",
+                "value": "StartEvent.vnf_status"
+            }
+        }
+    },
+    {
+        "name": "While",
+        "position": {
+            "left": 510.5,
+            "top": 110
+        },
+        "type": "While",
+        "connections": [
+            "element160"
+        ],
+        "id": "element156",
+        "condition": "$sfc_index&lt;=$sfcCount and $vl_status='active' and $vnf_status='active' and $sfc_status='active'"
+    },
+    {
+        "name": "createSFC",
+        "position": {
+            "left": 600.5,
+            "top": 106
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element187"
+        ],
+        "id": "element160",
+        "publicInterface": "sfcs Resource.1",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/ns/sfcs",
+        "path": {},
+        "query": {},
+        "body": {
+            "sdnControllerId": {
+                "type": "plan",
+                "value": "StartEvent.sdnControllerId"
+            },
+            "vnfInstanceData": {
+                "type": "string",
+                "value": ""
+            },
+            "additionalParamForVnf": {
+                "type": "plan",
+                "value": "StartEvent.object_additionalParamForVnf"
+            },
+            "nsInstanceId": {
+                "type": "plan",
+                "value": "StartEvent.nsInstanceId"
+            },
+            "additionalParamForNs": {
+                "type": "plan",
+                "value": "StartEvent.object_additionalParamForNs"
+            },
+            "context": {
+                "type": "plan",
+                "value": "StartEvent.object_context"
+            },
+            "sapData": {
+                "type": "string",
+                "value": ""
+            },
+            "fpindex": {
+                "type": "plan",
+                "value": "StartEvent.sfc_index"
+            }
+        },
+        "output": {
+            "sfcInstId": {
+                "type": "topology",
+                "value": ""
+            },
+            "jobId": {
+                "type": "topology",
+                "value": ""
+            }
+        }
+    },
+    {
+        "name": "RepeatUntil",
+        "position": {
+            "left": 627,
+            "top": 183
+        },
+        "type": "RepeatUntil",
+        "connections": [
+            "element191"
+        ],
+        "id": "element187",
+        "condition": "$sfc_status='active' or $sfc_status='failed'"
+    },
+    {
+        "name": "querySFC",
+        "position": {
+            "left": 602,
+            "top": 257
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element201"
+        ],
+        "id": "element191",
+        "publicInterface": "sfcs Resource.0",
+        "method": "GET",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/ns/sfcs/{sfcInstId}",
+        "path": {
+            "sfcInstId": {
+                "type": "plan",
+                "value": "createSFC.sfcInstId"
+            }
+        },
+        "query": {},
+        "body": {},
+        "output": {
+            "sfcName": {
+                "type": "topology",
+                "value": ""
+            },
+            "sfcInstId": {
+                "type": "topology",
+                "value": ""
+            },
+            "sfcStatus": {
+                "type": "plan",
+                "value": "StartEvent.sfc_status"
+            }
+        }
+    },
+    {
+        "name": "End",
+        "position": {
+            "left": 627,
+            "top": 315
+        },
+        "type": "Loop",
+        "connections": [
+            "element205"
+        ],
+        "id": "element201"
+    },
+    {
+        "name": "Assign_sfc_index",
+        "position": {
+            "left": 585,
+            "top": 389.5
+        },
+        "type": "Assign",
+        "connections": [
+            "element228"
+        ],
+        "id": "element205",
+        "params": {
+            "StartEvent.sfc_index": {
+                "type": "expression",
+                "value": "$sfc_index+1",
+                "extension": ""
+            }
+        }
+    },
+    {
+        "name": "End",
+        "position": {
+            "left": 627,
+            "top": 447
+        },
+        "type": "Loop",
+        "connections": [
+            "element356"
+        ],
+        "id": "element228"
+    },
+    {
+        "name": "jobstatus",
+        "position": {
+            "left": 251,
+            "top": 333
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element19"
+        ],
+        "id": "element150",
+        "publicInterface": "jobstatus.0",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}",
+        "path": {
+            "jobId": {
+                "type": "plan",
+                "value": "StartEvent.jobId"
+            }
+        },
+        "query": {},
+        "body": {
+            "progress": {
+                "type": "string",
+                "value": "20"
+            },
+            "errcode": {
+                "type": "plan",
+                "value": "StartEvent.vl_status"
+            },
+            "desc": {
+                "type": "string",
+                "value": ""
+            }
+        },
+        "output": {}
+    },
+    {
+        "name": "jobstatus",
+        "position": {
+            "left": 488,
+            "top": 443
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element156"
+        ],
+        "id": "element318",
+        "publicInterface": "jobstatus.0",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}",
+        "path": {
+            "jobId": {
+                "type": "plan",
+                "value": "StartEvent.jobId"
+            }
+        },
+        "query": {},
+        "body": {
+            "progress": {
+                "type": "string",
+                "value": "60"
+            },
+            "errcode": {
+                "type": "plan",
+                "value": "StartEvent.vnf_status"
+            },
+            "desc": {
+                "type": "string",
+                "value": ""
+            }
+        },
+        "output": {}
+    },
+    {
+        "name": "jobstatus",
+        "position": {
+            "left": 604.5,
+            "top": 512.5
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element386"
+        ],
+        "id": "element356",
+        "publicInterface": "jobstatus.0",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}",
+        "path": {
+            "jobId": {
+                "type": "plan",
+                "value": "StartEvent.jobId"
+            }
+        },
+        "query": {},
+        "body": {
+            "progress": {
+                "type": "string",
+                "value": "80"
+            },
+            "errcode": {
+                "type": "plan",
+                "value": "StartEvent.sfc_status"
+            },
+            "desc": {
+                "type": "string",
+                "value": ""
+            }
+        },
+        "output": {}
+    },
+    {
+        "name": "post_do",
+        "position": {
+            "left": 731.5,
+            "top": 106
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element369"
+        ],
+        "id": "element360",
+        "publicInterface": "ns postdeal.0",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/ns/{nsInstanceId}/postdeal",
+        "path": {
+            "nsInstanceId": {
+                "type": "plan",
+                "value": "StartEvent.nsInstanceId"
+            }
+        },
+        "query": {},
+        "body": {
+            "status": {
+                "type": "plan",
+                "value": "StartEvent.exec_status"
+            }
+        },
+        "output": {}
+    },
+    {
+        "name": "jobstatus",
+        "position": {
+            "left": 850,
+            "top": 106
+        },
+        "type": "RestTask",
+        "microservice": "nslcm",
+        "connections": [
+            "element31"
+        ],
+        "id": "element369",
+        "publicInterface": "jobstatus.0",
+        "method": "POST",
+        "accept": "application/json",
+        "contentType": "application/json",
+        "url": "http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}",
+        "path": {
+            "jobId": {
+                "type": "plan",
+                "value": "StartEvent.jobId"
+            }
+        },
+        "query": {},
+        "body": {
+            "progress": {
+                "type": "string",
+                "value": "100"
+            },
+            "errcode": {
+                "type": "plan",
+                "value": "StartEvent.exec_status"
+            },
+            "desc": {
+                "type": "string",
+                "value": ""
+            }
+        },
+        "output": {}
+    },
+    {
+        "name": "Assign_all_stauts",
+        "position": {
+            "left": 710,
+            "top": 512.5
+        },
+        "type": "Assign",
+        "connections": [
+            "element360"
+        ],
+        "id": "element386",
+        "params": {
+            "StartEvent.exec_status": {
+                "type": "expression",
+                "value": "starts-with($vl_status,'active') and contains($vnf_status,'active') and contains($sfc_status,'active')",
+                "extension": ""
+            }
+        }
+    }
+]
\ No newline at end of file
diff --git a/lcm/ns/data/init/deploy.xml b/lcm/ns/data/init/deploy.xml
new file mode 100644 (file)
index 0000000..688d88a
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+
+    Copyright 2016 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.
+
+-->
+<deploy xmlns="http://www.apache.org/ode/schemas/dd/2007/03"
+       xmlns:tns="http://www.zte.com.cn/tosca/nfv/ns"
+       xmlns:si="http://siserver.org/wsdl">
+       <process name="tns:init">
+               <active>true</active>
+               <retired>false</retired>
+               <process-events generate="all" />
+               <provide partnerLink="client">
+                       <service name="tns:initService" port="initPort" />
+               </provide>
+               <provide partnerLink="serviceInvokerPL">
+                       <service name="tns:initSICallback" port="initSICallbackPort" />
+               </provide>    
+               <invoke partnerLink="client">
+                       <service name="tns:initClientService" port="initClientPort" />
+               </invoke>
+               <invoke partnerLink="serviceInvokerPL">
+                       <service name="si:InvokerService" port="InvokePort" />
+               </invoke>
+       </process>
+</deploy>
diff --git a/lcm/ns/data/init/init.bpel b/lcm/ns/data/init/init.bpel
new file mode 100644 (file)
index 0000000..781b132
--- /dev/null
@@ -0,0 +1,1698 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+
+    Copyright 2016 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.
+
+-->
+<process xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="init"
+    xmlns:tns="http://www.zte.com.cn/tosca/nfv/ns"
+    targetNamespace="http://www.zte.com.cn/tosca/nfv/ns"
+    xmlns="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
+    xmlns:bpel4RestLight="http://iaas.uni-stuttgart.de/bpel/extensions/bpel4restlight"
+    xmlns:si="http://siserver.org/wsdl" 
+    xmlns:sischema="http://siserver.org/schema"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+    xmlns:ode="http://www.apache.org/ode/type/extension">
+
+    <import namespace="http://siserver.org/wsdl" location="invoker.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"></import>
+    <import importType="http://schemas.xmlsoap.org/wsdl/" location="init.wsdl"
+        namespace="http://www.zte.com.cn/tosca/nfv/ns" /> <!-- Todo place_holder wsdl and namespace -->
+
+    <extensions>
+        <extension mustUnderstand="yes"
+            namespace="http://iaas.uni-stuttgart.de/bpel/extensions/bpel4restlight" />
+    </extensions>
+
+    <partnerLinks>
+        <partnerLink name="client" initializePartnerRole="yes"
+            partnerLinkType="tns:initPLT" myRole="initProvider"
+            partnerRole="initClient" />
+
+        <partnerLink name="serviceInvokerPL"
+            initializePartnerRole="yes" partnerLinkType="tns:OpenTOSCAServiceInvokerPLT"
+            myRole="ServiceInvokerClient"  partnerRole="ServiceInvoker"  />    
+    </partnerLinks> 
+
+    <variables>
+        <variable name="input" messageType="tns:planInputMessage" />
+        <variable name="output" messageType="tns:planOutputMessage" />
+
+                <variable name="createVLResponse" type="xsd:string" />
+                <variable name="vl_index" type="xsd:string" />
+                <variable name="vnf_index" type="xsd:string" />
+                <variable name="sfc_index" type="xsd:string" />
+                <variable name="vnf_status" type="xsd:string" />
+                <variable name="sfc_status" type="xsd:string" />
+                <variable name="vl_status" type="xsd:string" />
+                <variable name="exec_status" type="xsd:string" />
+                <variable name="createVNFResponse" type="xsd:string" />
+                <variable name="query_vnf_nslcmResponse" type="xsd:string" />
+                <variable name="createSFCResponse" type="xsd:string" />
+                <variable name="querySFCResponse" type="xsd:string" />
+                                <variable name="jobId" type="xsd:string" />
+                <variable name="nsInstanceId" type="xsd:string" />
+                <variable name="object_context" type="xsd:string" />
+                <variable name="vlCount" type="xsd:string" />
+                <variable name="sfcCount" type="xsd:string" />
+                <variable name="vnfCount" type="xsd:string" />
+                <variable name="object_additionalParamForVnf" type="xsd:string" />
+                <variable name="sdnControllerId" type="xsd:string" />
+                <variable name="object_additionalParamForNs" type="xsd:string" />
+            </variables>
+
+    <correlationSets>
+        <correlationSet name="ServiceInvokerCS"
+            properties="tns:ServiceInvokerRequestProperty" />
+    </correlationSets>
+
+
+
+    <sequence>
+        <receive createInstance="yes" name="initiate" operation="initiatePlan"
+            partnerLink="client" portType="tns:initPT" variable="input" />
+
+        <!-- Get values for variables 'instanceDataAPIUrl', 'csarId', 'serviceTemplateId', 
+            'serviceInstanceId' from input message These values are required to read/write 
+            properties of the service instance the plan is working on -->
+        <assign name="initFromInputMsg" validate="no">
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:jobId]]></query>
+                </from>
+                <to variable="jobId" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:nsInstanceId]]></query>
+                </from>
+                <to variable="nsInstanceId" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:object_context]]></query>
+                </from>
+                <to variable="object_context" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:vlCount]]></query>
+                </from>
+                <to variable="vlCount" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:sfcCount]]></query>
+                </from>
+                <to variable="sfcCount" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:vnfCount]]></query>
+                </from>
+                <to variable="vnfCount" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:object_additionalParamForVnf]]></query>
+                </from>
+                <to variable="object_additionalParamForVnf" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:sdnControllerId]]></query>
+                </from>
+                <to variable="sdnControllerId" />
+            </copy>
+                        <copy>
+                <from variable="input" part="payload">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"><![CDATA[tns:object_additionalParamForNs]]></query>
+                </from>
+                <to variable="object_additionalParamForNs" />
+            </copy>
+                    </assign>
+
+        <assign name="initFromVarMsg" validate="no">
+                        <copy>
+                                <from>
+                    <literal></literal>
+                </from>
+                                <to variable="createVLResponse" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal>1</literal>
+                </from>
+                                <to variable="vl_index" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal>1</literal>
+                </from>
+                                <to variable="vnf_index" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal>1</literal>
+                </from>
+                                <to variable="sfc_index" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal>active</literal>
+                </from>
+                                <to variable="vnf_status" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal>active</literal>
+                </from>
+                                <to variable="sfc_status" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal>active</literal>
+                </from>
+                                <to variable="vl_status" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal>active</literal>
+                </from>
+                                <to variable="exec_status" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal></literal>
+                </from>
+                                <to variable="createVNFResponse" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal></literal>
+                </from>
+                                <to variable="query_vnf_nslcmResponse" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal></literal>
+                </from>
+                                <to variable="createSFCResponse" />
+            </copy>
+                        <copy>
+                                <from>
+                    <literal></literal>
+                </from>
+                                <to variable="querySFCResponse" />
+            </copy>
+                    </assign>
+        
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="While_WhileTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <while name="While">
+        <condition expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            $vl_index&lt;=$vlCount and $vl_status='active'
+        </condition>
+                <sequence name="While_WhileBranch_Sequence">
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="createVL" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+            </variables>
+    
+    <sequence name="createVL_Sequence">
+        <!-- build url start -->
+        <assign name="createVL_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/ns/vls</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="createVL_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="nsInstanceId">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"nsInstanceId":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_context">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"context":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_additionalParamForVnf">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"additionalParamForVnf":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_additionalParamForNs">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"additionalParamForNs":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="vl_index">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"vlIndex":"',$temp,'"')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='createVLResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+                <assign name="createVL_Response_result">
+            <copy>
+                <from variable="createVLResponse">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                    <![CDATA[//*[local-name()="result"]/text()]]>
+                    </query>
+                </from>
+                <to variable="vl_status"/>
+            </copy>
+        </assign>
+                            </sequence>
+</scope>
+
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="Assign_vl_index_AssignTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <assign name="Assign_vl_index_Assign">
+            <copy>
+                    <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            <![CDATA[$vl_index+1]]>
+            </from>
+                    <to variable="vl_index"/>
+        </copy>
+            <copy>
+                    <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            <![CDATA[concat(translate($vl_status,'0',''), 'active')]]>
+            </from>
+                    <to variable="vl_status"/>
+        </copy>
+        </assign>
+</scope>
+
+                    <wait name="Wait">
+                <for><![CDATA['PT01M30.0S']]></for>
+            </wait>
+        </sequence>
+    </while>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<!-- do nothing -->
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="jobstatus" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+                <!--temp var for response-->
+        <variable name="jobstatusResponse" type="xsd:string" />
+            </variables>
+    
+    <sequence name="jobstatus_Sequence">
+        <!-- build url start -->
+        <assign name="jobstatus_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+                <copy>
+                                    <from variable="jobId">
+                </from>
+                                    <to variable="temp"/>
+            </copy>
+        
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat(substring-before($url,'{jobId}'), $temp, substring-after($url,'{jobId}'))]]>
+                </from>
+                <to variable="url"></to>
+            </copy>
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="jobstatus_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="vl_status">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"errcode":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                            <from>
+                    <literal>20</literal>
+                </from>
+                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"progress":"',$temp,'"')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='jobstatusResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+        </sequence>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="While_WhileTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <while name="While">
+        <condition expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            $vnf_index&lt;=$vnfCount and $vl_status='active' and $vnf_status='active'
+        </condition>
+                <sequence name="While_WhileBranch_Sequence">
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="createVNF" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+            </variables>
+    
+    <sequence name="createVNF_Sequence">
+        <!-- build url start -->
+        <assign name="createVNF_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/ns/vnfs</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="createVNF_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="nsInstanceId">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"nsInstanceId":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_context">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"context":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_additionalParamForVnf">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"additionalParamForVnf":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_additionalParamForNs">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"additionalParamForNs":',$temp)]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='createVNFResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+                        </sequence>
+</scope>
+
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="RepeatUntil_RepeatTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <repeatUntil name="RepeatUntil">
+                <sequence name="RepeatUntil_RepeatBranch_Sequence">
+                                        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="query_vnf_nslcm" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+            </variables>
+    
+    <sequence name="query_vnf_nslcm_Sequence">
+        <!-- build url start -->
+        <assign name="query_vnf_nslcm_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/ns/vnfs/{vnfInstId}</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+                <copy>
+                                    <from variable="createVNFResponse">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                    <![CDATA[//*[local-name()="vnfInstId"]/text()]]>
+                    </query>
+                </from>
+                                    <to variable="temp"/>
+            </copy>
+        
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat(substring-before($url,'{vnfInstId}'), $temp, substring-after($url,'{vnfInstId}'))]]>
+                </from>
+                <to variable="url"></to>
+            </copy>
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="query_vnf_nslcm_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:GET contentType="application/json" accept="application/json" uri="$bpelvar[url]" response='query_vnf_nslcmResponse'></bpel4RestLight:GET>
+        </extensionActivity>
+            
+                        <assign name="query_vnf_nslcm_Response_vnfStatus">
+            <copy>
+                <from variable="query_vnf_nslcmResponse">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                    <![CDATA[//*[local-name()="vnfStatus"]/text()]]>
+                    </query>
+                </from>
+                <to variable="vnf_status"/>
+            </copy>
+        </assign>
+                    </sequence>
+</scope>
+
+                            <wait name="Wait">
+                <for><![CDATA['PT01M30.0S']]></for>
+            </wait>
+        </sequence>
+        <condition expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            $vnf_status='active' or $vnf_status='failed'
+        </condition>
+    </repeatUntil>
+</scope>
+
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<!-- do nothing -->
+
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="Assign_vnf_index_AssignTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <assign name="Assign_vnf_index_Assign">
+            <copy>
+                    <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            <![CDATA[$vnf_index+1]]>
+            </from>
+                    <to variable="vnf_index"/>
+        </copy>
+        </assign>
+</scope>
+
+                    <wait name="Wait">
+                <for><![CDATA['PT01M30.0S']]></for>
+            </wait>
+        </sequence>
+    </while>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<!-- do nothing -->
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="jobstatus" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+                <!--temp var for response-->
+        <variable name="jobstatusResponse" type="xsd:string" />
+            </variables>
+    
+    <sequence name="jobstatus_Sequence">
+        <!-- build url start -->
+        <assign name="jobstatus_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+                <copy>
+                                    <from variable="jobId">
+                </from>
+                                    <to variable="temp"/>
+            </copy>
+        
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat(substring-before($url,'{jobId}'), $temp, substring-after($url,'{jobId}'))]]>
+                </from>
+                <to variable="url"></to>
+            </copy>
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="jobstatus_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="vnf_status">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"errcode":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                            <from>
+                    <literal>60</literal>
+                </from>
+                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"progress":"',$temp,'"')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='jobstatusResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+        </sequence>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="While_WhileTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <while name="While">
+        <condition expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            $sfc_index&lt;=$sfcCount and $vl_status='active' and $vnf_status='active' and $sfc_status='active'
+        </condition>
+                <sequence name="While_WhileBranch_Sequence">
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="createSFC" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+            </variables>
+    
+    <sequence name="createSFC_Sequence">
+        <!-- build url start -->
+        <assign name="createSFC_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/ns/sfcs</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="createSFC_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="nsInstanceId">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"nsInstanceId":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_context">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"context":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="sdnControllerId">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"sdnControllerId":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_additionalParamForVnf">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"additionalParamForVnf":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="object_additionalParamForNs">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"additionalParamForNs":',$temp,',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                                            <from variable="sfc_index">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"fpindex":"',$temp,'"')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='createSFCResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+                        </sequence>
+</scope>
+
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="RepeatUntil_RepeatTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <repeatUntil name="RepeatUntil">
+                <sequence name="RepeatUntil_RepeatBranch_Sequence">
+                                        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="querySFC" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+            </variables>
+    
+    <sequence name="querySFC_Sequence">
+        <!-- build url start -->
+        <assign name="querySFC_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/ns/sfcs/{sfcInstId}</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+                <copy>
+                                    <from variable="createSFCResponse">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                    <![CDATA[//*[local-name()="sfcInstId"]/text()]]>
+                    </query>
+                </from>
+                                    <to variable="temp"/>
+            </copy>
+        
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat(substring-before($url,'{sfcInstId}'), $temp, substring-after($url,'{sfcInstId}'))]]>
+                </from>
+                <to variable="url"></to>
+            </copy>
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="querySFC_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:GET contentType="application/json" accept="application/json" uri="$bpelvar[url]" response='querySFCResponse'></bpel4RestLight:GET>
+        </extensionActivity>
+            
+                <assign name="querySFC_Response_sfcStatus">
+            <copy>
+                <from variable="querySFCResponse">
+                    <query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                    <![CDATA[//*[local-name()="sfcStatus"]/text()]]>
+                    </query>
+                </from>
+                <to variable="sfc_status"/>
+            </copy>
+        </assign>
+                            </sequence>
+</scope>
+
+                            <wait name="Wait">
+                <for><![CDATA['PT01M30.0S']]></for>
+            </wait>
+        </sequence>
+        <condition expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            $sfc_status='active' or $sfc_status='failed'
+        </condition>
+    </repeatUntil>
+</scope>
+
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<!-- do nothing -->
+
+                    <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="Assign_sfc_index_AssignTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <assign name="Assign_sfc_index_Assign">
+            <copy>
+                    <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            <![CDATA[$sfc_index+1]]>
+            </from>
+                    <to variable="sfc_index"/>
+        </copy>
+        </assign>
+</scope>
+
+                    <wait name="Wait">
+                <for><![CDATA['PT01M30.0S']]></for>
+            </wait>
+        </sequence>
+    </while>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<!-- do nothing -->
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="jobstatus" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+                <!--temp var for response-->
+        <variable name="jobstatusResponse" type="xsd:string" />
+            </variables>
+    
+    <sequence name="jobstatus_Sequence">
+        <!-- build url start -->
+        <assign name="jobstatus_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+                <copy>
+                                    <from variable="jobId">
+                </from>
+                                    <to variable="temp"/>
+            </copy>
+        
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat(substring-before($url,'{jobId}'), $temp, substring-after($url,'{jobId}'))]]>
+                </from>
+                <to variable="url"></to>
+            </copy>
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="jobstatus_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="sfc_status">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"errcode":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                            <from>
+                    <literal>80</literal>
+                </from>
+                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"progress":"',$temp,'"')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='jobstatusResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+        </sequence>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="Assign_all_stauts_AssignTask" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <assign name="Assign_all_stauts_Assign">
+            <copy>
+                    <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+            <![CDATA[starts-with($vl_status,'active') and contains($vnf_status,'active') and contains($sfc_status,'active')]]>
+            </from>
+                    <to variable="exec_status"/>
+        </copy>
+        </assign>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="post_do" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+                <!--temp var for response-->
+        <variable name="post_doResponse" type="xsd:string" />
+            </variables>
+    
+    <sequence name="post_do_Sequence">
+        <!-- build url start -->
+        <assign name="post_do_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/ns/{nsInstanceId}/postdeal</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+                <copy>
+                                    <from variable="nsInstanceId">
+                </from>
+                                    <to variable="temp"/>
+            </copy>
+        
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat(substring-before($url,'{nsInstanceId}'), $temp, substring-after($url,'{nsInstanceId}'))]]>
+                </from>
+                <to variable="url"></to>
+            </copy>
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="post_do_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="exec_status">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"status":"',$temp,'"')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='post_doResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+        </sequence>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<scope name="jobstatus" xmlns:pp="http://opentosca.org/api/pp"
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- add by qinlihan   add rest Components -->
+    <variables>
+        <variable name="request" type="xsd:string" />
+        <variable name="url" type="xsd:string" />
+        <variable name="temp" type="xsd:string" />
+                <!--temp var for response-->
+        <variable name="jobstatusResponse" type="xsd:string" />
+            </variables>
+    
+    <sequence name="jobstatus_Sequence">
+        <!-- build url start -->
+        <assign name="jobstatus_URL">
+            <copy>
+                <from>
+                    <literal>http://127.0.0.1:80/openoapi/nslcm/v1/jobs/{jobId}</literal>
+                </from>
+                <to variable="url"></to>
+            </copy>
+
+                <copy>
+                                    <from variable="jobId">
+                </from>
+                                    <to variable="temp"/>
+            </copy>
+        
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat(substring-before($url,'{jobId}'), $temp, substring-after($url,'{jobId}'))]]>
+                </from>
+                <to variable="url"></to>
+            </copy>
+        
+                </assign>
+        <!-- build url end -->
+    
+        <!-- build request start -->
+        <assign name="jobstatus_Request">
+                    <copy>
+                <from>
+                    <literal>{</literal>
+                </from>
+                <to variable="request"></to>
+            </copy>
+        
+                    <copy>
+                                            <from variable="exec_status">
+                </from>
+                                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"errcode":"',$temp,'"',',')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                            <from>
+                    <literal>100</literal>
+                </from>
+                            <to variable="temp"/>
+            </copy>
+            
+            <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                                <![CDATA[concat($request,'"progress":"',$temp,'"')]]>
+                                </from>
+                <to variable="request"></to>
+            </copy>
+                    <copy>
+                <from expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0">
+                <![CDATA[concat($request,'}')]]>
+                </from>
+                <to variable="request"></to>
+            </copy>
+            </assign>
+        <!-- build request end -->
+
+            <extensionActivity>
+            <bpel4RestLight:POST contentType="application/json" accept="application/json" request='request' response='jobstatusResponse' uri="$bpelvar[url]"></bpel4RestLight:POST>
+        </extensionActivity>
+            
+        </sequence>
+</scope>
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+        <!--
+    Copyright 2016 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.
+
+-->
+
+<!-- do nothing -->
+
+        <!--"/src/main/resources/templates/bpel_management_activity_scope_template.xml"-->
+    </sequence>
+</process>
diff --git a/lcm/ns/data/init/init.wsdl b/lcm/ns/data/init/init.wsdl
new file mode 100644 (file)
index 0000000..ff37558
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright 2016 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.
+
+-->
+<definitions name="init"
+    targetNamespace="http://www.zte.com.cn/tosca/nfv/ns"
+    xmlns:tns="http://www.zte.com.cn/tosca/nfv/ns"
+    xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
+    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:vprop="http://docs.oasis-open.org/wsbpel/2.0/varprop"
+    xmlns:si="http://siserver.org/wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    >
+
+    <import namespace="http://siserver.org/wsdl" location="invoker.wsdl" />
+    <types>
+        <schema attributeFormDefault="unqualified" elementFormDefault="qualified"
+            targetNamespace="http://www.zte.com.cn/tosca/nfv/ns"
+            xmlns="http://www.w3.org/2001/XMLSchema">
+            <element name="planInput">
+                <complexType>
+                    <sequence>
+                                                    <element name="jobId" type="string" />
+                                                    <element name="nsInstanceId" type="string" />
+                                                    <element name="object_context" type="string" />
+                                                    <element name="vlCount" type="string" />
+                                                    <element name="sfcCount" type="string" />
+                                                    <element name="vnfCount" type="string" />
+                                                    <element name="object_additionalParamForVnf" type="string" />
+                                                    <element name="sdnControllerId" type="string" />
+                                                    <element name="object_additionalParamForNs" type="string" />
+                                            </sequence>
+                </complexType>
+            </element>
+            <element name="planOutput">
+                <complexType>
+                    <sequence>
+                        <element name="correlationId" type="string" />
+                        <!-- Relevant if build plan was executed that created a new service 
+                            instance -->
+                        <element name="serviceInstanceId" type="string" />
+                        
+                                            </sequence>
+                </complexType>
+            </element>
+        </schema>
+    </types>
+
+    <message name="planInputMessage">
+        <part name="payload" element="tns:planInput" />
+    </message>
+    <message name="planOutputMessage">
+        <part name="payload" element="tns:planOutput" />
+    </message>
+
+
+    <plnk:partnerLinkType name="initPLT">
+        <plnk:role name="initProvider" portType="tns:initPT" />
+        <plnk:role name="initClient" portType="tns:initClientCallbackPT" />
+    </plnk:partnerLinkType>
+    <plnk:partnerLinkType name="OpenTOSCAServiceInvokerPLT">
+        <plnk:role name="ServiceInvokerClient" portType="si:CallbackPortType" />
+        <plnk:role name="ServiceInvoker" portType="si:InvokePortType" />
+    </plnk:partnerLinkType>
+
+    <vprop:property name="ServiceInvokerRequestProperty"
+        type="xsd:string" />
+
+    <vprop:propertyAlias messageType="si:invokeOperationAsyncMessage"
+        part="invokeOperationAsync" propertyName="tns:ServiceInvokerRequestProperty">
+        <vprop:query><![CDATA[//*[local-name()="MessageID" and namespace-uri()="http://siserver.org/schema"]]]></vprop:query>
+    </vprop:propertyAlias>
+
+    <vprop:propertyAlias messageType="si:invokeResponse"
+        part="invokeResponse" propertyName="tns:ServiceInvokerRequestProperty">
+        <vprop:query><![CDATA[//*[local-name()="MessageID" and namespace-uri()="http://siserver.org/schema"]]]></vprop:query>
+    </vprop:propertyAlias>
+
+    <!-- Port type provides the operation to the client for starting the plan 
+        plan -->
+    <portType name="initPT">
+        <operation name="initiatePlan">
+            <input message="tns:planInputMessage" />
+        </operation>
+    </portType>
+
+    <portType name="initClientCallbackPT">
+        <operation name="onResult">
+            <input message="tns:planOutputMessage" />
+        </operation>
+    </portType>
+
+
+
+
+    <binding name="initPTBinding" type="tns:initPT">
+        <soap:binding style="document"
+            transport="http://schemas.xmlsoap.org/soap/http" />
+        <operation name="initiatePlan">
+            <soap:operation
+                soapAction="http://www.zte.com.cn/tosca/nfv/ns/initiate" />
+            <input>
+                <soap:body use="literal" />
+            </input>
+        </operation>
+    </binding>
+    <binding name="initClientPTBinding" type="tns:initClientCallbackPT">
+        <soap:binding style="document"
+            transport="http://schemas.xmlsoap.org/soap/http" />
+        <operation name="onResult">
+            <soap:operation
+                soapAction="http://www.zte.com.cn/tosca/nfv/ns/onResult" />
+            <input>
+                <soap:body use="literal" />
+            </input>
+        </operation>
+    </binding>
+
+
+    <service name="initService">
+        <port name="initPort" binding="tns:initPTBinding">
+            <soap:address location="http://localhost:8080/init" />
+        </port>
+    </service>
+
+    <service name="initClientService">
+        <port name="initClientPort" binding="tns:initClientPTBinding">
+            <soap:address location="http://localhost:8080/initClient" />
+        </port>
+    </service>
+
+    <service name="initSICallback">
+        <port binding="si:CallbackBinding" name="initSICallbackPort">
+            <soap:address location="http://localhost:9763/services/initSICallback/"/>
+        </port>
+    </service>
+</definitions>
\ No newline at end of file
diff --git a/lcm/ns/data/init/invoker.wsdl b/lcm/ns/data/init/invoker.wsdl
new file mode 100644 (file)
index 0000000..ff6ed84
--- /dev/null
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+    xmlns:tns="http://siserver.org/wsdl"
+    xmlns:ns="http://siserver.org/schema"
+    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+    name="SIServerImplService"
+    targetNamespace="http://siserver.org/wsdl">
+
+    <wsdl:types>
+        <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema">
+            <xsd:import
+                namespace="http://siserver.org/schema"
+                schemaLocation="invoker.xsd" />
+        </xsd:schema>
+    </wsdl:types>
+    <wsdl:message name="invokeOperationMessage">
+        <wsdl:part
+            element="ns:invokeOperation"
+            name="invokeOperation">
+        </wsdl:part>
+    </wsdl:message>
+    <wsdl:message name="invokeOperationAsyncMessage">
+        <wsdl:part
+            element="ns:invokeOperationAsync"
+            name="invokeOperationAsync">
+        </wsdl:part>
+    </wsdl:message>
+    <wsdl:message name="invokeOperationSyncMessage">
+        <wsdl:part
+            element="ns:invokeOperationSync"
+            name="invokeOperationSync">
+        </wsdl:part>
+    </wsdl:message>
+    <wsdl:message name="invokePlanMessage">
+        <wsdl:part
+            element="ns:invokePlan"
+            name="invokePlan">
+        </wsdl:part>
+    </wsdl:message>
+    <wsdl:message name="invokeResponse">
+        <wsdl:part
+            element="ns:invokeResponse"
+            name="invokeResponse">
+        </wsdl:part>
+    </wsdl:message>
+    <wsdl:portType name="InvokePortType">
+        <wsdl:operation name="invokeOperation">
+            <wsdl:input message="tns:invokeOperationMessage">
+            </wsdl:input>
+        </wsdl:operation>
+        <wsdl:operation name="invokeOperationAsync">
+            <wsdl:input message="tns:invokeOperationAsyncMessage">
+            </wsdl:input>
+        </wsdl:operation>
+        <wsdl:operation name="invokeOperationSync">
+            <wsdl:input message="tns:invokeOperationSyncMessage">
+            </wsdl:input>
+            <wsdl:output message="tns:invokeResponse">
+            </wsdl:output>
+        </wsdl:operation>
+        <wsdl:operation name="invokePlan">
+            <wsdl:input message="tns:invokePlanMessage">
+            </wsdl:input>
+        </wsdl:operation>
+    </wsdl:portType>
+    <wsdl:portType name="CallbackPortType">
+        <wsdl:operation name="callback">
+            <wsdl:input message="tns:invokeResponse">
+            </wsdl:input>
+        </wsdl:operation>
+    </wsdl:portType>
+    <wsdl:binding
+        name="InvokeBinding"
+        type="tns:InvokePortType">
+        <soap:binding
+            style="document"
+            transport="http://schemas.xmlsoap.org/soap/http" />
+        <wsdl:operation name="invokeOperation">
+            <soap:operation
+                soapAction="http://siserver.org/invokeOperation"
+                style="document" />
+            <wsdl:input>
+                <soap:body use="literal" />
+            </wsdl:input>
+        </wsdl:operation>
+        <wsdl:operation name="invokeOperationAsync">
+            <soap:operation
+                soapAction="http://siserver.org/invokeOperationAsync"
+                style="document" />
+            <wsdl:input>
+                <soap:body use="literal" />
+            </wsdl:input>
+        </wsdl:operation>
+        <wsdl:operation name="invokeOperationSync">
+            <soap:operation
+                soapAction="http://siserver.org/invokeOperationSync"
+                style="document" />
+            <wsdl:input>
+                <soap:body use="literal" />
+            </wsdl:input>
+            <wsdl:output>
+                <soap:body use="literal" />
+            </wsdl:output>
+        </wsdl:operation>
+        <wsdl:operation name="invokePlan">
+            <soap:operation
+                soapAction="http://siserver.org/invokePlan"
+                style="document" />
+            <wsdl:input>
+                <soap:body use="literal" />
+            </wsdl:input>
+        </wsdl:operation>
+    </wsdl:binding>
+    <wsdl:binding
+        name="CallbackBinding"
+        type="tns:CallbackPortType">
+        <soap:binding
+            style="document"
+            transport="http://schemas.xmlsoap.org/soap/http" />
+        <wsdl:operation name="callback">
+            <wsdl:input>
+                <soap:body use="literal" />
+            </wsdl:input>
+        </wsdl:operation>
+    </wsdl:binding>
+    <!-- Note, in original invoker.wsdl the service element was hosting InvokerPort 
+        and CallbackPort. This resulted in crashes of the Apache ODE (WSO2 BPS) as 
+        it only distinguishes bey service name -->
+    <wsdl:service name="InvokerService">
+        <wsdl:port
+            name="CallbackPort"
+            binding="tns:CallbackBinding">
+            <soap:address location="http://localhost:8088/callback" />
+        </wsdl:port>
+        <wsdl:port
+            name="InvokePort"
+            binding="tns:InvokeBinding">
+            <soap:address location="http://0.0.0.0:8081/invoker" />
+        </wsdl:port>
+    </wsdl:service>
+</wsdl:definitions>
\ No newline at end of file
diff --git a/lcm/ns/data/init/invoker.xsd b/lcm/ns/data/init/invoker.xsd
new file mode 100644 (file)
index 0000000..6874551
--- /dev/null
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright 2016 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.
+
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+       xmlns:ns="http://siserver.org/schema" attributeFormDefault="qualified"
+       elementFormDefault="qualified" targetNamespace="http://siserver.org/schema">
+       <xs:complexType name="ParamsMapItemType">
+               <xs:sequence>
+                       <xs:element name="key" type="xs:string" />
+                       <xs:element name="value" type="xs:string" />
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="ParamsMap">
+               <xs:sequence>
+                       <xs:element minOccurs="0" maxOccurs="unbounded" name="Param"
+                               type="ns:ParamsMapItemType" />
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="Doc">
+               <xs:sequence>
+                       <xs:any minOccurs="0" maxOccurs="1" processContents="skip" />
+               </xs:sequence>
+       </xs:complexType>
+       <xs:element name="invokeOperation" type="ns:invokeOperationAsync" />
+       <xs:element name="invokeOperationAsync" type="ns:invokeOperationAsync" />
+       <xs:complexType name="invokeOperationAsync">
+               <xs:sequence>
+                       <xs:element minOccurs="1" maxOccurs="1" name="CsarID"
+                               type="xs:string" />
+                       <xs:element minOccurs="0" maxOccurs="1" name="ServiceInstanceID"
+                               type="xs:string" />
+                       <xs:element minOccurs="0" maxOccurs="1" name="NodeInstanceID"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1"
+                               name="ServiceTemplateIDNamespaceURI" type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1"
+                               name="ServiceTemplateIDLocalPart" type="xs:string" />
+                       <xs:choice>
+                               <xs:element minOccurs="1" maxOccurs="1" name="NodeTemplateID"
+                                       type="xs:string" />
+                               <xs:element minOccurs="1" maxOccurs="1"
+                                       name="RelationshipTemplateID" type="xs:string" />
+                       </xs:choice>
+                       <xs:element minOccurs="0" maxOccurs="1" name="InterfaceName"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="OperationName"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="ReplyTo"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="MessageID"
+                               type="xs:string" />
+                       <xs:choice>
+                               <xs:element minOccurs="0" name="Params" type="ns:ParamsMap" />
+                               <xs:element minOccurs="0" name="Doc" type="ns:Doc" />
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:element name="invokeOperationSync" type="ns:invokeOperationSync" />
+       <xs:complexType name="invokeOperationSync">
+               <xs:sequence>
+                       <xs:element minOccurs="1" maxOccurs="1" name="CsarID"
+                               type="xs:string" />
+                       <xs:element minOccurs="0" maxOccurs="1" name="ServiceInstanceID"
+                               type="xs:string" />
+                       <xs:element minOccurs="0" maxOccurs="1" name="NodeInstanceID"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1"
+                               name="ServiceTemplateIDNamespaceURI" type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1"
+                               name="ServiceTemplateIDLocalPart" type="xs:string" />
+                       <xs:choice>
+                               <xs:element minOccurs="1" maxOccurs="1" name="NodeTemplateID"
+                                       type="xs:string" />
+                               <xs:element minOccurs="1" maxOccurs="1"
+                                       name="RelationshipTemplateID" type="xs:string" />
+                       </xs:choice>
+                       <xs:element minOccurs="0" maxOccurs="1" name="InterfaceName"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="OperationName"
+                               type="xs:string" />
+                       <xs:choice>
+                               <xs:element minOccurs="0" name="Params" type="ns:ParamsMap" />
+                               <xs:element minOccurs="0" name="Doc" type="ns:Doc" />
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:element name="invokePlan" type="ns:invokePlan" />
+       <xs:complexType name="invokePlan">
+               <xs:sequence>
+                       <xs:element minOccurs="1" maxOccurs="1" name="CsarID"
+                               type="xs:string" />
+                       <xs:element minOccurs="0" maxOccurs="1" name="ServiceInstanceID"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="PlanIDNamespaceURI"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="PlanIDLocalPart"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="OperationName"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="ReplyTo"
+                               type="xs:string" />
+                       <xs:element minOccurs="1" maxOccurs="1" name="MessageID"
+                               type="xs:string" />
+                       <xs:choice>
+                               <xs:element minOccurs="0" name="Params" type="ns:ParamsMap" />
+                               <xs:element minOccurs="0" name="Doc" type="ns:Doc" />
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:element name="invokeResponse" type="ns:invokeResponse" />
+       <xs:complexType name="invokeResponse">
+               <xs:sequence>
+                       <xs:element minOccurs="0" maxOccurs="1" name="MessageID"
+                               type="xs:string" />
+                       <xs:choice>
+                               <xs:element minOccurs="0" name="Params" type="ns:ParamsMap" />
+                               <xs:element minOccurs="0" name="Doc" type="ns:Doc" />
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/lcm/ns/data/scalemapping.json b/lcm/ns/data/scalemapping.json
new file mode 100644 (file)
index 0000000..410332c
--- /dev/null
@@ -0,0 +1,112 @@
+{
+    "scale_options": [
+        {
+            "ns_instanceId":"23",
+            "ns_scale_aspect": "TIC_EDGE_IMS",
+            "ns_scale_info_list": [
+                {
+                    "step": "1",
+                    "vnf_scale_list":[
+                        {
+                            "vnfInstanceId":"nf_zte_cscf",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        },
+                        {
+                            "vnfInstanceId":"nf_zte_hss",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        }
+                    ]
+                },
+                {
+                    "step": "2",
+                    "vnf_scale_list":[
+                        {
+                            "vnfInstanceId":"nf_zte_cscf",
+                            "vnf_scaleAspectId": "mpu",
+                            "numberOfSteps": "1"
+                        },
+                        {
+                            "vnfInstanceId":"nf_zte_hss",
+                            "vnf_scaleAspectId": "mpu",
+                            "numberOfSteps": "1"
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "ns_instanceId":"23",
+            "ns_scale_aspect": "TIC_EDGE_HW",
+            "ns_scale_info_list": [
+                {
+                    "step": "4",
+                    "vnf_scale_list":[
+                        {
+                            "vnfInstanceId":"nf_hw_cscf",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        },
+                        {
+                            "vnfInstanceId":"nf_hw_hss",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        }
+                    ]
+                },
+                {
+                    "step": "6",
+                    "vnf_scale_list":[
+                        {
+                            "vnfInstanceId":"nf_HW_cscf",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        },
+                        {
+                            "vnfInstanceId":"nf_HW_hss",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "ns_instanceId":"235",
+            "ns_scale_aspect": "TIC_EDGE_HW",
+            "ns_scale_info_list": [
+                {
+                    "step": "4",
+                    "vnf_scale_list":[
+                        {
+                            "vnfInstanceId":"nf_hw_cscf",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "123"
+                        },
+                        {
+                            "vnfInstanceId":"nf_hw_hss",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "456"
+                        }
+                    ]
+                },
+                {
+                    "step": "6",
+                    "vnf_scale_list":[
+                        {
+                            "vnfInstanceId":"nf_HW_cscf",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        },
+                        {
+                            "vnfInstanceId":"nf_HW_hss",
+                            "vnf_scaleAspectId": "gpu",
+                            "numberOfSteps": "1"
+                        }
+                    ]
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/lcm/ns/ns_create.py b/lcm/ns/ns_create.py
new file mode 100644 (file)
index 0000000..69d7ae5
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright 2016 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 uuid
+
+from lcm.pub.database.models import NSDModel, NSInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.timeutil import now_time
+
+logger = logging.getLogger(__name__)
+
+
+class CreateNSService(object):
+    def __init__(self, nsd_id, ns_name, description):
+        self.nsd_id = nsd_id
+        self.ns_name = ns_name
+        self.description = description
+        self.ns_inst_id = ''
+        self.ns_package_id = ''
+
+    def do_biz(self):
+        self.check_nsd_valid()
+        self.check_ns_inst_name_exist()
+        self.create_ns_inst()
+        logger.debug("CreateNSService::do_biz::ns_inst_id=%s" % self.ns_inst_id)
+        return self.ns_inst_id
+
+    def check_nsd_valid(self):
+        logger.debug("CreateNSService::check_nsd_valid::nsd_id=%s" % self.nsd_id)
+        ns_package_info = NSDModel.objects.filter(nsd_id=self.nsd_id)
+        if not ns_package_info:
+            raise NSLCMException("nsd(%s) not exists." % self.nsd_id)
+        self.ns_package_id = ns_package_info[0].id
+        logger.debug("CreateNSService::check_nsd_valid::ns_package_id=%s" % self.ns_package_id)
+
+    def check_ns_inst_name_exist(self):
+        is_exist = NSInstModel.objects.filter(name=self.ns_name).exists()
+        logger.debug("CreateNSService::check_ns_inst_name_exist::is_exist=%s" % is_exist)
+        if is_exist:
+            raise NSLCMException("ns(%s) already existed." % self.ns_name)
+
+    def create_ns_inst(self):
+        self.ns_inst_id = str(uuid.uuid4())
+        logger.debug("CreateNSService::create_ns_inst::ns_inst_id=%s" % self.ns_inst_id)
+        NSInstModel(id=self.ns_inst_id, name=self.ns_name, nspackage_id=self.ns_package_id, 
+                    nsd_id=self.nsd_id, description=self.description, status='empty', 
+                    lastuptime=now_time()).save()
+
diff --git a/lcm/ns/ns_get.py b/lcm/ns/ns_get.py
new file mode 100644 (file)
index 0000000..15f20e1
--- /dev/null
@@ -0,0 +1,127 @@
+# Copyright 2016 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
+import traceback
+
+from lcm.ns.const import OWNER_TYPE
+from lcm.pub.database.models import NSInstModel, NfInstModel, VLInstModel, CPInstModel, VNFFGInstModel
+
+logger = logging.getLogger(__name__)
+
+
+class GetNSInfoService(object):
+    def __init__(self, ns_inst_id=None):
+        self.ns_inst_id = ns_inst_id
+
+    def get_ns_info(self):
+        try:
+            if self.ns_inst_id:
+                return self.get_single_ns_info(self.ns_inst_id)
+            else:
+                return self.get_total_ns_info()
+        except:
+            logger.error(traceback.format_exc())
+            return None if self.ns_inst_id else []
+
+    def get_total_ns_info(self):
+        ns_inst_infos = NSInstModel.objects.all()
+        ns_info_list = []
+        for info in ns_inst_infos:
+            ret = self.get_single_ns_info(info.id)
+            if not ret:
+                continue
+            ns_info_list.append(ret)
+        return ns_info_list
+
+    def get_single_ns_info(self, ns_inst_id):
+        ns_insts = NSInstModel.objects.filter(id=ns_inst_id)
+        if not ns_insts:
+            return None
+        ns_inst_info = ns_insts[0]
+        ret = {
+            'nsInstanceId': ns_inst_info.id,
+            'nsName': ns_inst_info.name,
+            'description': ns_inst_info.description,
+            'nsdId': ns_inst_info.nsd_id,
+            'vnfInfoId': self.get_vnf_infos(ns_inst_id),
+            'vlInfo': self.get_vl_infos(ns_inst_id),
+            'vnffgInfo': self.get_vnffg_infos(ns_inst_id, ns_inst_info.nsd_model),
+            'nsState': ns_inst_info.status}
+        return ret
+
+    @staticmethod
+    def get_vnf_infos(ns_inst_id):
+        ns_inst_infos = NfInstModel.objects.filter(ns_inst_id=ns_inst_id)
+        vnf_info_list = []
+        for info in ns_inst_infos:
+            vnf_info = {
+                'vnfInstanceId': info.nfinstid,
+                'vnfInstanceName': info.nf_name,
+                'vnfProfileId': info.vnf_id}
+            vnf_info_list.append(vnf_info)
+        return vnf_info_list
+
+    def get_vl_infos(self, ns_inst_id):
+        vl_inst_infos = VLInstModel.objects.filter(ownertype=OWNER_TYPE.NS, ownerid=ns_inst_id)
+        vl_info_list = []
+        for info in vl_inst_infos:
+            vl_info = {
+                'vlInstanceId': info.vlinstanceid,
+                'vlInstanceName': info.vlinstancename,
+                'vldId': info.vldid,
+                'relatedCpInstanceId': self.get_cp_infos(info.vlinstanceid)}
+            vl_info_list.append(vl_info)
+        return vl_info_list
+
+    @staticmethod
+    def get_cp_infos(vl_inst_id):
+        cp_inst_infos = CPInstModel.objects.filter(relatedvl__icontains=vl_inst_id)
+        cp_info_list = []
+        for info in cp_inst_infos:
+            cp_info = {
+                'cpInstanceId': info.cpinstanceid,
+                'cpInstanceName': info.cpname,
+                'cpdId': info.cpdid}
+            cp_info_list.append(cp_info)
+        return cp_info_list
+
+    def get_vnffg_infos(self, ns_inst_id, nsd_model):
+        vnffg_inst_infos = VNFFGInstModel.objects.filter(nsinstid=ns_inst_id)
+        vnffg_info_list = []
+        for info in vnffg_inst_infos:
+            vnffg_info = {
+                'vnffgInstanceId': info.vnffginstid,
+                'vnfId': self.convert_string_to_list(info.vnflist),
+                'pnfId': self.get_pnf_infos(nsd_model),
+                'virtualLinkId': self.convert_string_to_list(info.vllist),
+                'cpId': self.convert_string_to_list(info.cplist),
+                'nfp': self.convert_string_to_list(info.fplist)}
+            vnffg_info_list.append(vnffg_info)
+        return vnffg_info_list
+
+    @staticmethod
+    def get_pnf_infos(nsd_model):
+        context = json.loads(nsd_model)
+        pnfs = context['pnfs']
+        pnf_list = []
+        for pnf in pnfs:
+            pnf_list.append(pnf['pnf_id'])
+        return pnf_list
+
+    @staticmethod
+    def convert_string_to_list(detail_id_string):
+        if not detail_id_string:
+            return None
+        return detail_id_string.split(',')
diff --git a/lcm/ns/ns_instant.py b/lcm/ns/ns_instant.py
new file mode 100644 (file)
index 0000000..8f0f1c6
--- /dev/null
@@ -0,0 +1,185 @@
+# Copyright 2016-2017 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
+import traceback
+import time
+import uuid
+
+from rest_framework import status
+
+from lcm.pub.database.models import DefPkgMappingModel, ServiceBaseInfoModel, InputParamMappingModel
+from lcm.pub.database.models import NSInstModel, NfPackageModel, VNFFGInstModel
+from lcm.pub.msapi.catalog import get_process_id, get_download_url_from_catalog
+from lcm.pub.msapi.catalog import query_rawdata_from_catalog, get_servicetemplate_id, get_servicetemplate
+from lcm.pub.msapi.wso2bpel import workflow_run
+from lcm.pub.msapi.extsys import select_vnfm
+from lcm.pub.utils.jobutil import JobUtil
+from lcm.pub.utils import toscautil
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.exceptions import NSLCMException
+
+logger = logging.getLogger(__name__)
+
+
+class InstantNSService(object):
+    def __init__(self, ns_inst_id, plan_content):
+        self.ns_inst_id = ns_inst_id
+        self.req_data = plan_content
+
+    def do_biz(self):
+        try:
+            job_id = JobUtil.create_job("NS", "NS_INST", self.ns_inst_id)
+            logger.debug('ns-instant(%s) workflow starting...' % self.ns_inst_id)
+            logger.debug('req_data=%s' % self.req_data)
+            ns_inst = NSInstModel.objects.get(id=self.ns_inst_id)
+
+            input_parameters = []
+            for key, val in self.req_data['additionalParamForNs'].items():
+                input_parameters.append({"key": key, "value": val})
+
+            vim_id = ''
+            if 'location' in self.req_data['additionalParamForNs']:
+                vim_id = self.req_data['additionalParamForNs']['location']
+            location_constraints = []
+            if 'locationConstraints' in self.req_data:
+                location_constraints = self.req_data['locationConstraints']
+            
+            JobUtil.add_job_status(job_id, 5, 'Start query nsd(%s)' % ns_inst.nspackage_id)
+            src_plan = query_rawdata_from_catalog(ns_inst.nspackage_id, input_parameters)
+            dst_plan = toscautil.convert_nsd_model(src_plan["rawData"])
+            logger.debug('tosca plan dest:%s' % dst_plan)
+            NSInstModel.objects.filter(id=self.ns_inst_id).update(nsd_model=dst_plan)
+
+            params_json = json.JSONEncoder().encode(self.req_data["additionalParamForNs"])
+            # start
+            params_vnf = []
+            plan_dict = json.JSONDecoder().decode(dst_plan)
+            for vnf in ignore_case_get(plan_dict, "vnfs"):
+                vnfd_id = vnf['properties']['id']
+                vnfd = NfPackageModel.objects.get(vnfdid=vnfd_id)
+                vnfd_model = json.JSONDecoder().decode(vnfd.vnfdmodel)
+                vnfm_type = vnfd_model["metadata"].get("vnfmType", "ztevmanagerdriver")
+                vimid = self.get_vnf_vim_id(vim_id, location_constraints, vnfd_id)
+                vnfm_info = select_vnfm(vnfm_type=vnfm_type, vim_id=vimid)
+                params_vnf.append({
+                    "vnfProfileId": vnf["vnf_id"],
+                    "additionalParam": {
+                        "vimId": vimid,
+                        "vnfmInstanceId": vnfm_info["vnfmId"],
+                        "vnfmType": vnfm_type,
+                        "inputs": params_json
+                    }
+                })
+            # end
+            
+            self.set_vl_vim_id(vim_id, location_constraints, plan_dict)
+            dst_plan = json.JSONEncoder().encode(plan_dict)
+            logger.debug('tosca plan dest add vimid:%s' % dst_plan)
+            NSInstModel.objects.filter(id=self.ns_inst_id).update(nsd_model=dst_plan)
+            
+            vnf_params_json = json.JSONEncoder().encode(params_vnf)
+            plan_input = {'jobId': job_id, 
+                'nsInstanceId': self.req_data["nsInstanceId"],
+                'object_context': dst_plan,
+                'object_additionalParamForNs': params_json,
+                'object_additionalParamForVnf': vnf_params_json}
+            plan_input.update(**self.get_model_count(dst_plan))
+            plan_input["sdnControllerId"] = ignore_case_get(
+                self.req_data['additionalParamForNs'], "sdncontroller")
+
+            ServiceBaseInfoModel(service_id=self.ns_inst_id,
+                                 service_name=ns_inst.name,
+                                 service_type='NFVO',
+                                 description=ns_inst.description,
+                                 active_status='--',
+                                 status=ns_inst.status,
+                                 creator='--',
+                                 create_time=int(time.time()*1000)).save()
+
+            service_tpl = get_servicetemplate(ns_inst.nsd_id)
+            DefPkgMappingModel(service_id=self.ns_inst_id,
+                               service_def_id=service_tpl['csarId'],
+                               template_name=service_tpl['templateName'],
+                               template_id=service_tpl['serviceTemplateId']).save()
+
+            for key, val in self.req_data['additionalParamForNs'].items():
+                InputParamMappingModel(service_id=self.ns_inst_id,
+                    input_key=key, input_value=val).save()
+
+            for vnffg in ignore_case_get(plan_dict, "vnffgs"):
+                VNFFGInstModel(vnffgdid=vnffg["vnffg_id"],
+                    vnffginstid=str(uuid.uuid4()),
+                    nsinstid=self.ns_inst_id,
+                    endpointnumber=0).save()
+
+            servicetemplate_id = get_servicetemplate_id(ns_inst.nsd_id)
+            process_id = get_process_id('init', servicetemplate_id)
+            data = {"processId": process_id, "params": {"planInput": plan_input}}
+            logger.debug('ns-instant(%s) workflow data:%s' % (self.ns_inst_id, data))
+
+            ret = workflow_run(data)
+            logger.info("ns-instant(%s) workflow result:%s" % (self.ns_inst_id, ret))
+            JobUtil.add_job_status(job_id, 10, 'NS inst(%s) workflow started: %s' % (
+                self.ns_inst_id, ret.get('status')))
+            if ret.get('status') == 1:
+                return dict(data={'jobId': job_id}, status=status.HTTP_200_OK)
+            return dict(data={'error': ret['message']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            logger.error("ns-instant(%s) workflow error:%s" % (self.ns_inst_id, e.message))
+            JobUtil.add_job_status(job_id, 255, 'NS instantiation failed: %s' % e.message)
+            return dict(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+            
+    def get_vnf_vim_id(self, vim_id, location_constraints, vnfdid):
+        for location in location_constraints:
+            if "vnfProfileId" in location and vnfdid == location["vnfProfileId"]:
+                return location["locationConstraints"]["vimId"]
+        if vim_id:
+            return vim_id
+        raise NSLCMException("No Vim info is found for vnf(%s)." % vnfdid)
+        
+    def set_vl_vim_id(self, vim_id, location_constraints, plan_dict):
+        if "vls" not in plan_dict:
+            logger.debug("No vl is found in nsd.")
+            return
+        vl_vnf = {}
+        for vnf in ignore_case_get(plan_dict, "vnfs"):
+            if "dependencies" in vnf:
+                for depend in vnf["dependencies"]:
+                    vl_vnf[depend["vl_id"]] = vnf['properties']['id']
+        vnf_vim = {}
+        for location in location_constraints:
+            if "vnfProfileId" in location:
+                vnfd_id = location["vnfProfileId"]
+                vnf_vim[vnfd_id] = location["locationConstraints"]["vimId"]
+        for vl in plan_dict["vls"]:
+            vnfdid = ignore_case_get(vl_vnf, vl["vl_id"])
+            vimid = ignore_case_get(vnf_vim, vnfdid)
+            if not vimid:
+                vimid = vim_id
+            if not vimid:
+                raise NSLCMException("No Vim info for vl(%s) of vnf(%s)." % (vl["vl_id"], vnfdid))
+            if "location_info" not in vl["properties"]:
+                vl["properties"]["location_info"] = {}
+            vl["properties"]["location_info"]["vimid"] = vimid
+       
+    @staticmethod
+    def get_model_count(context):
+        data = json.JSONDecoder().decode(context)
+        vls = len(data.get('vls', []))
+        sfcs = len(data.get('fps', []))
+        vnfs = len(data.get('vnfs', []))
+        return {'vlCount': str(vls), 'sfcCount': str(sfcs), 'vnfCount': str(vnfs)}
diff --git a/lcm/ns/ns_manual_scale.py b/lcm/ns/ns_manual_scale.py
new file mode 100644 (file)
index 0000000..dc2d1b4
--- /dev/null
@@ -0,0 +1,129 @@
+# Copyright 2017 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 datetime
+import logging
+import threading
+import time
+import traceback
+
+from lcm.ns.const import NS_INST_STATUS
+from lcm.ns.vnfs.scale_vnfs import NFManualScaleService
+from lcm.pub.database.models import JobModel, NSInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.jobutil import JobUtil, JOB_MODEL_STATUS
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.utils.scaleaspect import get_scale_vnf_data
+
+JOB_ERROR = 255
+SCALE_TYPE = ("SCALE_NS", "SCALE_VNF")
+logger = logging.getLogger(__name__)
+
+
+class NSManualScaleService(threading.Thread):
+    def __init__(self, ns_instance_id, request_data, job_id):
+        super(NSManualScaleService, self).__init__()
+        self.ns_instance_id = ns_instance_id
+        self.request_data = request_data
+        self.job_id = job_id
+        self.scale_type = ''
+        self.scale_vnf_data = ''
+        self.scale_ns_data = ''
+
+    def run(self):
+        try:
+            self.do_biz()
+        except NSLCMException as e:
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, 'ns scale fail')
+        finally:
+            self.update_ns_status(NS_INST_STATUS.ACTIVE)
+
+    def do_biz(self):
+        self.update_job(1, desc='ns scale start')
+        self.update_ns_status(NS_INST_STATUS.SCALING)
+        self.get_and_check_params()
+        self.do_vnfs_scale()
+        self.update_job(100, desc='ns scale success')
+
+    def get_and_check_params(self):
+        self.scale_type = ignore_case_get(self.request_data, 'scaleType')
+        if not self.scale_type or self.scale_type != SCALE_TYPE[0]:
+            logger.error('scaleType parameter does not exist or value is incorrect. It must be SCALE_NS.')
+            raise NSLCMException('scaleType parameter does not exist or value incorrect. It must be SCALE_NS.')
+
+        # Get data if SCALE_NS
+        self.scale_ns_data = ignore_case_get(self.request_data, 'scaleNsData')
+        self.scale_vnf_data = get_scale_vnf_data(self.scale_ns_data,self.ns_instance_id)
+        logger.debug('scale_vnf_data = %s' % self.scale_vnf_data)
+        # Get data if SCALE_VNF
+        #self.scale_vnf_data = ignore_case_get(self.request_data, 'scaleVnfData')
+        if not self.scale_vnf_data:
+            logger.error('scaleVnfData parameter does not exist or value incorrect')
+            raise NSLCMException('scaleVnfData parameter does not exist or value incorrect')
+
+    def do_vnfs_scale(self):
+        for i in range(len(self.scale_vnf_data)):
+            vnf_scale_params = self.prepare_vnf_scale_params(self.scale_vnf_data[i])
+            count = len(self.scale_vnf_data)
+            progress_range = [11 + 80 / count * i, 10 + 80 / count * (i + 1)]
+            status = self.do_vnf_scale(vnf_scale_params, progress_range)
+            if status is JOB_MODEL_STATUS.FINISHED:
+                logger.info('nf[%s] scale handle end' % vnf_scale_params.get('vnfInstanceId'))
+                self.update_job(progress_range[1],
+                                desc='nf[%s] scale handle end' % vnf_scale_params.get('vnfInstanceId'))
+            else:
+                logger.error('nf scale failed')
+                raise NSLCMException('nf scale failed')
+
+    def prepare_vnf_scale_params(self, vnf_data):
+        vnf_instance_id = ignore_case_get(vnf_data, 'vnfInstanceId')
+        scale_by_step_data = ignore_case_get(vnf_data, 'scaleByStepData')
+        result = {
+            "vnfInstanceId": vnf_instance_id,
+            "scaleByStepData": scale_by_step_data,
+            "nsInstanceId": self.ns_instance_id
+        }
+        return result
+
+    def do_vnf_scale(self, vnf_scale_params, progress_range):
+        nf_inst_id = vnf_scale_params.get('vnfInstanceId')
+        nf_service = NFManualScaleService(nf_inst_id, vnf_scale_params)
+        nf_service.start()
+        self.update_job(progress_range[0], desc='nf[%s] scale handle start' % nf_inst_id)
+        status = self.wait_job_finish(nf_service.job_id)
+        return status
+
+    @staticmethod
+    def wait_job_finish(sub_job_id, timeout=3600):
+        query_interval = 2
+        start_time = end_time = datetime.datetime.now()
+        while (end_time - start_time).seconds < timeout:
+            job_result = JobModel.objects.get(jobid=sub_job_id)
+            time.sleep(query_interval)
+            end_time = datetime.datetime.now()
+            if job_result.progress == 100:
+                return JOB_MODEL_STATUS.FINISHED
+            elif job_result.progress > 100:
+                return JOB_MODEL_STATUS.ERROR
+            else:
+                continue
+        return JOB_MODEL_STATUS.TIMEOUT
+
+    def update_job(self, progress, desc=''):
+        JobUtil.add_job_status(self.job_id, progress, desc)
+
+    def update_ns_status(self, status):
+        NSInstModel.objects.filter(id=self.ns_instance_id).update(status=status)
diff --git a/lcm/ns/ns_terminate.py b/lcm/ns/ns_terminate.py
new file mode 100644 (file)
index 0000000..9580657
--- /dev/null
@@ -0,0 +1,279 @@
+# Copyright 2016 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 math
+import traceback
+import logging
+import json
+import threading
+import time
+from lcm.ns.vnfs.wait_job import wait_job_finish
+from lcm.pub.database.models import NSInstModel, VLInstModel, FPInstModel, NfInstModel
+from lcm.pub.database.models import DefPkgMappingModel, InputParamMappingModel, ServiceBaseInfoModel
+from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi.nslcm import call_from_ns_cancel_resource
+from lcm.pub.utils.values import ignore_case_get
+
+JOB_ERROR = 255
+# [delete vnf try times]
+
+logger = logging.getLogger(__name__)
+
+
+class TerminateNsService(threading.Thread):
+    def __init__(self, ns_inst_id, terminate_type, terminate_timeout, job_id):
+        threading.Thread.__init__(self)
+        self.ns_inst_id = ns_inst_id
+        self.terminate_type = terminate_type
+        self.terminate_timeout = terminate_timeout
+        self.job_id = job_id
+        self.vnfm_inst_id = ''
+
+    def run(self):
+        try:
+            self.do_biz()
+        except NSLCMException as e:
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            JobUtil.add_job_status(self.job_id, JOB_ERROR,  "ns terminate fail.", '')
+
+    def do_biz(self):
+        if not self.check_data():
+            JobUtil.add_job_status(self.job_id, 100, "Need not terminate.", '')
+            return
+
+        self.cancel_sfc_list()
+        self.cancel_vnf_list()
+        time.sleep(4)
+        self.cancel_vl_list()
+
+        self.finaldata()
+
+    def check_data(self):
+        JobUtil.add_job_status(self.job_id, 0, "TERMINATING...", '')
+        ns_inst = NSInstModel.objects.filter(id=self.ns_inst_id)
+        if not ns_inst.exists():
+            logger.warn('ns instance [%s] does not exist.' % self.ns_inst_id)
+            return False
+        JobUtil.add_job_status(self.job_id, 10, "Ns cancel: check ns_inst_id success", '')
+        return True
+
+    # delete VLINST
+    def cancel_vl_list(self):
+        array_vlinst = VLInstModel.objects.filter(ownertype='2', ownerid=self.ns_inst_id)
+        if not array_vlinst:
+            logger.error("[cancel_vl_list] no vlinst attatch to ns_inst_id:%s" % self.ns_inst_id)
+            return
+        step_progress = 20 / len(array_vlinst)
+        cur_progress = 70
+        for vlinst in array_vlinst:
+            tmp_msg = vlinst.vlinstanceid
+            try:
+                ret = self.delete_vl(tmp_msg)
+                if ret[0] == 0:
+                    cur_progress += step_progress
+                    result = json.JSONDecoder().decode(ret[1]).get("result", "")
+                    if str(result) == '0':
+                        JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] success." % tmp_msg, '')
+                    else:
+                        JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] failed." % tmp_msg, '')
+                        return 'false'
+                else:
+                    NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
+                    return 'false'
+            except Exception as e:
+                logger.error("[cancel_vl_list] error[%s]!" % e.message)
+                logger.error(traceback.format_exc())
+                JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] Failed." % tmp_msg, '')
+                return 'false'
+        return 'true'
+
+    # delete SFC
+    def cancel_sfc_list(self):
+        array_sfcinst = FPInstModel.objects.filter(nsinstid=self.ns_inst_id)
+        if not array_sfcinst:
+            logger.error("[cancel_sfc_list] no sfcinst attatch to ns_inst_id:%s" % self.ns_inst_id)
+            return
+        step_progress = 20 / len(array_sfcinst)
+        cur_progress = 30
+        for sfcinst in array_sfcinst:
+            tmp_msg = sfcinst.sfcid
+            try:
+                ret = self.delete_sfc(tmp_msg)
+                if ret[0] == 0:
+                    cur_progress += step_progress
+                    result = json.JSONDecoder().decode(ret[1]).get("result", "")
+                    if str(result) == '0':
+                        JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] success." % tmp_msg, '')
+                    else:
+                        JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] failed." % tmp_msg, '')
+                        return 'false'
+                else:
+                    NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
+                    return 'false'
+            except Exception as e:
+                logger.error("[cancel_sfc_list] error[%s]!" % e.message)
+                logger.error(traceback.format_exc())
+                JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] Failed." % tmp_msg, '')
+                return 'false'
+        return 'true'
+
+    # delete Vnf
+    def cancel_vnf_list(self):
+        array_vnfinst = NfInstModel.objects.filter(ns_inst_id=self.ns_inst_id)
+        if not array_vnfinst:
+            logger.error("[cancel_vnf_list] no vnfinst attatch to ns_inst_id:%s" % self.ns_inst_id)
+            return
+        step_progress = 20 / len(array_vnfinst)
+        cur_progress = 50
+        for vnfinst in array_vnfinst:
+            tmp_msg = vnfinst.nfinstid
+            try:
+                self.delete_vnf(tmp_msg)
+                cur_progress += step_progress
+                JobUtil.add_job_status(self.job_id, cur_progress, "Delete vnfinst:[%s] success." % tmp_msg, '')
+            except Exception as e:
+                logger.error("[cancel_vnf_list] error[%s]!" % e.message)
+                logger.error(traceback.format_exc())
+                JobUtil.add_job_status(self.job_id, cur_progress, "Delete vnfinst:[%s] Failed." % tmp_msg, '')
+                return 'false'
+        return 'true'
+
+    def delete_vnf(self, nf_instid):
+        ret = call_from_ns_cancel_resource('vnf', nf_instid)
+        self.delete_resource(ret)
+
+    def delete_sfc(self, sfc_instid):
+        ret = call_from_ns_cancel_resource('sfc', sfc_instid)
+        return ret
+
+    def delete_vl(self, vl_instid):
+        ret = call_from_ns_cancel_resource('vl', vl_instid)
+        return ret
+
+    def delete_resource(self, result):
+        logger.debug("terminate_type=%s, result=%s", self.terminate_type, result)
+        if result[0] == 0:
+            job_info = json.JSONDecoder().decode(result[1])
+            vnfm_job_id = ignore_case_get(job_info, "jobid")
+            self.add_progress(5, "SEND_TERMINATE_REQ_SUCCESS")
+            if self.terminate_type == 'forceful':
+                ret = wait_job_finish(self.vnfm_inst_id, self.job_id, vnfm_job_id,
+                                      progress_range=[10, 50],
+                                      timeout=self.terminate_timeout,
+                                      job_callback=TerminateNsService.wait_job_mode_callback, mode='1')
+                if ret != JOB_MODEL_STATUS.FINISHED:
+                    logger.error('[NS terminate] VNFM terminate ns failed')
+                    NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
+                    raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
+        else:
+            logger.error('[NS terminate] VNFM terminate ns failed')
+            NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
+            raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
+
+    def exception(self):
+        NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
+        raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
+
+    def finaldata(self):
+        NSInstModel.objects.filter(id=self.ns_inst_id).update(status='null')
+        JobUtil.add_job_status(self.job_id, 100, "ns terminate ends.", '')
+
+    # @staticmethod
+    # def call_vnfm_to_cancel_resource(res_type, instid):
+    #     ret = call_from_ns_cancel_resource(res_type, instid)
+    #     return ret
+
+    def add_progress(self, progress, status_decs, error_code=""):
+        JobUtil.add_job_status(self.job_id, progress, status_decs, error_code)
+
+    @staticmethod
+    def wait_job_mode_callback(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
+        for job in jobs:
+            progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
+            if 255 == progress and '1' == kwargs['mode']:
+                break
+            JobUtil.add_job_status(vnfo_job_id, progress, job.get('statusdescription', ''), job.get('errorcode', ''))
+
+        latest_progress = TerminateNsService.calc_progress_over_100(job_status['progress'], progress_range)
+        if 255 == latest_progress and '1' == kwargs['mode']:
+            JobUtil.add_job_status(vnfo_job_id, progress_range[1], job_status.get('statusdescription', ''),
+                                   job_status.get('errorcode', ''))
+        else:
+            JobUtil.add_job_status(vnfo_job_id, latest_progress, job_status.get('statusdescription', ''),
+                                   job_status.get('errorcode', ''))
+        if job_status['status'] in ('error', 'finished'):
+            return True, job_status['status']
+        return False, 'processing'
+
+    @staticmethod
+    def wait_job_finish_common_call_back(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
+        error_254 = False
+        for job in jobs:
+            progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
+            if 254 == progress:
+                logger.debug("=========254==============")
+                progress = 255
+                error_254 = True
+            JobUtil.add_job_status(vnfo_job_id, progress, job.get('statusdescription', ""), job.get('errorcode', ""))
+        latest_progress = TerminateNsService.calc_progress_over_100(job_status['progress'], progress_range)
+        if 254 == latest_progress:
+            logger.debug("=========254==============")
+            latest_progress = 255
+            error_254 = True
+        JobUtil.add_job_status(vnfo_job_id, latest_progress, job_status.get('statusdescription', ""),
+                               job_status.get('errorcode', ""))
+        # return error_254
+        if error_254:
+            logger.debug("return 254")
+            return True, 'error_254'
+        if job_status['status'] in ('error', 'finished'):
+            return True, job_status['status']
+        return False, 'processing'
+
+    @staticmethod
+    def calc_progress_over_100(vnfm_progress, target_range=None):
+        if target_range is None:
+            target_range = [0, 100]
+        progress = int(vnfm_progress)
+        if progress > 100:
+            return progress
+        floor_progress = int(math.floor(float(target_range[1] - target_range[0]) / 100 * progress))
+        target_range = floor_progress + target_range[0]
+        return target_range
+
+
+class DeleteNsService(object):
+    def __init__(self, ns_inst_id):
+        self.ns_inst_id = ns_inst_id
+
+    def do_biz(self):
+        try:
+            self.delete_ns()
+        except:
+            logger.error(traceback.format_exc())
+
+    def delete_ns(self):
+        logger.debug("delele NSInstModel(%s)", self.ns_inst_id)
+        NSInstModel.objects.filter(id=self.ns_inst_id).delete()
+
+        logger.debug("delele InputParamMappingModel(%s)", self.ns_inst_id)
+        InputParamMappingModel.objects.filter(service_id=self.ns_inst_id).delete()
+
+        logger.debug("delele DefPkgMappingModel(%s)", self.ns_inst_id)
+        DefPkgMappingModel.objects.filter(service_id=self.ns_inst_id).delete()
+
+        logger.debug("delele ServiceBaseInfoModel(%s)", self.ns_inst_id)
+        ServiceBaseInfoModel.objects.filter(service_id=self.ns_inst_id).delete()
diff --git a/lcm/ns/sfcs/__init__.py b/lcm/ns/sfcs/__init__.py
new file mode 100644 (file)
index 0000000..b847fa8
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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.
\ No newline at end of file
diff --git a/lcm/ns/sfcs/create_flowcla.py b/lcm/ns/sfcs/create_flowcla.py
new file mode 100644 (file)
index 0000000..346a8bc
--- /dev/null
@@ -0,0 +1,92 @@
+# Copyright 2016 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.ns.sfcs.utils import get_fp_model_by_fp_inst_id
+from lcm.pub.database.models import FPInstModel
+from lcm.pub.msapi import extsys
+from lcm.pub.msapi import sdncdriver
+
+logger = logging.getLogger(__name__)
+
+
+class CreateFlowClassifier(object):
+    def __init__(self, data):
+        self.ns_model_data = data["ns_model_data"]
+        self.fp_inst_id = data["fpinstid"]
+        self.flow_classifiers_model = get_fp_model_by_fp_inst_id(data["ns_model_data"], self.fp_inst_id)["properties"][
+            "policy"]
+        self.sdnControllerId = ""
+        self.url = ""
+        self.dscp = ""
+        self.ip_proto = ""
+        self.source_port_range = ""
+        self.dest_port_range = ""
+        self.source_ip_range = ""
+        self.dest_ip_range = ""
+        self.flow_classfier_id = ""
+
+    def do_biz(self):
+        logger.info("CreateFlowClassifier start:")
+        self.init_data(self.flow_classifiers_model)
+        self.create_flow_classfier()
+        self.update_fp_inst()
+        logger.info("CreateFlowClassifier end:")
+
+    def init_data(self, flow_classifiers_model):
+        fp_database_info = FPInstModel.objects.filter(fpinstid=self.fp_inst_id).get()
+        self.sdnControllerId = fp_database_info.sdncontrollerid
+        self.url = extsys.get_sdn_controller_by_id(self.sdnControllerId)["url"]
+        self.dscp = flow_classifiers_model["criteria"]["dscp"]
+        self.ip_proto = flow_classifiers_model["criteria"]["ip_protocol"]
+        self.source_port_range = flow_classifiers_model["criteria"]["source_port_range"]
+        self.dest_port_range = flow_classifiers_model["criteria"]["dest_port_range"]
+        self.dest_ip_range = flow_classifiers_model["criteria"]["dest_ip_range"]
+        self.source_ip_range = flow_classifiers_model["criteria"]["source_ip_range"]
+
+    def update_fp_inst(self):
+        fp_inst_info = FPInstModel.objects.filter(fpinstid=self.fp_inst_id).get()
+        fp_inst_info.flowclassifiers = self.flow_classfier_id
+        FPInstModel.objects.filter(fpinstid=self.fp_inst_id).update(flowclassifiers=fp_inst_info.flowclassifiers)
+
+    def create_flow_classfier(self):
+        data = {
+            "sdnControllerId": self.sdnControllerId,
+            "url": self.url,
+            "name": "",
+            "description": "",
+            "dscp": self.dscp,
+            "ip_proto": self.ip_proto,
+            "source_port_range": self.source_port_range,
+            "dest_port_range": self.dest_port_range,
+            "source_ip_range": self.concat_str(self.source_ip_range),
+            "dest_ip_range": self.concat_str(self.dest_ip_range)
+        }
+        # req_param = json.JSONEncoder().encoding(data)
+        # url = "/openoapi/sdncdriver/v1.0/createflowclassfier"
+        # ret = req_by_msb(url,"POST", data)
+        # if ret[0] > 0:
+        #     logger.error('Send Flow Classifier request to Driver failed.')
+        #     utils.sfc_inst_failed_handle(self.fp_inst_id, "Send Flow Classifier request to Driver failed.")
+        #     raise NSLCMException('Send Flow Classifier request to Driver failed.')
+        # resp_body = json.loads(ret[1])
+        self.flow_classfier_id = sdncdriver.create_flow_classfier(data)
+
+    def concat_str(self, str_list):
+        final_str = ""
+        for str in str_list:
+            final_str += str + ","
+        return final_str[:-1]
diff --git a/lcm/ns/sfcs/create_port_chain.py b/lcm/ns/sfcs/create_port_chain.py
new file mode 100644 (file)
index 0000000..a3e98e0
--- /dev/null
@@ -0,0 +1,95 @@
+# Copyright 2016 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.database.models import FPInstModel
+from lcm.pub.msapi import extsys
+from lcm.pub.msapi import sdncdriver
+
+logger = logging.getLogger(__name__)
+
+
+class CreatePortChain(object):
+    def __init__(self, data):
+        self.fp_inst_id = data["fpinstid"]
+        self.ns_model_info = data["ns_model_data"]
+        self.sdnControllerId = ""
+        self.symmetric = ""
+        self.port_pair_groups_ids = []
+        self.flow_classifier_ids = []
+
+    def do_biz(self):
+        logger.info("CreatePortChain start:")
+        self.init_data()
+        self.create_sfc()
+        logger.info("CreatePortChain end:")
+
+    def init_data(self):
+        fp_inst_info = FPInstModel.objects.filter(fpinstid=self.fp_inst_id).get()
+        self.sdnControllerId = fp_inst_info.sdncontrollerid
+        self.symmetric = "true" if fp_inst_info.symmetric == 1 else "false"
+        flow_classfier_str = fp_inst_info.flowclassifiers
+        self.flow_classifier_ids = [flow_classfier_str]
+        portpairgroup_ids = []
+        for portpairgroup in json.loads(fp_inst_info.portpairgroups):
+            portpairgroup_ids.append(portpairgroup["groupid"])
+        self.port_pair_groups_ids = portpairgroup_ids
+
+    def create_sfc(self):
+        data = {
+            "sdnControllerId": self.sdnControllerId,
+            "url": extsys.get_sdn_controller_by_id(self.sdnControllerId)["url"],
+            "flowClassifiers": self.flow_classifier_ids,
+            "portPairGroups": self.port_pair_groups_ids,
+            "symmetric": self.symmetric
+        }
+
+        # url = "/openoapi/sdncdriver/v1.0/createchain"
+        # req_param = json.JSONEncoder.encoding(data)
+        # ret = req_by_msb(url, "POST", req_param)
+        # ret = req_by_msb("OPENAPI_CREATE_SERVICE_PORT_CHAIN",data)
+        # if ret[0] > 0:
+        #     logger.error('Send SFC Create request to Driver failed.')
+        #     sfc_inst_failed_handle( "Send SFC Create request to Driver failed.")
+        #     raise NSLCMException('Send SFC Create request to Driver failed.')
+        # resp_body = json.loads(ret[1])
+        # sfc_id = resp_body["id"]
+        sfc_id = sdncdriver.create_port_chain(data)
+        FPInstModel.objects.filter(fpinstid=self.fp_inst_id).update(sfcid=sfc_id)
+
+        # def get_url_by_sdncontrollerid(self):
+        #     try:
+        #         logger.warn("query sdncontroller by id begins:")
+        #
+        #         url = "/openoapi/extsys/v1/sdncontrollers/%s" % (self.sdnControllerId)
+        #         ret = req_by_msb(url, "GET")
+        #         if ret[0] > 0:
+        #             logger.error('query sdncontroller failed.')
+        #             raise VnfoException('query sdncontroller failed.')
+        #         resp_body = json.JSONDecoder().decode(ret[1])
+        #         logger.warn("query sdncontroller by id ends:")
+        #     except:
+        #         if ret[0] > 0:
+        #             logger.error('Send Flow Classifier request to Driver failed.')
+        #             self.sfc_inst_failed_handle(self.fp_inst_id, "Send Flow Classifier request to Driver failed.")
+        #             raise VnfoException('Send Flow Classifier request to Driver failed.')
+        #
+        #     return resp_body('url')
+
+        # def sfc_inst_failed_handle(fp_inst_id, error_msg):
+        #     logger.error('create sfc  failed, detail message: %s' % error_msg)
+        #     FPInstModel.objects.filter(fpid=fp_inst_id).update(status="disabled").get()
diff --git a/lcm/ns/sfcs/create_portpairgp.py b/lcm/ns/sfcs/create_portpairgp.py
new file mode 100644 (file)
index 0000000..701adab
--- /dev/null
@@ -0,0 +1,277 @@
+# Copyright 2016 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.ns.sfcs.utils import get_fp_model_by_fp_inst_id
+from lcm.pub.database.models import FPInstModel, NfInstModel, CPInstModel, PortInstModel, VNFCInstModel
+from lcm.pub.msapi import extsys
+from lcm.pub.msapi import sdncdriver
+
+logger = logging.getLogger(__name__)
+
+
+class CreatePortPairGroup(object):
+    def __init__(self, data):
+        self.fp_inst_id = data["fpinstid"]
+        self.ns_model_data = data["ns_model_data"]
+        self.ns_inst_id = data["nsinstid"]
+        self.fp_model = get_fp_model_by_fp_inst_id(self.ns_model_data,
+                                                   self.fp_inst_id)
+        self.port_pair_groups = []
+        self.port_pair_group_db_infos = []
+        self.sdncontrollerid = ""
+
+    def do_biz(self):
+        logger.info("CreatePortPairGroup start")
+        self.init_port_pair_group(self.fp_model)
+        self.create_port_pair_and_groups()
+        self.save_port_pair_group_info_2_db()
+        logger.info("CreatePortPairGroup end")
+
+    def create_port_pair_and_groups(self):
+        for port_pair_group_info in self.port_pair_groups:
+            port_pairs_info = port_pair_group_info.get("portpair")
+            port_pair_ids = []
+            for port_pair_info in port_pairs_info:
+                port_pair_ids.append(self.create_port_pair(port_pair_info))
+            self.create_port_pair_and_group(port_pair_ids)
+
+    def save_port_pair_group_info_2_db(self):
+        logger.info("portpairgroups in fpinstmodel:%s" % self.port_pair_group_db_infos)
+        FPInstModel.objects.filter(fpinstid=self.fp_inst_id).update(
+            portpairgroups=json.JSONEncoder().encode(self.port_pair_group_db_infos))
+
+    def create_port_pair_and_group(self, port_pair_ids):
+        # url = const.port_pair_group_url
+        port_pair_group = {
+            "sdnControllerId": self.sdncontrollerid,
+            "url": extsys.get_sdn_controller_by_id(self.sdncontrollerid)["url"],
+            "portPairs": port_pair_ids
+        }
+        port_pair_group_id = sdncdriver.create_port_pair_group(port_pair_group)
+        port_pair_group_info = {
+            "groupid": port_pair_group_id,
+            "portpair": port_pair_ids}
+
+        self.port_pair_group_db_infos.append(port_pair_group_info)
+
+    def create_port_pair(self, port_pair_info):
+        # url = const.port_pair_url
+        port_pair_info.update({
+            "sdnControllerId": self.sdncontrollerid,
+            "url": extsys.get_sdn_controller_by_id(self.sdncontrollerid)["url"]})
+        return sdncdriver.create_port_pair(port_pair_info)
+
+    def init_port_pair_group(self, fp_model):
+        forwarder_list = fp_model["forwarder_list"]
+        self.sdncontrollerid = FPInstModel.objects.filter(fpinstid=self.fp_inst_id).get().sdncontrollerid
+        index = 0
+        while index < len(forwarder_list):
+            if (forwarder_list[index]["type"] == "cp"):
+                index += self.generate_port_pair_group_cp(index, forwarder_list)
+            else:
+                index += self.generate_port_pair_group_vnf(index, forwarder_list)
+            index += 1
+
+        logger.info("port pair group: %s" % self.port_pair_groups)
+
+    def generate_port_pair_group_cp(self, index, forwarder_list):
+        cur_forwarder = forwarder_list[index]["node_name"]
+        cur_cp_model_info = self.get_cp_model_info_by_cpid(cur_forwarder)
+        if (index < len(forwarder_list) - 1 and forwarder_list[index + 1]["type"] == "cp"):
+            next_forward = forwarder_list[index + 1]["node_name"]
+            next_cp_model_info = self.get_cp_model_info_by_cpid(next_forward)
+            if (cur_cp_model_info["pnf_id"] == next_cp_model_info["pnf_id"]):  # same port pair group
+                self.generate_port_pair_group_type_cp(cur_cp_model_info, next_cp_model_info)
+                return 1
+        self.generate_port_pair_group_type_cp(cur_cp_model_info, cur_cp_model_info)
+        return 0
+
+    def generate_port_pair_group_vnf(self, index, forwarder_list):
+        incre = 0
+        cur_vnf_id = forwarder_list[index]["node_name"]
+        cur_forwarder = forwarder_list[index]["capability"]
+        self.vnf_model_in_ns_info = self.get_vnf_model_info_by_vnf_id(cur_vnf_id)
+        vnf_inst_database_info = NfInstModel.objects.filter(vnf_id=self.vnf_model_in_ns_info["vnf_id"],
+                                                            ns_inst_id=self.ns_inst_id).get()
+        self.vnf_inst_database_info = vnf_inst_database_info
+        logger.info("VNFD MODEL : %s" %vnf_inst_database_info.vnfd_model)
+        vnfd_model_info = json.loads(vnf_inst_database_info.vnfd_model)
+        # vnfd_model_info = json.dumps(vnf_inst_database_info.vnfd_model)
+        # vnfd_model_info = json.dumps(self.vnf_inst_database_info.vnfd_model)
+        self.vnfd_model_info = vnfd_model_info
+        logger.info("forward list: %s" % forwarder_list)
+        logger.info("current fowarder : %s" % cur_forwarder)
+        cpd_id = self.get_cpdid_info_forwarder(vnfd_model_info, cur_forwarder)
+        self.cp_model_in_vnf = self.get_cp_from_vnfd_model(cpd_id)
+        vnfc_inst_infos = VNFCInstModel.objects.filter(nfinstid=vnf_inst_database_info.nfinstid)
+        if not vnfc_inst_infos:
+            logger.error("VNFCInstModel is None")
+            return 0
+        logger.info("vnfc instance id: %s" % vnfc_inst_infos.get().vnfcinstanceid)
+        logger.info("cpd id: %s" % cpd_id)
+        cp_inst_infos = []
+        for vnfc_inst_info in vnfc_inst_infos:
+            cp_db_info = CPInstModel.objects.filter(cpdid=cpd_id,
+                                                    # ownertype=OWNER_TYPE.VNF,
+                                                    ownertype=3,
+                                                    ownerid=vnfc_inst_info.vnfcinstanceid).get()
+            if cp_db_info:
+                cp_inst_infos.append(cp_db_info)
+        if not cp_inst_infos:
+            logger.error("CPInstModel is None")
+            return 0
+        logger.info("cp info : %s" % cp_inst_infos)
+        port_pairs = []
+        if (index < len(forwarder_list) - 1 and forwarder_list[index + 1]["type"] == "vnf"):
+            next_vnf_id = forwarder_list[index + 1]["node_name"]
+            if (cur_vnf_id != next_vnf_id):
+                for cp_inst_info in cp_inst_infos:
+                    port_pairs.append(self.generate_port_pair_group(cp_inst_info, cp_inst_info))
+            else:
+                next_forwarder = forwarder_list[index]["capability"]
+                next_forwarder_cpd_id = self.get_cpdid_info_forwarder(vnfd_model_info, next_forwarder)
+
+                vnfc_inst_infos = VNFCInstModel.objects.filter(nfinstid=vnf_inst_database_info.nfinstid)
+
+                if not vnfc_inst_infos:
+                    logger.error("VNFCInstModel is None")
+                    return 0
+                next_cp_inst_infos = []
+                for vnfc_inst_info in vnfc_inst_infos:
+                    next_cp_db_info = CPInstModel.objects.filter(cpdid=next_forwarder_cpd_id,
+                                                                 # ownertype=OWNER_TYPE.VNF,
+                                                                 ownertype=3,
+                                                                 ownerid=vnfc_inst_info.vnfcinstanceid).get()
+                    if next_cp_db_info:
+                        next_cp_inst_infos.append(next_cp_db_info)
+
+                port_pairs.append(self.generate_port_pair_group(cp_inst_infos[0], next_cp_inst_infos[0]))
+                incre = 1
+
+        else:
+            for cp_inst_info in cp_inst_infos:
+                port_pairs.append(self.generate_port_pair_group(cp_inst_info, cp_inst_info))
+        self.port_pair_groups.append(
+            {
+                "portpair": port_pairs
+            }
+        )
+        return incre
+
+    def generate_port_pair_group_type_cp(self, ingress_cp_model_info, egress_cp_model_info):
+        sf_type = ""
+        request_reclassification = False
+        nsh_aware = True
+        sf_param = {}
+        if ingress_cp_model_info["pnf_id"] == "":
+            pass
+        else:
+            pnf_model_info = self.get_pnf_model_info_by_cpid(ingress_cp_model_info["pnf_id"])
+            sf_type = "pnf_" + pnf_model_info["properties"]["pnf_type"]
+            nsh_aware = pnf_model_info["properties"]["nsh_aware"]
+            request_reclassification = pnf_model_info["properties"]["request_reclassification"]
+            sf_param = pnf_model_info["properties"]
+        sf_param["mng-address"] = pnf_model_info["properties"]["management_address"]
+        port_pair_info = {
+            "sfType": sf_type,
+            "nshAware": nsh_aware,
+            "requestReclassification": request_reclassification,
+            "ingress": {
+                "encapsulation": ingress_cp_model_info["properties"]["sfc_encapsulation"],
+                "ip": ingress_cp_model_info["properties"]["ip_address"],
+                "mac": ingress_cp_model_info["properties"]["mac_address"],
+                "portName": ingress_cp_model_info["properties"].get("interface_name")
+            },
+            "egress": {
+                "encapsulation": egress_cp_model_info["properties"]["sfc_encapsulation"],
+                "ip": egress_cp_model_info["properties"]["ip_address"],
+                "mac": egress_cp_model_info["properties"]["mac_address"],
+                "portName": egress_cp_model_info["properties"].get("interface_name")
+            },
+            "sfParam": sf_param
+        }
+        self.port_pair_groups.append(
+            {
+                "portpair": [port_pair_info]
+            }
+        )
+
+    def generate_port_pair_group(self, ingress_cp_inst_info, egress_cp_inst_info):
+        if (ingress_cp_inst_info.relatedport != ""):
+            ingress_port = ingress_cp_inst_info.relatedport
+        else:
+            ingress_port = CPInstModel.objects.filter(cpinstanceid=ingress_cp_inst_info.relatedcp,
+                                                      ownertype="vnf",
+                                                      ownerid=self.vnf_inst_database_info.nfinstid).get().relatedport
+        if (egress_cp_inst_info.relatedport != ""):
+            egress_port = egress_cp_inst_info.relatedport
+        else:
+            egress_port = CPInstModel.objects.filter(cpinstanceid=egress_cp_inst_info.relatedcp,
+                                                     ownertype="vnf",
+                                                     ownerid=self.vnf_inst_database_info.nfinstid).get().relatedport
+        ingress_port_inst_info = PortInstModel.objects.filter(portid=ingress_port).get()
+        egress_port_inst_info = PortInstModel.objects.filter(portid=egress_port).get()
+
+        port_pair_info = {
+            "sfType": "vnf_" + self.vnf_model_in_ns_info["properties"]["vnf_type"],
+            "nshAware": self.vnf_model_in_ns_info["properties"]["nsh_aware"],
+            "requestReclassification": self.vnf_model_in_ns_info["properties"]["request_reclassification"],
+            "ingress": {
+                "encapsulation": ingress_port_inst_info.sfcencapsulation,
+                "ip": ingress_port_inst_info.ipaddress,
+                "mac": ingress_port_inst_info.macaddress
+            },
+            "egress": {
+                "encapsulation": egress_port_inst_info.sfcencapsulation,
+                "ip": egress_port_inst_info.ipaddress,
+                "mac": egress_port_inst_info.macaddress
+            },
+            "sfParam": self.vnf_model_in_ns_info["properties"]
+        }
+        return port_pair_info
+
+    def get_cp_from_vnfd_model(self, cpdid):
+        for cp_model in self.vnfd_model_info["cps"]:
+            if cp_model["cp_id"] == cpdid:
+                return cp_model
+
+    def get_pnf_model_info_by_cpid(self, pnfid):
+        for pnf_model_info in self.ns_model_data["pnfs"]:
+            if (pnf_model_info["pnf_id"] == pnfid):
+                return pnf_model_info
+
+    def get_cp_model_info_by_cpid(self, cpid):
+        for cp_model_info in self.ns_model_data["cps"]:
+            if (cp_model_info["cp_id"] == cpid):
+                return cp_model_info
+
+    def get_vnf_model_info_by_vnf_id(self, vnfid):
+        for vnf_model_info in self.ns_model_data["vnfs"]:
+            if (vnf_model_info["vnf_id"] == vnfid):
+                return vnf_model_info
+
+    def get_cpdid_info_forwarder(self, vnf_model, forwarder):
+        logger.info("vnf_exposed %s" % type(vnf_model))
+        # logger.info("vnf_exposed %s" % json.loads(vnf_model))
+        # vnf_model = json.loads(vnf_model)
+        logger.info("vnf_exposed %s" % type(vnf_model["vnf_exposed"]))
+        logger.info("vnf_exposed %s" % vnf_model["vnf_exposed"])
+        logger.info("foward_cps %s" % vnf_model["vnf_exposed"]["forward_cps"])
+        for forwarder_info in vnf_model["vnf_exposed"]["forward_cps"]:
+            if (forwarder_info["key_name"] == forwarder):
+                return forwarder_info["cp_id"]
diff --git a/lcm/ns/sfcs/create_sfc_worker.py b/lcm/ns/sfcs/create_sfc_worker.py
new file mode 100644 (file)
index 0000000..380fd59
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright 2016 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 threading import Thread
+
+from lcm.ns.sfcs.create_flowcla import CreateFlowClassifier
+from lcm.ns.sfcs.create_port_chain import CreatePortChain
+from lcm.ns.sfcs.create_portpairgp import CreatePortPairGroup
+from lcm.ns.sfcs.sfc_instance import SfcInstance
+from lcm.ns.sfcs.utils import update_fp_status
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.jobutil import JobUtil
+
+logger = logging.getLogger(__name__)
+
+
+class CreateSfcWorker(Thread):
+    def __init__(self, data):
+        super(CreateSfcWorker, self).__init__()
+        self.ns_inst_id = data["nsinstid"]
+        self.ns_model_data = data["ns_model_data"]
+        self.fp_id = data["fpindex"]
+        self.sdnControllerId = data["sdncontrollerid"]
+        self.fp_inst_id = data["fpinstid"]
+        self.data = data
+        self.job_id = ""
+
+    def init_data(self):
+        self.job_id = JobUtil.create_job("SFC", "sfc_init", self.ns_inst_id + "_" + self.fp_id)
+        return self.job_id
+
+    def run(self):
+        try:
+            logger.info("Service Function Chain Worker  start : ")
+
+            CreateFlowClassifier(self.data).do_biz()
+            JobUtil.add_job_status(self.job_id, 50, "create flow classifer successfully!", "")
+            CreatePortPairGroup(self.data).do_biz()
+            JobUtil.add_job_status(self.job_id, 75, "create port pair group successfully!", "")
+            CreatePortChain(self.data).do_biz()
+            update_fp_status(self.fp_inst_id, "active")
+            JobUtil.add_job_status(self.job_id, 100, "create port chain successful!", "")
+            logger.info("Service Function Chain Worker end : ")
+        except NSLCMException as e:
+            self.handle_exception(e)
+        except Exception as e:
+            self.handle_exception(e)
+
+    def handle_exception(self, e):
+        detail = "sfc instantiation failed, detail message: %s" % e.message
+        JobUtil.add_job_status(self.job_id, 255, "create sfc failed!", "")
+        logger.error(traceback.format_exc())
+        logger.error(detail)
+        update_fp_status(self.fp_inst_id, "failed")
diff --git a/lcm/ns/sfcs/delete_sfcs.py b/lcm/ns/sfcs/delete_sfcs.py
new file mode 100644 (file)
index 0000000..23fed4c
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright 2016 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
+import traceback
+
+from lcm.pub.database.models import FPInstModel, VNFFGInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi import extsys, resmgr, sdncdriver
+
+logger = logging.getLogger(__name__)
+
+
+class DeleteSfcs(object):
+    def __init__(self, sfc_inst_id):
+        self.sfc_inst_id = sfc_inst_id
+        self.ns_inst_id = ""
+
+    def do(self):
+        try:
+            sfc_inst_info = FPInstModel.objects.filter(fpinstid=self.sfc_inst_id)
+            if not sfc_inst_info:
+                logger.warn("sfc inst id(%s) is not exist or has been already deleted" % self.sfc_inst_id)
+                return {"result": 0, "detail": "sfc is not exist or has been already deleted"}
+            self.ns_inst_id = sfc_inst_info[0].nsinstid
+            self.delete_sfc_from_driver(sfc_inst_info[0])
+            self.delete_sfc_from_resmgr()
+            self.delete_sfc_from_db(sfc_inst_info)
+            return {"result": 0, "detail": "delete sfc success"}
+        except NSLCMException as e:
+            return self.exception_handle(e)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            return self.exception_handle(e)
+
+    def exception_handle(self, e):
+        detail = 'sfc delete failed, detail message: %s' % e.message
+        logger.error(detail)
+        return {"result": 1, "detail": detail}
+
+    def delete_sfc_from_driver(self, sfc_inst_info):
+        sdn_controller_id = sfc_inst_info.sdncontrollerid
+        sdn_controller_url = extsys.get_sdn_controller_by_id(sdn_controller_id)["url"]
+        sfc_id = sfc_inst_info.sfcid
+        flow_classifiers = sfc_inst_info.flowclassifiers
+        port_pair_groups = sfc_inst_info.portpairgroups
+        if sfc_id:
+            req_param = {"sdnControllerId": sdn_controller_id, "url": sdn_controller_url, "id": sfc_id}
+            sdncdriver.delete_port_chain(req_param)
+        if flow_classifiers:
+            for flow_id in flow_classifiers.split(","):
+                req_param = {"sdnControllerId": sdn_controller_id, "url": sdn_controller_url, "id": flow_id}
+                sdncdriver.delete_flow_classifier(req_param)
+        if port_pair_groups:
+            for group in json.JSONDecoder().decode(port_pair_groups):
+                group_id = group["groupid"]
+                req_param = {"sdnControllerId": sdn_controller_id, "url": sdn_controller_url, "id": group_id}
+                sdncdriver.delete_port_pair_group(req_param)
+                port_pair = group["portpair"]
+                for port_pair_id in port_pair:
+                    req_param = {"sdnControllerId": sdn_controller_id, "url": sdn_controller_url, "id": port_pair_id}
+                    sdncdriver.delete_port_pair(req_param)
+
+    def delete_sfc_from_db(self, sfc_inst_info):
+        # do_biz_with_share_lock("delete-sfclist-in-vnffg-%s" % self.ns_inst_id, self.delete_sfc_inst_id_in_vnffg)
+        self.delete_sfc_inst_id_in_vnffg()
+        sfc_inst_info.delete()
+
+    def delete_sfc_from_resmgr(self):
+        resmgr.delete_sfc(self.sfc_inst_id)
+
+    def delete_sfc_inst_id_in_vnffg(self):
+        for vnffg_info in VNFFGInstModel.objects.filter(nsinstid=self.ns_inst_id):
+            new_sfc_id_list = ""
+            for old_sfc_id in vnffg_info.fplist.split(","):
+                if old_sfc_id != self.sfc_inst_id:
+                    new_sfc_id_list += old_sfc_id + ","
+            new_sfc_id_list = new_sfc_id_list[:-1]
+            VNFFGInstModel.objects.filter(vnffginstid=vnffg_info.vnffginstid).update(fplist=new_sfc_id_list)
diff --git a/lcm/ns/sfcs/detail_views.py b/lcm/ns/sfcs/detail_views.py
new file mode 100644 (file)
index 0000000..b5646f5
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright 2016 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 status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from lcm.ns.sfcs.delete_sfcs import DeleteSfcs
+from lcm.ns.sfcs.get_sfcs import GetSfcs
+
+
+class SfcDetailView(APIView):
+    def get(self, request, sfc_inst_id):
+        print "SfcCreateView--get::> %s" % sfc_inst_id
+        sfc_inst_info = GetSfcs(sfc_inst_id).do()
+        if not sfc_inst_info:
+            return Response(status=status.HTTP_404_NOT_FOUND)
+        return Response(status=status.HTTP_200_OK, data={'sfcInstId': sfc_inst_id,
+                                                         'sfcName': "xxx",
+                                                         'sfcStatus': sfc_inst_info[0].status})
+
+    def delete(self, request_paras, sfc_inst_id):
+        resp = DeleteSfcs(sfc_inst_id).do()
+        return Response(data=resp, status=status.HTTP_202_ACCEPTED)
+
+
+class SfcCreateView(APIView):
+    def post(self, request):
+        print "SfcCreateView--post::> %s" % request.stream.body
+        return Response(data={"jobId": "1234", "sfcInstId": "1"}, status=status.HTTP_201_CREATED)
diff --git a/lcm/ns/sfcs/get_sfcs.py b/lcm/ns/sfcs/get_sfcs.py
new file mode 100644 (file)
index 0000000..653f8f6
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2016 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 FPInstModel
+
+
+class GetSfcs(object):
+    def __init__(self, sfc_inst_id):
+        self.sfc_inst_id = sfc_inst_id
+
+    def do(self):
+        return FPInstModel.objects.filter(fpinstid=self.sfc_inst_id)
diff --git a/lcm/ns/sfcs/sfc_instance.py b/lcm/ns/sfcs/sfc_instance.py
new file mode 100644 (file)
index 0000000..cb68f8c
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright 2016 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 VNFFGInstModel, FPInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.share_lock import do_biz_with_share_lock
+
+logger = logging.getLogger(__name__)
+
+
+class SfcInstance(object):
+    def __init__(self, data):
+        self.ns_inst_id = data["nsinstid"]
+        self.ns_model_data = data["ns_model_data"]
+        self.fp_id = data["fpindex"]
+        self.fp_inst_id = data["fpinstid"]
+        self.sdnControllerId = data["sdncontrollerid"]
+
+    def do_biz(self):
+        self.init_data()
+        return self.save()
+
+    def init_data(self):
+        self.fp_model = self.get_fp_model_by_fp_id()
+        logger.info("fp_model.properties:%s, fp_id:%s" % (self.fp_model["properties"], self.fp_id))
+        if not self.fp_model:
+            return
+        logger.info("sfc_inst_symmetric %s" % self.fp_model["properties"].get("symmetric"))
+        self.symmetric = self.fp_model["properties"].get("symmetric")
+        logger.info("sfc_inst_symmetric %s" % self.symmetric)
+        self.policyinfo = self.fp_model["properties"].get("policy")
+        self.status = "processing"
+        vnffg_database_info = VNFFGInstModel.objects.filter(vnffgdid=self.get_vnffgdid_by_fp_id(),
+                                                            nsinstid=self.ns_inst_id).get()
+        self.vnffg_inst_id = vnffg_database_info.vnffginstid
+
+    def get_fp_model_by_fp_id(self):
+        fps_model = self.ns_model_data["fps"]
+        for fp_model in fps_model:
+            if fp_model["fp_id"] == self.fp_id:
+                return fp_model
+        return None
+
+    def get_vnffgdid_by_fp_id(self):
+        vnffgs_model = self.ns_model_data["vnffgs"]
+        for vnffg_model in vnffgs_model:
+            fp_ids = vnffg_model["members"]
+            for fp_id in fp_ids:
+                if fp_id == self.fp_id:
+                    return vnffg_model["vnffg_id"]
+
+    def save(self):
+        try:
+            logger.info("Sfc Instanciate save2db start : ")
+            FPInstModel(fpid=self.fp_id,
+                        fpinstid=self.fp_inst_id,
+                        nsinstid=self.ns_inst_id,
+                        vnffginstid=self.vnffg_inst_id,
+                        symmetric=1 if self.symmetric else 0,
+                        policyinfo=self.policyinfo,
+                        status=self.status,
+                        sdncontrollerid=self.sdnControllerId
+                        ).save()
+
+            do_biz_with_share_lock("update-sfclist-in-vnffg-%s" % self.ns_inst_id, self.update_vnfffg_info)
+            logger.info("Sfc Instanciate save2db end : ")
+
+        except:
+            logger.error('SFC instantiation failed')
+            raise NSLCMException('SFC instantiation failed.')
+        return {
+            "fpinstid": self.fp_inst_id
+        }
+
+
+    def update_vnfffg_info(self):
+        vnffg_database_info = VNFFGInstModel.objects.filter(vnffginstid=self.vnffg_inst_id).get()
+        fp_inst_list = vnffg_database_info.fplist
+        fp_inst_list = fp_inst_list + ',' + self.fp_inst_id if fp_inst_list else self.fp_inst_id
+        VNFFGInstModel.objects.filter(vnffginstid=self.vnffg_inst_id).update(fplist=fp_inst_list)
diff --git a/lcm/ns/sfcs/urls.py b/lcm/ns/sfcs/urls.py
new file mode 100644 (file)
index 0000000..a47f840
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright 2016 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 patterns, url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from lcm.ns.sfcs.detail_views import SfcDetailView
+from lcm.ns.sfcs.views import SfcView, SfcInstanceView, PortPairGpView, FlowClaView, PortChainView
+
+urlpatterns = patterns('',
+                       url(r'^openoapi/nslcm/v1/ns/sfcs$', SfcView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/sfcs/(?P<sfc_inst_id>[0-9a-zA-Z_-]+)$', SfcDetailView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/sfc_instance$', SfcInstanceView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/create_port_pair_group$', PortPairGpView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/create_flow_classifier$', FlowClaView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/create_port_chain$', PortChainView.as_view()),
+                       )
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns/sfcs/utils.py b/lcm/ns/sfcs/utils.py
new file mode 100644 (file)
index 0000000..b6d68cd
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright 2016 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 FPInstModel
+
+logger = logging.getLogger(__name__)
+
+
+def sfc_inst_failed_handle(fp_inst_id, error_msg):
+    logger.error('create sfc  failed, detail message: %s' % error_msg)
+    FPInstModel.objects.filter(fpid=fp_inst_id).update(status="disabled").get()
+
+
+def ignorcase_get(args, key):
+    if not key:
+        return ""
+    if key in args:
+        return args[key]
+    for oldkey in args:
+        if oldkey.upper() == key.upper():
+            return args[oldkey]
+    return ""
+
+def ignor_dot(str):
+    index = str.find('.')
+    if index == -1:
+        return str;
+    return str[0:index]
+
+def get_fp_id(fpindex,ns_model):
+    index = int(int(float(fpindex))-1)
+    return ns_model['fps'][index].get("fp_id")
+
+def update_fp_status(fp_inst_id,status_info):
+    FPInstModel.objects.filter(fpinstid=fp_inst_id).update(status=status_info)
+
+def get_fp_model_by_fp_inst_id(ns_model_data, fp_inst_id):
+    fp_databas_info = FPInstModel.objects.filter(fpinstid=fp_inst_id).get()
+    fps_model = ns_model_data["fps"]
+    for fp_model in fps_model:
+        if fp_model["fp_id"] == fp_databas_info.fpid:
+            return fp_model
diff --git a/lcm/ns/sfcs/views.py b/lcm/ns/sfcs/views.py
new file mode 100644 (file)
index 0000000..1e3f98f
--- /dev/null
@@ -0,0 +1,108 @@
+# Copyright 2016 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
+import traceback
+import uuid
+
+import time
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from lcm.ns.sfcs.create_flowcla import CreateFlowClassifier
+from lcm.ns.sfcs.create_port_chain import CreatePortChain
+from lcm.ns.sfcs.create_portpairgp import CreatePortPairGroup
+from lcm.ns.sfcs.create_sfc_worker import CreateSfcWorker
+from lcm.ns.sfcs.sfc_instance import SfcInstance
+from lcm.ns.sfcs.utils import get_fp_id, ignorcase_get
+
+logger = logging.getLogger(__name__)
+
+
+class SfcInstanceView(APIView):
+    def post(self, request):
+        data = {
+            'nsinstid': request.data['nsinstanceid'],
+            "ns_model_data": json.loads(request.data['context']),
+            'fpindex': request.data['fpindex'],
+            'fpinstid': str(uuid.uuid4()),
+            'sdncontrollerid': request.data["sdncontrollerid"]}
+        rsp = SfcInstance(data).do_biz()
+        return Response(data=rsp, status=status.HTTP_200_OK)
+
+
+class PortPairGpView(APIView):
+    def post(self, request):
+        data = {
+            'fpinstid': request.data["fpinstid"],
+            "ns_model_data": json.loads(request.data['context']),
+            'nsinstid': request.data["nsinstanceid"]}
+        CreatePortPairGroup(data).do_biz()
+        return Response(status=status.HTTP_200_OK)
+
+
+class FlowClaView(APIView):
+    def post(self, request):
+        data = {
+            'fpinstid': request.data["fpinstid"],
+            "ns_model_data": json.loads(request.data['context'])}
+        CreateFlowClassifier(data).do_biz()
+        return Response(status=status.HTTP_200_OK)
+
+
+class PortChainView(APIView):
+    def post(self, request):
+        data = {
+            'fpinstid': request.data["fpinstid"],
+            "ns_model_data": json.loads(request.data['context'])}
+        CreatePortChain(data).do_biz()
+        return Response(status=status.HTTP_200_OK)
+
+
+class SfcView(APIView):
+    def post(self, request):
+        try:
+            logger.info("Create Service Function Chain start")
+            logger.info("service_function_chain_request: %s" % json.dumps(request.data))
+            logger.info("service_function_chain_context  : %s" % json.dumps(request.data['context']))
+            logger.info("service_function_chain_context  : %s" % request.data['context'])
+            logger.info("service_function_chain_instanceid : %s" % ignorcase_get(request.data, 'nsinstanceid'))
+            logger.info("service_function_chain_sdncontrollerid : %s" % ignorcase_get(request.data, 'sdncontrollerid'))
+            logger.info("service_function_chain_fpindex : %s" % ignorcase_get(request.data, 'fpindex'))
+            ns_model_data = request.data['context']
+        except Exception as e:
+            logger.error(traceback.format_exc())
+        data = {
+            'nsinstid': ignorcase_get(request.data, 'nsinstanceid'),
+            "ns_model_data": ns_model_data,
+            'fpindex': get_fp_id(ignorcase_get(request.data, 'fpindex'), ns_model_data),
+            'fpinstid': str(uuid.uuid4()),
+            'sdncontrollerid': ignorcase_get(request.data, 'sdncontrollerid')
+        }
+        logger.info("Save FPInstModel start: ")
+        SfcInstance(data).do_biz()
+        logger.info("Save FPInstModel end: ")
+        worker = CreateSfcWorker(data)
+        job_id = worker.init_data()
+        worker.start()
+        logger.info("Service Function Chain Thread Sleep start : %s" %time.ctime())
+        time.sleep(2)
+        logger.info("Service Function Chain Thread Sleep end: %s" % time.ctime())
+        logger.info("Create Service Function Chain end")
+        return Response(data={"jobId": job_id,
+                              "sfcInstId": data["fpinstid"]},
+                        status=status.HTTP_200_OK)
diff --git a/lcm/ns/swagger.json b/lcm/ns/swagger.json
new file mode 100644 (file)
index 0000000..2664027
--- /dev/null
@@ -0,0 +1,1046 @@
+{
+    "swagger": "2.0",
+    "info": {
+        "version": "1.0.0",
+        "title": "ZTE vManager Service rest API"
+    },
+    "basePath": "/openoapi/nslcm/v1",
+    "tags": [
+        {
+            "name": "lcm Resource"
+        }
+    ],
+    "paths": {
+        "/ns/vls": {
+            "post": {
+                "tags": [
+                    "vls Resource"
+                ],
+                "summary": "vl create",
+                "description": "",
+                "operationId": "create_vl",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "in": "body",
+                        "name": "body",
+                        "description": "instantiate request param",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/VlPostRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "201": {
+                        "description": "",
+                        "schema": {
+                            "$ref": "#/definitions/VlPostResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/ns/vls/{vlId}": {
+            "get": {
+                "tags": [
+                    "vls Resource"
+                ],
+                "summary": "query the specified vl info",
+                "description": "",
+                "operationId": "query_vl",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "name": "vlId",
+                        "in": "path",
+                        "description": "vl instance id",
+                        "required": true,
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/VlInfo"
+                        }
+                    },
+                    "404": {
+                        "description": "the vl instance id is wrong"
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            },
+            "delete": {
+                "tags": [
+                    "vls Resource"
+                ],
+                "summary": "delete vl",
+                "description": "",
+                "operationId": "delete_vl",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "",
+                        "name": "vlId",
+                        "in": "path"
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/DeleteVlResponse"
+                        }
+                    },
+                    "404": {
+                        "description": "the vl instance id is wrong"
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            }
+        },
+        "/ns/vnfs": {
+            "post": {
+                "tags": [
+                    "vnfs Resource"
+                ],
+                "summary": "vnf create",
+                "description": "",
+                "operationId": "create_vnf",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "in": "body",
+                        "name": "body",
+                        "description": "instantiate request param",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/VnfPostRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "201": {
+                        "description": "",
+                        "schema": {
+                            "$ref": "#/definitions/VnfPostResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/ns/vnfs/{vnfInstId}": {
+            "get": {
+                "tags": [
+                    "vnfs Resource"
+                ],
+                "summary": "query the specified vnf info",
+                "description": "",
+                "operationId": "query_vnf",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "name": "vnfInstId",
+                        "in": "path",
+                        "description": "vnf instance id",
+                        "required": true,
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/VnfInfo"
+                        }
+                    },
+                    "404": {
+                        "description": "the vnf instance id is wrong"
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            },
+            "delete": {
+                "tags": [
+                    "vnfs Resource"
+                ],
+                "summary": "delete vnf",
+                "description": "",
+                "operationId": "delete_vnf",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "",
+                        "name": "vnfInstId",
+                        "in": "path"
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/DeleteResponse"
+                        }
+                    },
+                    "404": {
+                        "description": "the vl instance id is wrong"
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            }
+        },
+        "/ns/sfcs": {
+            "post": {
+                "tags": [
+                    "sfcs Resource"
+                ],
+                "summary": "sfc create",
+                "description": "",
+                "operationId": "create_sfc",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "in": "body",
+                        "name": "body",
+                        "description": "request param",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/SfcPostRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "201": {
+                        "description": "",
+                        "schema": {
+                            "$ref": "#/definitions/SfcPostResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/ns/sfcs/{sfcInstId}": {
+            "get": {
+                "tags": [
+                    "sfcs Resource"
+                ],
+                "summary": "query the specified sfc info",
+                "description": "",
+                "operationId": "query_sfc",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "name": "sfcInstId",
+                        "in": "path",
+                        "description": "sfc instance id",
+                        "required": true,
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/SfcInfo"
+                        }
+                    },
+                    "404": {
+                        "description": "the sfc instance id is wrong"
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            },
+            "delete": {
+                "tags": [
+                    "vnfs Resource"
+                ],
+                "summary": "delete sfc",
+                "description": "",
+                "operationId": "delete_sfc",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "",
+                        "name": "sfcInstId",
+                        "in": "path"
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/DeleteResponse"
+                        }
+                    },
+                    "404": {
+                        "description": "the sfc instance id is wrong"
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            }
+        },
+        "/ns/{nsInstanceId}/postdeal": {
+            "post": {
+                "tags": [
+                    "ns postdeal"
+                ],
+                "summary": "ns postdeal",
+                "description": "",
+                "operationId": "ns_postdeal",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "",
+                        "name": "nsInstanceId",
+                        "in": "path"
+                    },
+                    {
+                        "in": "body",
+                        "name": "body",
+                        "description": "request param",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/NSInstPostDetailRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "202": {
+                        "description": ""
+                    }
+                }
+            }
+        },
+        "/ns/{nsInstanceId}/scale": {
+            "post": {
+                "tags": [
+                    "ns scale"
+                ],
+                "summary": "ns scale",
+                "description": "ns scale",
+                "operationId": "ns_scale",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "",
+                        "name": "nsInstanceId",
+                        "in": "path"
+                    },
+                                       {
+                        "required": true,
+                        "type": "Enum",
+                        "description": "",
+                        "name": "scaleType",
+                        "in": "body"
+                    },
+                    {
+                        "in": "body",
+                        "name": "scaleNsData",
+                        "description": "scaleNsData",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/ScaleNsData"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "",
+                        "schema": {
+                            "$ref": "#/definitions/NsScaleResponse"
+                        }
+                    },
+                    "201": {
+                        "description": "Invalid Request"
+                    }
+                }
+            }
+        },
+        "/ns/{ns_instance_id}": {
+            "delete": {
+                "tags": [
+                    "ns lcm"
+                ],
+                "summary": "ns delete",
+                "description": "ns delete",
+                "operationId": "ns_delete",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "Identifier of the NS instance.",
+                        "name": "ns_instance_id",
+                        "in": "path"
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "The NS instance resource and the associated NS identifier were deleted successfully."
+                    }
+                }
+            }
+        },
+        "/ns/{ns_instance_id}/terminate": {
+            "post": {
+                "tags": [
+                    "ns lcm"
+                ],
+                "summary": "ns terminate",
+                "description": "ns terminate",
+                "operationId": "ns_terminate",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "Identifier of the NS instance.",
+                        "name": "ns_instance_id",
+                        "in": "path"
+                    },
+                    {
+                        "in": "body",
+                        "name": "NsTerminateRequest",
+                        "description": "NsTerminateRequest",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/NsTerminateRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "202": {
+                        "description": "",
+                        "schema": {
+                            "$ref": "#/definitions/NsTerminateResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            }
+        },
+        "/mandb/{modelName}": {
+            "get": {
+                "tags": [
+                    "ns lcm"
+                ],
+                "summary": "query ns table info",
+                "description": "query ns table info",
+                "operationId": "query_ns_table",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "model Name.",
+                        "name": "modelName",
+                        "in": "path"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/TableInfo"
+                        }
+                    },
+                    "500": {
+                        "description": "the url is invalid"
+                    }
+                }
+            },
+            "delete": {
+                "tags": [
+                    "ns lcm"
+                ],
+                "summary": "ns table delete",
+                "description": "ns table delete",
+                "operationId": "ns_table_delete",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "model Name.",
+                        "name": "modelName",
+                        "in": "path"
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "The tables were deleted successfully."
+                    }
+                }
+            }
+        },
+        "/ns": {
+            "get": {
+                "tags": [
+                    "ns lcm"
+                ],
+                "summary": "ns get",
+                "description": "ns get",
+                "operationId": "ns_get",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+  
+                ],
+                "responses": {
+                    "200": {
+                        "description": "successful operation",
+                        "schema": {
+                            "$ref": "#/definitions/NsInfo"
+                        }
+                    }
+                }
+            }
+        },
+        "/jobs/{jobId}":{
+          "post": {
+                "tags": [
+                    "jobstatus"
+                ],
+                "summary": "jobstatus",
+                "description": "",
+                "operationId": "jobstatus",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "parameters": [
+                    {
+                        "required": true,
+                        "type": "string",
+                        "description": "",
+                        "name": "jobId",
+                        "in": "path"
+                    },
+                    {
+                        "in": "body",
+                        "name": "body",
+                        "description": "request param",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/JobProgressRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "202": {
+                        "description": ""
+                    }
+                }
+            }
+        }
+    },
+    "definitions": {
+        "VlPostRequest": {
+            "type": "object",
+            "properties": {
+                "jobId": {
+                    "type": "string"
+                },
+                "nsInstanceId": {
+                    "type": "string"
+                },
+                "flavourId": {
+                    "type": "string"
+                },
+                "sapData": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "pnfInfo": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "vnfInstanceData": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "nestedNsInstanceId": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "locationConstraints": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "additionalParamForNs": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "additionalParamForVnf": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "extNSVirtualLink": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "context": {
+                    "type": "string"
+                },
+                "vlIndex": {
+                    "type": "string"
+                }
+            }
+        },
+        "VlPostResponse": {
+            "type": "object",
+            "properties": {
+                "result": {
+                    "type": "integer",
+                    "enum": [
+                        0,
+                        1
+                    ]
+                },
+                "detail": {
+                    "type": "string"
+                },
+                "vlId": {
+                    "type": "string"
+                }
+            }
+        },
+        "VnfPostRequest": {
+            "type": "object",
+            "properties": {
+                "jobId": {
+                    "type": "string"
+                },
+                "nsInstanceId": {
+                    "type": "string"
+                },
+                "flavourId": {
+                    "type": "string"
+                },
+                "sapData": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "pnfInfo": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "vnfInstanceData": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "nestedNsInstanceId": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "locationConstraints": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "additionalParamForNs": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "additionalParamForVnf": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "extNSVirtualLink": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "context": {
+                    "type": "string"
+                },
+                "vnfIndex": {
+                    "type": "string"
+                }
+            }
+        },
+        "VnfPostResponse": {
+            "type": "object",
+            "properties": {
+                "vnfInstId": {
+                    "type": "string"
+                },
+                "jobId": {
+                    "type": "string"
+                }
+            }
+        },
+        "SfcPostRequest": {
+            "type": "object",
+            "properties": {
+                "jobId": {
+                    "type": "string"
+                },
+                "nsInstanceId": {
+                    "type": "string"
+                },
+                "sapData": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "vnfInstanceData": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "additionalParamForNs": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "additionalParamForVnf": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    }
+                },
+                "sdnControllerId": {
+                    "type": "string"
+                },
+                "context": {
+                    "type": "string"
+                },
+                "fpindex": {
+                    "type": "string"
+                }
+            }
+        },
+        "NSInstPostDetailRequest": {
+            "type": "object",
+            "properties": {
+                "status": {
+                    "type": "string"
+                }
+            }
+        },
+        "JobProgressRequest": {
+            "type": "object",
+            "properties": {
+                "progress": {
+                    "type": "string"
+                },
+                "desc": {
+                    "type": "string"
+                },
+                "errcode": {
+                    "type": "string"
+                }
+            }
+        },
+        "SfcPostResponse": {
+            "type": "object",
+            "properties": {
+                "sfcInstId": {
+                    "type": "string"
+                },
+                "jobId": {
+                    "type": "string"
+                }
+            }
+        },
+        "VlInfo": {
+            "type": "object",
+            "properties": {
+                "vlId": {
+                    "type": "string"
+                },
+                "vlName": {
+                    "type": "string"
+                },
+                "vlStatus": {
+                    "type": "string"
+                }
+            }
+        },
+        "VnfInfo": {
+            "type": "object",
+            "properties": {
+                "vnfInstId": {
+                    "type": "string"
+                },
+                "vnfName": {
+                    "type": "string"
+                },
+                "vnfStatus": {
+                    "type": "string"
+                }
+            }
+        },
+        "SfcInfo": {
+            "type": "object",
+            "properties": {
+                "sfcInstId": {
+                    "type": "string"
+                },
+                "sfcName": {
+                    "type": "string"
+                },
+                "sfcStatus": {
+                    "type": "string"
+                }
+            }
+        },
+        "DeleteVlResponse": {
+            "type": "object",
+            "properties": {
+                "result": {
+                    "type": "integer",
+                    "enum": [
+                        0,
+                        1
+                    ]
+                },
+                "detail": {
+                    "type": "string"
+                }
+            }
+        },
+        "DeleteResponse": {
+            "type": "object",
+            "properties": {
+                "result": {
+                    "type": "integer",
+                    "enum": [
+                        0,
+                        1
+                    ]
+                },
+                "detail": {
+                    "type": "string"
+                }
+            }
+        },
+        "ScaleNsData": {
+            "type": "object",
+            "properties": {
+                "scaleNsByStepsData": {
+                    "$ref": "#/definitions/ScaleNsByStepsData"
+                }
+            }
+        },
+        "ScaleNsByStepsData": {
+            "type": "object",
+            "properties": {
+                "scalingDirection": {
+                    "type": "Enum"
+                },
+                "aspectId": {
+                    "type": "string"
+                },
+                "numberOfSteps": {
+                    "type": "integer"
+                }
+            }
+        },
+        "NsScaleResponse": {
+            "type": "object",
+            "properties": {
+                "jobID": {
+                    "type": "string"
+                }
+            }
+        },
+        "NsTerminateRequest": {
+            "type": "object",
+            "properties": {
+                "terminationType": {
+                    "type": "string"
+                },
+                "gracefulTerminationTimeout": {
+                    "type": "string"
+                }
+            }
+        },
+        "NsTerminateResponse": {
+            "type": "object",
+            "properties": {
+                "jobID": {
+                    "type": "string"
+                }
+            }
+        },
+        "TableInfo": {
+            "type": "object",
+            "properties": {
+                "count": {
+                    "type": "string"
+                }
+            }
+        },
+        "NsInfo": {
+            "type": "object",
+            "properties": {
+                "vnfInfoId": {
+                    "type": "string"
+                },
+                "vlInfo": {
+                    "type": "string"
+                },
+                "nsState": {
+                    "type": "string"
+                },
+                "description": {
+                    "type": "string"
+                },
+                "nsName": {
+                    "type": "string"
+                },
+                "nsInstanceId": {
+                    "type": "string"
+                },
+                "nsdId": {
+                    "type": "string"
+                },
+                "vnffgInfo": {
+                    "type": "string"
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lcm/ns/tests/__init__.py b/lcm/ns/tests/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/tests/sfcs/__init__.py b/lcm/ns/tests/sfcs/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/tests/sfcs/test_create_flow_classifier.py b/lcm/ns/tests/sfcs/test_create_flow_classifier.py
new file mode 100644 (file)
index 0000000..eb149dc
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright 2016 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 mock
+# import json
+# from test_data import nsd_model
+# from rest_framework import status
+# from lcm.pub.utils import restcall
+# from lcm.pub.database.models import FPInstModel
+# from django.test import Client
+# from django.test import TestCase
+#
+#
+# class TestSfc(TestCase):
+#     def setUp(self):
+#         self.client = Client()
+#         FPInstModel.objects.all().delete()
+#         FPInstModel(fpinstid="fp_inst_1", fpid="fpd_1", sdncontrollerid="test").save()
+#
+#     def tearDown(self):
+#         FPInstModel.objects.all().delete()
+#
+#     @mock.patch.object(restcall, 'call_req')
+#     def test_create_flow_classifier_success(self, mock_call_req):
+#         data = {
+#             "fpinstid": "fp_inst_1",
+#             "context": json.dumps(nsd_model)
+#         }
+#         mock_vals = {
+#             "/openoapi/extsys/v1/sdncontrollers/test":
+#                 [0, json.JSONEncoder().encode({"url": "url_1"}), '200'],
+#             "/openoapi/sdncdriver/v1.0/createflowclassfier":
+#                 [0, json.JSONEncoder().encode({"id": "test_id_1"}), '200'],
+#             "/openoapi/microservices/v1/services":
+#                 [0, None, '200']
+#
+#         }
+#
+#         def side_effect(*args):
+#             return mock_vals[args[4]]
+#
+#         mock_call_req.side_effect = side_effect
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/create_flow_classifier", data)
+#         ret = FPInstModel.objects.get(fpinstid="fp_inst_1")
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#         self.assertEqual("test_id_1", ret.flowclassifiers)
diff --git a/lcm/ns/tests/sfcs/test_create_port_chain.py b/lcm/ns/tests/sfcs/test_create_port_chain.py
new file mode 100644 (file)
index 0000000..ab68681
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright 2016 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 mock
+# import json
+# from test_data import nsd_model
+# from rest_framework import status
+# from lcm.pub.utils import restcall
+# from lcm.pub.database.models import FPInstModel
+# from django.test import Client
+# from django.test import TestCase
+#
+#
+# class TestSfc(TestCase):
+#     def setUp(self):
+#         self.client = Client()
+#         FPInstModel.objects.all().delete()
+#         FPInstModel(fpinstid="fp_inst_1", sdncontrollerid="test_sdncontrollerid",
+#                     symmetric=1, flowclassifiers="test_flowclassifiers",
+#                     portpairgroups=json.JSONEncoder().encode([{"groupid": "1"}])).save()
+#
+#     def tearDown(self):
+#         FPInstModel.objects.all().delete()
+#
+#     @mock.patch.object(restcall, 'call_req')
+#     def test_create_port_chain_success(self, mock_call_req):
+#         data = {
+#             "fpinstid": "fp_inst_1",
+#             "context": json.dumps(nsd_model)
+#         }
+#         mock_vals = {
+#             "/openoapi/extsys/v1/sdncontrollers/test_sdncontrollerid":
+#                 [0, json.JSONEncoder().encode({"url": "url_1"}), '200'],
+#             "/openoapi/sdncdriver/v1.0/createportchain":
+#                 [0, json.JSONEncoder().encode({"id": "test_id_1"}), '200'],
+#              "/openoapi/microservices/v1/services":
+#                  [0, None, '200']
+#         }
+#
+#         def side_effect(*args):
+#             return mock_vals[args[4]]
+#
+#         mock_call_req.side_effect = side_effect
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/create_port_chain", data)
+#         ret = FPInstModel.objects.get(fpinstid="fp_inst_1")
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#         self.assertEqual("test_id_1", ret.sfcid)
diff --git a/lcm/ns/tests/sfcs/test_create_port_pair_group.py b/lcm/ns/tests/sfcs/test_create_port_pair_group.py
new file mode 100644 (file)
index 0000000..a63b630
--- /dev/null
@@ -0,0 +1,81 @@
+# Copyright 2016 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 mock
+# import json
+# from test_data import nsd_model, vnfd_model_dict1, vnfd_model_dict2
+# from rest_framework import status
+# from lcm.pub.utils import restcall
+# from lcm.pub.database.models import FPInstModel, NfInstModel
+# from django.test import Client
+# from django.test import TestCase
+#
+#
+# class TestSfc(TestCase):
+#     def setUp(self):
+#         self.client = Client()
+#         FPInstModel.objects.all().delete()
+#         NfInstModel.objects.all().delete()
+#         NfInstModel(
+#             nfinstid="vnf_inst_1", ns_inst_id="ns_inst_1", vnf_id="vnf_1",
+#             vnfd_model=json.dumps(vnfd_model_dict1)).save()
+#         NfInstModel(
+#             nfinstid="vnf_inst_2", vnf_id="vnf_2", ns_inst_id="ns_inst_1",
+#             vnfd_model=json.dumps(vnfd_model_dict2)).save()
+#         FPInstModel(
+#             fpid="fpd_1", fpinstid="fp_inst_1", nsinstid="ns_inst_1", vnffginstid="vnffg_inst_1",
+#             policyinfo=[{
+#                 "type": "ACL",
+#                 "criteria": {
+#                     "dest_port_range": [80, 1024],
+#                     "source_port_range": [80, 1024],
+#                     "ip_protocol": "tcp",
+#                     "dest_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                     "source_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                     "dscp": 100,
+#                 }
+#             }],
+#             status="enabled",
+#             sdncontrollerid="sdn_controller_1"
+#         ).save()
+#
+#     def tearDown(self):
+#         FPInstModel.objects.all().delete()
+#         NfInstModel.objects.all().delete()
+#
+#     @mock.patch.object(restcall, 'call_req')
+#     def test_create_port_pair_group_success(self, mock_call_req):
+#         data = {
+#             "nsinstanceid": "ns_inst_1",
+#             "fpinstid": "fp_inst_1",
+#             "context": json.dumps(nsd_model)
+#         }
+#         mock_vals = {
+#             "/openoapi/extsys/v1/sdncontrollers/sdn_controller_1":
+#                 [0, json.JSONEncoder().encode({"url": "url_1"}), '200'],
+#             "/openoapi/sdncdriver/v1.0/createportpair":
+#                 [0, json.JSONEncoder().encode({"id": "createportpair_id"}), '200'],
+#             "/openoapi/sdncdriver/v1.0/createportpairgroup":
+#                 [0, json.JSONEncoder().encode({"id": "createportpairgroup_id"}), '200'],
+#             "/openoapi/microservices/v1/services":
+#                 [0, None, '200']
+#         }
+#
+#         def side_effect(*args):
+#             return mock_vals[args[4]]
+#
+#         mock_call_req.side_effect = side_effect
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/create_port_pair_group", data)
+#         rest = json.loads(FPInstModel.objects.get(fpinstid="fp_inst_1").portpairgroups)[0]
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#         self.assertEqual("createportpairgroup_id", rest["groupid"])
diff --git a/lcm/ns/tests/sfcs/test_data.py b/lcm/ns/tests/sfcs/test_data.py
new file mode 100644 (file)
index 0000000..e873464
--- /dev/null
@@ -0,0 +1,1411 @@
+# Copyright 2016 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.
+
+nsd_model = {
+    "metadata": {
+        "id": "nsd_demo",
+        "vendor": "zte",
+        "version": "1.1.0",
+        "name": "testNSD",
+        "description": "demo nsd",
+    },
+
+    "inputs": {
+        "param1": "11",
+        "param2": "22",
+    },
+
+    "vnfs": [
+        {
+            "type": "tosca.nodes.nfv.ext.VNF.FireWall",
+            "vnf_id": "vnf_1",
+            "description": "",
+            "properties": {
+                "id": "vnfd_1",
+                "vendor": "zte",
+                "version": "1.2.0",
+                "vnfd_version": "1.1.0",
+                "vnf_type": "vnf1",
+                "domain_type": "CN",
+                "name": "vnf1",
+                "is_shared": False,
+                "cross_dc": False,
+                "request_reclassification": False,
+                "nsh_aware": False,
+                "custom_properties": {
+                    "key1": "value1",
+                    "keyN": "valueN",
+                },
+            },
+            "dependencies": [
+                "vnf_id1", "vnf_id2"
+            ],
+            "networks": [
+                {
+                    "key_name": "virtualLink1",
+                    "vl_id": "vl_id1",
+                },
+            ],
+        },
+        {
+            "type": "tosca.nodes.nfv.ext.VNF.FireWall",
+            "vnf_id": "vnf_2",
+            "description": "",
+            "properties": {
+                "id": "vnfd_2",
+                "vendor": "zte",
+                "version": "1.2.0",
+                "vnfd_version": "1.1.0",
+                "vnf_type": "vnf2",
+                "domain_type": "CN",
+                "name": "vnf1",
+                "is_shared": False,
+                "cross_dc": False,
+                "request_reclassification": False,
+                "nsh_aware": False,
+                "custom_properties": {
+                    "key1": "value1",
+                    "keyN": "valueN",
+                },
+            },
+            "dependencies": [
+                "vnf_id1", "vnf_id2"
+            ],
+            "networks": [
+                {
+                    "key_name": "virtualLink1",
+                    "vl_id": "vl_id1",
+                },
+            ],
+        }
+    ],
+
+    "pnfs": [
+        {
+            "pnf_id": "pnf1",
+            "description": "",
+            "properties": {
+                "id": "pnf1",
+                "vendor": "zte",
+                "version": "1.1.0",
+                "pnf_type": "TTGW",
+                "request_reclassification": False,
+                "nsh_aware": False,
+            },
+            "cps": [
+                "cpd_1", "cpd_22",
+            ]
+        }
+    ],
+
+    "nested_ns": [
+        {
+            "ns_id": "ns2",
+            "description": "",
+            "properties": {
+                "id": "ns2_demo",
+                "vendor": "zte",
+                "version": "1.1.0",
+                "name": "NSD2",
+            },
+            "networks": [
+                {
+                    "key_name": "virtualLink1",
+                    "vl_id": "vl_id1",
+                },
+            ],
+        }
+    ],
+
+    "vls": [
+        {
+            "vl_id": "vldId1",
+            "description": "",
+            "properties": {
+                "name": "umac_241_control",
+                "network_id": "fgdhsj434hfjdfd",
+                "network_name": "umac_control",
+                "vendor": "zte",
+                "mtu": 1500,
+                "network_type": "vlan",
+                "physical_network": "phynet01",
+                "segmentation_id": "30",
+                "vlan_transparent": False,
+                "vds_name": "vds1",
+                "cidr": "192.168.199.0/24",
+                "ip_version": 4,
+                "gateway_ip": "192.168.199.1",
+                "dhcp_enabled": False,
+                "dns_nameservers": ["192.168.0.4", "192.168.0.10"],
+                "start_ip": "192.168.199.2",
+                "end_ip": "192.168.199.254",
+                "host_routes": [
+                    {
+                        "destination": "10.43.26.0/24",
+                        "nexthop": "10.41.23.1",
+                    },
+                ],
+                "location_info": {
+                    "vimId": "vimid",
+                    "tenant": "tenantname",
+                },
+                "vlan_transparent": False,
+            },
+        },
+    ],
+
+    "cps": [
+        {
+            "cp_id": "cpd_1",
+            "description": "",
+            "properties": {
+                "mac_address": "00:d9:00:82:11:e1",
+                "ip_address": "192.168.1.21",
+                "ip_range_start": "192.168.1.20",
+                "ip_range_end": "192.168.1.29",
+                "floating_ip_address": {
+                    "external_network": "extnet01",
+                    "ip_address": "10.43.53.23",
+                },
+                "service_ip_address": "192.168.1.23",
+                "order": 1,
+                "bandwidth": 1000,
+                "vnic_type": "normal",
+                "allowed_address_pairs": [
+                    {
+                        "ip": "192.168.1.13",
+                        "mac": "00:f3:43:20:a2:a3"
+                    },
+                ],
+                "bond": "none",
+                "macbond": "00:d9:00:82:11:d1",
+                "sfc_encapsulation": "",
+                "direction": "",
+            },
+            "vl_id": "vlid1",
+            "pnf_id": "pnf1",
+        },
+
+        {
+            "cp_id": "forwarder_brasDP_dcPort",
+            "description": "",
+            "properties": {
+                "mac_address": "00:d9:00:82:14:e1",
+                "ip_address": "192.168.1.24",
+                "ip_range_start": "192.168.1.20",
+                "ip_range_end": "192.168.1.29",
+                "floating_ip_address": {
+                    "external_network": "extnet01",
+                    "ip_address": "10.43.53.23",
+                },
+                "service_ip_address": "192.168.1.23",
+                "order": 1,
+                "bandwidth": 1000,
+                "vnic_type": "normal",
+                "allowed_address_pairs": [
+                    {
+                        "ip": "192.168.1.13",
+                        "mac": "00:f3:43:20:a2:a3"
+                    },
+                ],
+                "bond": "none",
+                "macbond": "00:d9:00:82:11:d1",
+                "sfc_encapsulation": "",
+                "direction": "",
+            },
+            "vl_id": "vlid1",
+            "pnf_id": "pnf1",
+        },
+        {
+            "cp_id": "forwarder_brasDP_internetPort",
+            "description": "",
+            "properties": {
+                "mac_address": "00:d9:00:82:15:e1",
+                "ip_address": "192.168.1.25",
+                "ip_range_start": "192.168.1.20",
+                "ip_range_end": "192.168.1.29",
+                "floating_ip_address": {
+                    "external_network": "extnet01",
+                    "ip_address": "10.43.53.23",
+                },
+                "service_ip_address": "192.168.1.23",
+                "order": 1,
+                "bandwidth": 1000,
+                "vnic_type": "normal",
+                "allowed_address_pairs": [
+                    {
+                        "ip": "192.168.1.13",
+                        "mac": "00:f3:43:20:a2:a3"
+                    },
+                ],
+                "bond": "none",
+                "macbond": "00:d9:00:82:11:d1",
+                "sfc_encapsulation": "",
+                "direction": "",
+            },
+            "vl_id": "vlid1",
+            "pnf_id": "pnf1",
+        },
+
+    ],
+
+    "fps": [
+        {
+            "fp_id": "fpd_1",
+            "description": "",
+            "properties": {
+                "policy": {
+                    "type": "ACL",
+                    "criteria": {
+                        "dest_port_range": [80, 1024],
+                        "source_port_range": [80, 1024],
+                        "ip_protocol": "tcp",
+                        "dest_ip_range": ["192.168.1.2", "192.168.1.100"],
+                        "source_ip_range": ["192.168.1.2", "192.168.1.100"],
+                        "dscp": 100,
+                    },
+                },
+                "symmetric": True,
+            },
+            "forwarder_list": [
+                {
+                    "type": "cp",
+                    "node_name": "cpd_1",
+                    "capability": "",
+                },
+                {
+                    "type": "cp",
+                    "node_name": "forwarder_brasDP_dcPort",
+                    "capability": "",
+                },
+                {
+                    "type": "vnf",
+                    "node_name": "vnf_1",
+                    "capability": "forwarder1",
+                },
+                {
+                    "type": "vnf",
+                    "node_name": "vnf_2",
+                    "capability": "forwarder2",
+                },
+                {
+                    "type": "cp",
+                    "node_name": "forwarder_brasDP_dcPort",
+                    "capability": "",
+                },
+                {
+                    "type": "cp",
+                    "node_name": "forwarder_brasDP_internetPort",
+                    "capability": "",
+                },
+            ],
+        },
+
+        {
+            "fp_id": "fpd_2",
+            "description": "",
+            "properties": {
+                "policy": {
+                    "type": "ACL",
+                    "criteria": {
+                        "dest_port_range": [80, 1024],
+                        "source_port_range": [80, 1024],
+                        "ip_protocol": "tcp",
+                        "dest_ip_range": ["192.168.1.2", "192.168.1.100"],
+                        "source_ip_range": ["192.168.1.2", "192.168.1.100"],
+                        "dscp": 100,
+                    },
+                },
+                "symmetric": True,
+            },
+            "forwarder_list": [
+
+                {
+                    "type": "cp",
+                    "node_name": "forwarder_brasDP_internetPort",
+                    "capability": "",
+                },
+                {
+                    "type": "cp",
+                    "node_name": "forwarder_brasDP_dcPort",
+                    "capability": "",
+                },
+                {
+                    "type": "vnf",
+                    "node_name": "vnf_2",
+                    "capability": "forwarder2",
+                },
+
+            ],
+        },
+    ],
+
+    "vnffgs": [
+        {
+            "vnffg_id": "vnffg_id1",
+            "description": "",
+            "properties": {
+                "vendor": "zte",
+                "version": "1.1.2",
+                "number_of_endpoints": 7,
+                "dependent_virtual_link": ["vldId1"],
+                "connection_point": ["CP01", "CP02"],
+                "constituent_vnfs": ["vnf_id1", "vnf_id2"],
+                "constituent_pnfs": ["pnf1", "pnf2"],
+            },
+            "members": ["fpd_1", "fpd_2"],
+        }
+    ],
+
+    "server_groups": [
+        {
+            "group_id": "",
+            "description": "",
+            "properties": {
+                "name": "server_group1",
+                "affinity_antiaffinity": "anti-affinity",
+                "scope": "host",
+            },
+            "members": ["vnf1", "vnf2"],
+        },
+    ],
+
+    "ns_exposed": {
+        "external_cps": [
+            {
+                "key_name": "virtualLink1",
+                "cp_id": "cp1",
+            },
+        ],
+        "forward_cps": [
+            {
+                "key_name": "forwarder_brasDP_userPort",
+                "cp_id": "cpd_1",
+            },
+            {
+                "key_name": "forwarder_brasDP_internetPort",
+                "cp_id": "cpd_4",
+            },
+            {
+                "key_name": "forwarder_brasDP_dcPort",
+                "cp_id": "cpd_5",
+            },
+
+        ],
+    },
+
+    "policies": [
+        {
+            "scaling": [
+                {
+                    "policy_id": "id1",
+                    "description": "",
+                    "properties": {
+                        "policy_file": "Policies/ns1-policy.xml",
+                    },
+                    "targets": ['pfu_vm'],
+                },
+            ],
+        },
+    ],
+
+    "ns_flavours": [
+        {
+            "flavour_id": "flavour1",
+            "description": "",
+            "vnf_profiles": [
+                {
+                    "vnf_id": "vnf1",
+                    "flavour_id": "flavour1",
+                    "instances_minimum_number": 1,
+                    "instances_maximum_number": 4,
+                    "local_affinity_antiaffinity_rule": [
+                        {
+                            "affinity_antiaffinity": "affinity",
+                            "scope": "node",
+                        }
+                    ]
+                },
+            ],
+            "pnf_profiles": [
+                {
+                    "pnf_id": "pnf1",
+                },
+            ],
+            "vl_profiles": [
+                {
+                    "vl_id": "vlid1",
+                    "bitrate_requirements": {
+                        "root": 1000,
+                        "leaf": 100
+                    },
+                    "qos": {
+                        "maximum_latency": "1 ms",
+                        "maximum_jitter": "10 ms",
+                        "maximum_packet_loss_ratio": 0.5
+                    },
+                }
+            ],
+            "instantiation_levels": [
+                {
+                    "id": "instLevel1",
+                    "description": "",
+                    "vnf_levels": [
+                        {
+                            "vnf_id": "",
+                            "vnf_instantiation_level": "small",
+                            "instances_number": 1
+                        },
+                    ],
+                    "scale_level_id": "scaleLevel1",
+                }
+            ],
+            "default_instantiation_level": "instLevel1",
+            "scale_levels": [
+                {
+                    "id": "scaleLevel1",
+                    "order": 1,
+                    "vnf_levels": [
+                        {
+                            "vnf_id": "",
+                            "vnf_instantiation_level": "small",
+                            "instances_number": 1
+                        },
+                    ],
+                },
+            ],
+            "supported_operations": ["Scale", "Heal"],
+            "affinity_antiaffinity_groups": [
+                {
+                    "group_id": "group1Id",
+                    "name": "groupName",
+                    "affinity_antiaffinity": "affinity",
+                    "scope": "node",
+                    "members": [
+                        "vnfId1", "vnfIdN",
+                    ],
+                },
+            ],
+        },
+    ],
+}
+vnfd_model_dict1 = {
+
+    'vdus': [
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'2'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_omm.001',
+            'image_file': u'opencos_sss_omm_img_release_20150723-1-disk1',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'omm.001',
+                'manual_scale_select_vim': False
+            },
+            'description': u'singleommvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'4'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_1',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'1',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ompvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_2',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'2',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ompvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_3',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'3',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ompvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'4'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_10',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'10',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ppvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_11',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'11',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ppvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_12',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'12',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ppvm'
+        }
+    ],
+    'volumn_storages': [
+
+    ],
+    'policies': {
+        'scaling': {
+            'targets': {
+
+            },
+            'policy_id': u'policy_scale_sss-vnf-template',
+            'properties': {
+                'policy_file': '*-vnfd.zip/*-vnf-policy.xml'
+            },
+            'description': ''
+        }
+    },
+    'image_files': [
+        {
+            'description': '',
+            'properties': {
+                'name': u'opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+                'checksum': '',
+                'disk_format': u'VMDK',
+                'file_url': u'./zte-cn-sss-main-image/OMM/opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+                'container_type': 'vm',
+                'version': '',
+                'hypervisor_type': 'kvm'
+            },
+            'image_file_id': u'opencos_sss_omm_img_release_20150723-1-disk1'
+        },
+        {
+            'description': '',
+            'properties': {
+                'name': u'sss.vmdk',
+                'checksum': '',
+                'disk_format': u'VMDK',
+                'file_url': u'./zte-cn-sss-main-image/NE/sss.vmdk',
+                'container_type': 'vm',
+                'version': '',
+                'hypervisor_type': 'kvm'
+            },
+            'image_file_id': u'sss'
+        }
+    ],
+    'vls': [
+
+    ],
+    'cps': [
+        {'cp_id': 'cpd_1',
+         "description": "",
+         "properties": {
+             "mac_address": "00:d9:00:82:11:e1",
+             "ip_address": "10.43.25.2",
+             "ip_range_start": "192.168.1.20",
+             "ip_range_end": "192.168.1.29",
+             "sfc_encapsulation": ""
+         }
+         },
+    ],
+    'metadata': {
+        'vendor': u'zte',
+        'is_shared': False,
+        'description': '',
+        'domain_type': u'CN',
+        'version': u'v4.14.10',
+        'vmnumber_overquota_alarm': False,
+        'cross_dc': False,
+        'vnf_type': u'SSS',
+        'vnfd_version': u'V00000001',
+        'id': u'vnfd_2',
+        'name': u'sss-vnf-template'
+    },
+
+    'vnf_exposed': {
+        "external_cps": [
+            {
+                "key_name": "virtualLink1",
+                "cp_id": "cp1",
+            },
+        ],
+        "forward_cps": [
+            {
+                "key_name": "forwarder1",
+                "cp_id": "cpd_1",
+            },
+            {
+                "key_name": "forwarder2",
+                "cp_id": "cpd_2",
+            },
+        ],
+    }
+}
+vnfd_model_dict2 = {
+    'local_storages': [
+
+    ],
+    'vdus': [
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'2'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_omm.001',
+            'image_file': u'opencos_sss_omm_img_release_20150723-1-disk1',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'omm.001',
+                'manual_scale_select_vim': False
+            },
+            'description': u'singleommvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'4'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_1',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'1',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ompvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_2',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'2',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ompvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_3',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'3',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ompvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'4'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_10',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'10',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ppvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_11',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'11',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ppvm'
+        },
+        {
+            'volumn_storages': [
+
+            ],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'
+            },
+            'local_storages': [
+
+            ],
+            'vdu_id': u'vdu_12',
+            'image_file': u'sss',
+            'dependencies': [
+
+            ],
+            'vls': [
+
+            ],
+            'cps': [
+
+            ],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''
+                },
+                'inject_data_list': [
+
+                ],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''
+                },
+                'local_affinity_antiaffinity_rule': {
+
+                },
+                'template_id': u'12',
+                'manual_scale_select_vim': False
+            },
+            'description': u'ppvm'
+        }
+    ],
+    'volumn_storages': [
+
+    ],
+    'policies': {
+        'scaling': {
+            'targets': {
+
+            },
+            'policy_id': u'policy_scale_sss-vnf-template',
+            'properties': {
+                'policy_file': '*-vnfd.zip/*-vnf-policy.xml'
+            },
+            'description': ''
+        }
+    },
+    'image_files': [
+        {
+            'description': '',
+            'properties': {
+                'name': u'opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+                'checksum': '',
+                'disk_format': u'VMDK',
+                'file_url': u'./zte-cn-sss-main-image/OMM/opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+                'container_type': 'vm',
+                'version': '',
+                'hypervisor_type': 'kvm'
+            },
+            'image_file_id': u'opencos_sss_omm_img_release_20150723-1-disk1'
+        },
+        {
+            'description': '',
+            'properties': {
+                'name': u'sss.vmdk',
+                'checksum': '',
+                'disk_format': u'VMDK',
+                'file_url': u'./zte-cn-sss-main-image/NE/sss.vmdk',
+                'container_type': 'vm',
+                'version': '',
+                'hypervisor_type': 'kvm'
+            },
+            'image_file_id': u'sss'
+        }
+    ],
+    'vls': [
+
+    ],
+    'cps': [
+        {'cp_id': 'cpd_2',
+         "description": "",
+         "properties": {
+             "mac_address": "00:d9:00:82:11:e2",
+             "ip_address": "10.43.25.3",
+             "ip_range_start": "192.168.1.20",
+             "ip_range_end": "192.168.1.29",
+             "sfc_encapsulation": ""
+         }
+         },
+    ],
+    'metadata': {
+        'vendor': u'zte',
+        'is_shared': False,
+        'description': '',
+        'domain_type': u'CN',
+        'version': u'v4.14.10',
+        'vmnumber_overquota_alarm': False,
+        'cross_dc': False,
+        'vnf_type': u'SSS',
+        'vnfd_version': u'V00000001',
+        'id': u'sss-vnf-template',
+        'name': u'vnfd_2'
+    },
+    'vnf_exposed': {
+        "external_cps": [
+            {
+                "key_name": "virtualLink1",
+                "cp_id": "cp1",
+            },
+        ],
+        "forward_cps": [
+            {
+                "key_name": "forwarder2",
+                "cp_id": "cpd_2",
+            },
+            {
+                "key_name": "forwarder3",
+                "cp_id": "cpd_2",
+            },
+        ],
+    }
+}
+
+
+
+
diff --git a/lcm/ns/tests/sfcs/test_sfc.py b/lcm/ns/tests/sfcs/test_sfc.py
new file mode 100644 (file)
index 0000000..cabead0
--- /dev/null
@@ -0,0 +1,1652 @@
+# Copyright 2016 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 mock
+# from django.test import Client
+# from django.test import TestCase
+# from rest_framework import status
+#
+# from lcm.pub.database.models import FPInstModel, CPInstModel, PortInstModel, NfInstModel
+# from lcm.pub.database.models import VNFFGInstModel
+# from lcm.pub.msapi import extsys
+# from lcm.pub.msapi import sdncdriver
+# from lcm.pub.utils import restcall
+#
+#
+# class TestSfc(TestCase):
+#     def setUp(self):
+#         self.client = Client()
+#         FPInstModel.objects.filter().delete()
+#         VNFFGInstModel.objects.filter().delete()
+#         CPInstModel.objects.filter().delete()
+#         PortInstModel.objects.filter().delete()
+#         NfInstModel.objects.filter().delete()
+#
+#         self.save_vnffg_inst_data()
+#         self.save_vnf_inst_data()
+#         self.save_cp_inst_data()
+#         self.save_port_inst_data()
+#         self.save_fp_inst_data()
+#
+#     def tearDown(self):
+#         pass
+#
+#     @mock.patch.object(restcall, 'call_req')
+#     def test_sfc_instanciate(self, mock_call_req):
+#         data = {
+#             "nsinstanceid": "ns_inst_1",
+#             "context": json.dumps(nsd_model),
+#             "fpindex": "fpd_1",
+#             "sdncontrollerid": "sdnControllerId_1"
+#         }
+#
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/sfc_instance", data, format='json')
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#
+#     @mock.patch.object(extsys, "get_sdn_controller_by_id")
+#     @mock.patch.object(sdncdriver, "create_flow_classfier")
+#     @mock.patch.object(restcall, 'call_req')
+#     def test_create_flow_classfier(self, mock_call_req, mock_create_flow_classfier, mock_get_sdn_controller_by_id):
+#         data = {
+#             "fpinstid": "fp_inst_1",
+#             "context": json.dumps(nsd_model)
+#         }
+#         mock_create_flow_classfier.return_value = [0, json.dumps({'id': '1'})]
+#         mock_get_sdn_controller_by_id.return_value = json.loads('{"test":"test_name","url":"url_add"}')
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/create_flow_classifier", data)
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#
+#     @mock.patch.object(extsys, "get_sdn_controller_by_id")
+#     @mock.patch.object(sdncdriver, 'create_port_pair_group')
+#     @mock.patch.object(sdncdriver, 'create_port_pair')
+#     @mock.patch.object(restcall, 'call_req')
+#     def test_create_port_pair_group(self, mock_call_req, mock_create_port_pair, mock_create_port_pair_group
+#                                     , mock_get_sdn_controller_by_id):
+#         data = {
+#             "nsinstanceid": "ns_inst_1",
+#             "fpinstid": "fp_inst_1",
+#             "context": json.dumps(nsd_model)
+#         }
+#         mock_create_port_pair.return_value = [0, json.dumps({'id': '1'})]
+#         mock_create_port_pair_group.return_value = [0, json.dumps({'id': '1'})]
+#         mock_get_sdn_controller_by_id.return_value = json.loads('{"test":"test_name","url":"url_add"}')
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/create_port_pair_group", data)
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#
+#     @mock.patch.object(extsys, "get_sdn_controller_by_id")
+#     @mock.patch.object(sdncdriver, 'create_port_chain')
+#     @mock.patch.object(restcall, 'call_req')
+#     def test_create_port_chain(self, mock_call_req, mock_create_port_chain
+#                                , mock_get_sdn_controller_by_id):
+#         data = {
+#             "nsinstanceid": "ns_inst_1",
+#             "fpinstid": "fp_inst_1",
+#             "context": json.dumps(nsd_model)
+#         }
+#         self.update_fp_inst_data()
+#         mock_create_port_chain.return_value = [0, json.dumps({'id': '1'})]
+#         mock_get_sdn_controller_by_id.return_value = json.loads('{"test":"test_name","url":"url_add"}')
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/create_port_chain", data)
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#
+#     # @mock.patch.object(restcall, 'call_req')
+#     # def test_create_sfc(self, mock_call_req):
+#     #     data = {
+#     #         "nsinstanceid": "ns_inst_1",
+#     #         "context": json.dumps(nsd_model),
+#     #         "fpindex": "fpd_1",
+#     #         'fpinstid': str(uuid.uuid4()),
+#     #         "sdncontrollerid": "sdnControllerId_1"
+#     #     }
+#     #
+#     #     resp = self.client.post("/openoapi/nslcm/v1/ns/sfc", data, format='json')
+#     #     self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#
+#     def update_fp_inst_data(self):
+#         FPInstModel.objects.filter(fpinstid="fp_inst_1").update(flowclassifiers="1",
+#                                                                 portpairgroups=json.JSONEncoder().encode([{
+#                                                                     "groupid": "1",
+#                                                                     "portpair": ["2"]
+#                                                                 }]))
+#
+#     def save_vnffg_inst_data(self):
+#         VNFFGInstModel(
+#             vnffgdid="vnffg_id1",
+#             vnffginstid="vnffg_inst_1",
+#             nsinstid="ns_inst_1",
+#             endpointnumber=2,
+#             vllist="vlinst1",
+#             cplist="cp1",
+#             vnflist="vnf1,vnf2"
+#         ).save()
+#
+#     def save_cp_inst_data(self):
+#         CPInstModel(
+#             cpinstanceid="cp_inst_1",
+#             cpdid="cpd_1",
+#             ownertype=0,
+#             ownerid="vnf_inst_1",
+#             relatedtype=1,
+#             relatedport="port_inst_1"
+#         ).save()
+#
+#         CPInstModel(
+#             cpinstanceid="cp_inst_2",
+#             cpdid="cpd_2",
+#             ownertype=0,
+#             ownerid="vnf_inst_2",
+#             relatedtype=1,
+#             relatedport="port_inst_2"
+#         ).save()
+#
+#     def save_fp_inst_data(self):
+#         FPInstModel(
+#             fpid="fpd_1",
+#             fpinstid="fp_inst_1",
+#             nsinstid="ns_inst_1",
+#             vnffginstid="vnffg_inst_1",
+#             policyinfo=[{
+#                 "type": "ACL",
+#                 "criteria": {
+#                     "dest_port_range": [80, 1024],
+#                     "source_port_range": [80, 1024],
+#                     "ip_protocol": "tcp",
+#                     "dest_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                     "source_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                     "dscp": 100,
+#                 }
+#             }],
+#             status="enabled",
+#             sdncontrollerid="sdn_controller_1"
+#
+#         ).save()
+#
+#         FPInstModel(
+#             fpid="fpd_2",
+#             fpinstid="fp_inst_2",
+#             nsinstid="ns_inst_1",
+#             vnffginstid="vnffg_inst_1",
+#             policyinfo=[{
+#                 "type": "ACL",
+#                 "criteria": {
+#                     "dest_port_range": [80, 1024],
+#                     "source_port_range": [80, 1024],
+#                     "ip_protocol": "tcp",
+#                     "dest_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                     "source_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                     "dscp": 100,
+#                 }
+#             }],
+#             status="enabled",
+#             sdncontrollerid="sdn_controller_1"
+#
+#         ).save()
+#
+#     #
+#     # def save_sdnc_inst_data(self):
+#     #     SDNCModel(
+#     #         uuid="uuid_111",
+#     #         sdncontrollerid="sdn_controller_1",
+#     #         name="111",
+#     #         type="vnf",
+#     #         url="192.168.0.1:8080",
+#     #         username="admin",
+#     #         pwd="admin",
+#     #         ver="ver",
+#     #         longitude="longitude",
+#     #         latitude="latitude"
+#     #
+#     #     ).save()
+#
+#
+#
+#
+#     def save_port_inst_data(self):
+#         PortInstModel(
+#             portid="port_inst_1",
+#             networkid="network_inst_1",
+#             subnetworkid="subnetwork_inst_1",
+#             vimid="vim_1",
+#             # insttype="2",
+#             resourceid="res_1",
+#             ipaddress="10.43.25.2",
+#             macaddress="EC-F4-BB-20-43-F1"
+#         ).save()
+#
+#         PortInstModel(
+#             portid="port_inst_2",
+#             networkid="network_inst_1",
+#             subnetworkid="subnetwork_inst_1",
+#             vimid="vim_1",
+#             # insttype="2",
+#             resourceid="res_1",
+#             ipaddress="10.43.25.3",
+#             macaddress="EC-F4-BB-20-43-F2"
+#         ).save()
+#
+#     def save_vnf_inst_data(self):
+#         NfInstModel(
+#             nfinstid="vnf_inst_1",
+#             ns_inst_id="ns_inst_1",
+#             vnf_id="vnf_1",
+#             vnfd_model=json.dumps(vnfd_model_dict1)
+#
+#         ).save()
+#
+#         NfInstModel(
+#             nfinstid="vnf_inst_2",
+#             vnf_id="vnf_2",
+#             ns_inst_id="ns_inst_1",
+#             vnfd_model=json.dumps(vnfd_model_dict2)
+#
+#         ).save()
+#
+#
+# vnfd_model_dict1 = {
+#
+#     'vdus': [
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'2'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_omm.001',
+#             'image_file': u'opencos_sss_omm_img_release_20150723-1-disk1',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'omm.001',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'singleommvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'4'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_1',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'1',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ompvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_2',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'2',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ompvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_3',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'3',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ompvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'4'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_10',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'10',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ppvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_11',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'11',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ppvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_12',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'12',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ppvm'
+#         }
+#     ],
+#     'volumn_storages': [
+#
+#     ],
+#     'policies': {
+#         'scaling': {
+#             'targets': {
+#
+#             },
+#             'policy_id': u'policy_scale_sss-vnf-template',
+#             'properties': {
+#                 'policy_file': '*-vnfd.zip/*-vnf-policy.xml'
+#             },
+#             'description': ''
+#         }
+#     },
+#     'image_files': [
+#         {
+#             'description': '',
+#             'properties': {
+#                 'name': u'opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+#                 'checksum': '',
+#                 'disk_format': u'VMDK',
+#                 'file_url': u'./zte-cn-sss-main-image/OMM/opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+#                 'container_type': 'vm',
+#                 'version': '',
+#                 'hypervisor_type': 'kvm'
+#             },
+#             'image_file_id': u'opencos_sss_omm_img_release_20150723-1-disk1'
+#         },
+#         {
+#             'description': '',
+#             'properties': {
+#                 'name': u'sss.vmdk',
+#                 'checksum': '',
+#                 'disk_format': u'VMDK',
+#                 'file_url': u'./zte-cn-sss-main-image/NE/sss.vmdk',
+#                 'container_type': 'vm',
+#                 'version': '',
+#                 'hypervisor_type': 'kvm'
+#             },
+#             'image_file_id': u'sss'
+#         }
+#     ],
+#     'vls': [
+#
+#     ],
+#     'cps': [
+#         {'cp_id': 'cpd_1',
+#          "description": "",
+#          "properties": {
+#              "mac_address": "00:d9:00:82:11:e1",
+#              "ip_address": "10.43.25.2",
+#              "ip_range_start": "192.168.1.20",
+#              "ip_range_end": "192.168.1.29",
+#              "sfc_encapsulation": ""
+#          }
+#          },
+#     ],
+#     'metadata': {
+#         'vendor': u'zte',
+#         'is_shared': False,
+#         'description': '',
+#         'domain_type': u'CN',
+#         'version': u'v4.14.10',
+#         'vmnumber_overquota_alarm': False,
+#         'cross_dc': False,
+#         'vnf_type': u'SSS',
+#         'vnfd_version': u'V00000001',
+#         'id': u'vnfd_2',
+#         'name': u'sss-vnf-template'
+#     },
+#
+#     'vnf_exposed': {
+#         "external_cps": [
+#             {
+#                 "key_name": "virtualLink1",
+#                 "cp_id": "cp1",
+#             },
+#         ],
+#         "forward_cps": [
+#             {
+#                 "key_name": "forwarder1",
+#                 "cp_id": "cpd_1",
+#             },
+#             {
+#                 "key_name": "forwarder2",
+#                 "cp_id": "cpd_2",
+#             },
+#         ],
+#     }
+# }
+#
+# vnfd_model_dict2 = {
+#     'local_storages': [
+#
+#     ],
+#     'vdus': [
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'2'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_omm.001',
+#             'image_file': u'opencos_sss_omm_img_release_20150723-1-disk1',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'omm.001',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'singleommvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'4'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_1',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'1',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ompvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_2',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'2',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ompvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_3',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'3',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ompvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'4'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_10',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'10',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ppvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_11',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'11',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ppvm'
+#         },
+#         {
+#             'volumn_storages': [
+#
+#             ],
+#             'nfv_compute': {
+#                 'mem_size': '',
+#                 'num_cpus': u'14'
+#             },
+#             'local_storages': [
+#
+#             ],
+#             'vdu_id': u'vdu_12',
+#             'image_file': u'sss',
+#             'dependencies': [
+#
+#             ],
+#             'vls': [
+#
+#             ],
+#             'cps': [
+#
+#             ],
+#             'properties': {
+#                 'key_vdu': '',
+#                 'support_scaling': False,
+#                 'vdu_type': '',
+#                 'name': '',
+#                 'storage_policy': '',
+#                 'location_info': {
+#                     'vimId': '',
+#                     'availability_zone': '',
+#                     'region': '',
+#                     'dc': '',
+#                     'host': '',
+#                     'tenant': ''
+#                 },
+#                 'inject_data_list': [
+#
+#                 ],
+#                 'watchdog': {
+#                     'action': '',
+#                     'enabledelay': ''
+#                 },
+#                 'local_affinity_antiaffinity_rule': {
+#
+#                 },
+#                 'template_id': u'12',
+#                 'manual_scale_select_vim': False
+#             },
+#             'description': u'ppvm'
+#         }
+#     ],
+#     'volumn_storages': [
+#
+#     ],
+#     'policies': {
+#         'scaling': {
+#             'targets': {
+#
+#             },
+#             'policy_id': u'policy_scale_sss-vnf-template',
+#             'properties': {
+#                 'policy_file': '*-vnfd.zip/*-vnf-policy.xml'
+#             },
+#             'description': ''
+#         }
+#     },
+#     'image_files': [
+#         {
+#             'description': '',
+#             'properties': {
+#                 'name': u'opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+#                 'checksum': '',
+#                 'disk_format': u'VMDK',
+#                 'file_url': u'./zte-cn-sss-main-image/OMM/opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+#                 'container_type': 'vm',
+#                 'version': '',
+#                 'hypervisor_type': 'kvm'
+#             },
+#             'image_file_id': u'opencos_sss_omm_img_release_20150723-1-disk1'
+#         },
+#         {
+#             'description': '',
+#             'properties': {
+#                 'name': u'sss.vmdk',
+#                 'checksum': '',
+#                 'disk_format': u'VMDK',
+#                 'file_url': u'./zte-cn-sss-main-image/NE/sss.vmdk',
+#                 'container_type': 'vm',
+#                 'version': '',
+#                 'hypervisor_type': 'kvm'
+#             },
+#             'image_file_id': u'sss'
+#         }
+#     ],
+#     'vls': [
+#
+#     ],
+#     'cps': [
+#         {'cp_id': 'cpd_2',
+#          "description": "",
+#          "properties": {
+#              "mac_address": "00:d9:00:82:11:e2",
+#              "ip_address": "10.43.25.3",
+#              "ip_range_start": "192.168.1.20",
+#              "ip_range_end": "192.168.1.29",
+#              "sfc_encapsulation": ""
+#          }
+#          },
+#     ],
+#     'metadata': {
+#         'vendor': u'zte',
+#         'is_shared': False,
+#         'description': '',
+#         'domain_type': u'CN',
+#         'version': u'v4.14.10',
+#         'vmnumber_overquota_alarm': False,
+#         'cross_dc': False,
+#         'vnf_type': u'SSS',
+#         'vnfd_version': u'V00000001',
+#         'id': u'sss-vnf-template',
+#         'name': u'vnfd_2'
+#     },
+#     'vnf_exposed': {
+#         "external_cps": [
+#             {
+#                 "key_name": "virtualLink1",
+#                 "cp_id": "cp1",
+#             },
+#         ],
+#         "forward_cps": [
+#             {
+#                 "key_name": "forwarder2",
+#                 "cp_id": "cpd_2",
+#             },
+#             {
+#                 "key_name": "forwarder3",
+#                 "cp_id": "cpd_2",
+#             },
+#         ],
+#     }
+# }
+#
+# nsd_model = {
+#     "metadata": {
+#         "id": "nsd_demo",
+#         "vendor": "zte",
+#         "version": "1.1.0",
+#         "name": "testNSD",
+#         "description": "demo nsd",
+#     },
+#
+#     "inputs": {
+#         "param1": "11",
+#         "param2": "22",
+#     },
+#
+#     "vnfs": [
+#         {
+#             "type": "tosca.nodes.nfv.ext.VNF.FireWall",
+#             "vnf_id": "vnf_1",
+#             "description": "",
+#             "properties": {
+#                 "id": "vnfd_1",
+#                 "vendor": "zte",
+#                 "version": "1.2.0",
+#                 "vnfd_version": "1.1.0",
+#                 "vnf_type": "vnf1",
+#                 "domain_type": "CN",
+#                 "name": "vnf1",
+#                 "is_shared": False,
+#                 "cross_dc": False,
+#                 "request_reclassification": False,
+#                 "nsh_aware": False,
+#                 "custom_properties": {
+#                     "key1": "value1",
+#                     "keyN": "valueN",
+#                 },
+#             },
+#             "dependencies": [
+#                 "vnf_id1", "vnf_id2"
+#             ],
+#             "networks": [
+#                 {
+#                     "key_name": "virtualLink1",
+#                     "vl_id": "vl_id1",
+#                 },
+#             ],
+#         },
+#         {
+#             "type": "tosca.nodes.nfv.ext.VNF.FireWall",
+#             "vnf_id": "vnf_2",
+#             "description": "",
+#             "properties": {
+#                 "id": "vnfd_2",
+#                 "vendor": "zte",
+#                 "version": "1.2.0",
+#                 "vnfd_version": "1.1.0",
+#                 "vnf_type": "vnf2",
+#                 "domain_type": "CN",
+#                 "name": "vnf1",
+#                 "is_shared": False,
+#                 "cross_dc": False,
+#                 "request_reclassification": False,
+#                 "nsh_aware": False,
+#                 "custom_properties": {
+#                     "key1": "value1",
+#                     "keyN": "valueN",
+#                 },
+#             },
+#             "dependencies": [
+#                 "vnf_id1", "vnf_id2"
+#             ],
+#             "networks": [
+#                 {
+#                     "key_name": "virtualLink1",
+#                     "vl_id": "vl_id1",
+#                 },
+#             ],
+#         }
+#     ],
+#
+#     "pnfs": [
+#         {
+#             "pnf_id": "pnf1",
+#             "description": "",
+#             "properties": {
+#                 "id": "pnf1",
+#                 "vendor": "zte",
+#                 "version": "1.1.0",
+#                 "pnf_type": "TTGW",
+#                 "request_reclassification": False,
+#                 "nsh_aware": False,
+#             },
+#             "cps": [
+#                 "cpd_1", "cpd_22",
+#             ]
+#         }
+#     ],
+#
+#     "nested_ns": [
+#         {
+#             "ns_id": "ns2",
+#             "description": "",
+#             "properties": {
+#                 "id": "ns2_demo",
+#                 "vendor": "zte",
+#                 "version": "1.1.0",
+#                 "name": "NSD2",
+#             },
+#             "networks": [
+#                 {
+#                     "key_name": "virtualLink1",
+#                     "vl_id": "vl_id1",
+#                 },
+#             ],
+#         }
+#     ],
+#
+#     "vls": [
+#         {
+#             "vl_id": "vldId1",
+#             "description": "",
+#             "properties": {
+#                 "name": "umac_241_control",
+#                 "network_id": "fgdhsj434hfjdfd",
+#                 "network_name": "umac_control",
+#                 "vendor": "zte",
+#                 "mtu": 1500,
+#                 "network_type": "vlan",
+#                 "physical_network": "phynet01",
+#                 "segmentation_id": "30",
+#                 "vlan_transparent": False,
+#                 "vds_name": "vds1",
+#                 "cidr": "192.168.199.0/24",
+#                 "ip_version": 4,
+#                 "gateway_ip": "192.168.199.1",
+#                 "dhcp_enabled": False,
+#                 "dns_nameservers": ["192.168.0.4", "192.168.0.10"],
+#                 "start_ip": "192.168.199.2",
+#                 "end_ip": "192.168.199.254",
+#                 "host_routes": [
+#                     {
+#                         "destination": "10.43.26.0/24",
+#                         "nexthop": "10.41.23.1",
+#                     },
+#                 ],
+#                 "location_info": {
+#                     "vimId": "vimid",
+#                     "tenant": "tenantname",
+#                 },
+#                 "vlan_transparent": False,
+#             },
+#         },
+#     ],
+#
+#     "cps": [
+#         {
+#             "cp_id": "cpd_1",
+#             "description": "",
+#             "properties": {
+#                 "mac_address": "00:d9:00:82:11:e1",
+#                 "ip_address": "192.168.1.21",
+#                 "ip_range_start": "192.168.1.20",
+#                 "ip_range_end": "192.168.1.29",
+#                 "floating_ip_address": {
+#                     "external_network": "extnet01",
+#                     "ip_address": "10.43.53.23",
+#                 },
+#                 "service_ip_address": "192.168.1.23",
+#                 "order": 1,
+#                 "bandwidth": 1000,
+#                 "vnic_type": "normal",
+#                 "allowed_address_pairs": [
+#                     {
+#                         "ip": "192.168.1.13",
+#                         "mac": "00:f3:43:20:a2:a3"
+#                     },
+#                 ],
+#                 "bond": "none",
+#                 "macbond": "00:d9:00:82:11:d1",
+#                 "sfc_encapsulation": "",
+#                 "direction": "",
+#             },
+#             "vl_id": "vlid1",
+#             "pnf_id": "pnf1",
+#         },
+#
+#         {
+#             "cp_id": "forwarder_brasDP_dcPort",
+#             "description": "",
+#             "properties": {
+#                 "mac_address": "00:d9:00:82:14:e1",
+#                 "ip_address": "192.168.1.24",
+#                 "ip_range_start": "192.168.1.20",
+#                 "ip_range_end": "192.168.1.29",
+#                 "floating_ip_address": {
+#                     "external_network": "extnet01",
+#                     "ip_address": "10.43.53.23",
+#                 },
+#                 "service_ip_address": "192.168.1.23",
+#                 "order": 1,
+#                 "bandwidth": 1000,
+#                 "vnic_type": "normal",
+#                 "allowed_address_pairs": [
+#                     {
+#                         "ip": "192.168.1.13",
+#                         "mac": "00:f3:43:20:a2:a3"
+#                     },
+#                 ],
+#                 "bond": "none",
+#                 "macbond": "00:d9:00:82:11:d1",
+#                 "sfc_encapsulation": "",
+#                 "direction": "",
+#             },
+#             "vl_id": "vlid1",
+#             "pnf_id": "pnf1",
+#         },
+#         {
+#             "cp_id": "forwarder_brasDP_internetPort",
+#             "description": "",
+#             "properties": {
+#                 "mac_address": "00:d9:00:82:15:e1",
+#                 "ip_address": "192.168.1.25",
+#                 "ip_range_start": "192.168.1.20",
+#                 "ip_range_end": "192.168.1.29",
+#                 "floating_ip_address": {
+#                     "external_network": "extnet01",
+#                     "ip_address": "10.43.53.23",
+#                 },
+#                 "service_ip_address": "192.168.1.23",
+#                 "order": 1,
+#                 "bandwidth": 1000,
+#                 "vnic_type": "normal",
+#                 "allowed_address_pairs": [
+#                     {
+#                         "ip": "192.168.1.13",
+#                         "mac": "00:f3:43:20:a2:a3"
+#                     },
+#                 ],
+#                 "bond": "none",
+#                 "macbond": "00:d9:00:82:11:d1",
+#                 "sfc_encapsulation": "",
+#                 "direction": "",
+#             },
+#             "vl_id": "vlid1",
+#             "pnf_id": "pnf1",
+#         },
+#
+#     ],
+#
+#     "fps": [
+#         {
+#             "fp_id": "fpd_1",
+#             "description": "",
+#             "properties": {
+#                 "policy": {
+#                     "type": "ACL",
+#                     "criteria": {
+#                         "dest_port_range": [80, 1024],
+#                         "source_port_range": [80, 1024],
+#                         "ip_protocol": "tcp",
+#                         "dest_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                         "source_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                         "dscp": 100,
+#                     },
+#                 },
+#                 "symmetric": True,
+#             },
+#             "forwarder_list": [
+#                 {
+#                     "type": "cp",
+#                     "node_name": "cpd_1",
+#                     "capability": "",
+#                 },
+#                 {
+#                     "type": "cp",
+#                     "node_name": "forwarder_brasDP_dcPort",
+#                     "capability": "",
+#                 },
+#                 {
+#                     "type": "vnf",
+#                     "node_name": "vnf_1",
+#                     "capability": "forwarder1",
+#                 },
+#                 {
+#                     "type": "vnf",
+#                     "node_name": "vnf_2",
+#                     "capability": "forwarder2",
+#                 },
+#                 {
+#                     "type": "cp",
+#                     "node_name": "forwarder_brasDP_dcPort",
+#                     "capability": "",
+#                 },
+#                 {
+#                     "type": "cp",
+#                     "node_name": "forwarder_brasDP_internetPort",
+#                     "capability": "",
+#                 },
+#             ],
+#         },
+#
+#         {
+#             "fp_id": "fpd_2",
+#             "description": "",
+#             "properties": {
+#                 "policy": {
+#                     "type": "ACL",
+#                     "criteria": {
+#                         "dest_port_range": [80, 1024],
+#                         "source_port_range": [80, 1024],
+#                         "ip_protocol": "tcp",
+#                         "dest_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                         "source_ip_range": ["192.168.1.2", "192.168.1.100"],
+#                         "dscp": 100,
+#                     },
+#                 },
+#                 "symmetric": True,
+#             },
+#             "forwarder_list": [
+#
+#                 {
+#                     "type": "cp",
+#                     "node_name": "forwarder_brasDP_internetPort",
+#                     "capability": "",
+#                 },
+#                 {
+#                     "type": "cp",
+#                     "node_name": "forwarder_brasDP_dcPort",
+#                     "capability": "",
+#                 },
+#                 {
+#                     "type": "vnf",
+#                     "node_name": "vnf_2",
+#                     "capability": "forwarder2",
+#                 },
+#
+#             ],
+#         },
+#     ],
+#
+#     "vnffgs": [
+#         {
+#             "vnffg_id": "vnffg_id1",
+#             "description": "",
+#             "properties": {
+#                 "vendor": "zte",
+#                 "version": "1.1.2",
+#                 "number_of_endpoints": 7,
+#                 "dependent_virtual_link": ["vldId1"],
+#                 "connection_point": ["CP01", "CP02"],
+#                 "constituent_vnfs": ["vnf_id1", "vnf_id2"],
+#                 "constituent_pnfs": ["pnf1", "pnf2"],
+#             },
+#             "members": ["fpd_1", "fpd_2"],
+#         }
+#     ],
+#
+#     "server_groups": [
+#         {
+#             "group_id": "",
+#             "description": "",
+#             "properties": {
+#                 "name": "server_group1",
+#                 "affinity_antiaffinity": "anti-affinity",
+#                 "scope": "host",
+#             },
+#             "members": ["vnf1", "vnf2"],
+#         },
+#     ],
+#
+#     "ns_exposed": {
+#         "external_cps": [
+#             {
+#                 "key_name": "virtualLink1",
+#                 "cp_id": "cp1",
+#             },
+#         ],
+#         "forward_cps": [
+#             {
+#                 "key_name": "forwarder_brasDP_userPort",
+#                 "cp_id": "cpd_1",
+#             },
+#             {
+#                 "key_name": "forwarder_brasDP_internetPort",
+#                 "cp_id": "cpd_4",
+#             },
+#             {
+#                 "key_name": "forwarder_brasDP_dcPort",
+#                 "cp_id": "cpd_5",
+#             },
+#
+#         ],
+#     },
+#
+#     "policies": [
+#         {
+#             "scaling": [
+#                 {
+#                     "policy_id": "id1",
+#                     "description": "",
+#                     "properties": {
+#                         "policy_file": "Policies/ns1-policy.xml",
+#                     },
+#                     "targets": ['pfu_vm'],
+#                 },
+#             ],
+#         },
+#     ],
+#
+#     "ns_flavours": [
+#         {
+#             "flavour_id": "flavour1",
+#             "description": "",
+#             "vnf_profiles": [
+#                 {
+#                     "vnf_id": "vnf1",
+#                     "flavour_id": "flavour1",
+#                     "instances_minimum_number": 1,
+#                     "instances_maximum_number": 4,
+#                     "local_affinity_antiaffinity_rule": [
+#                         {
+#                             "affinity_antiaffinity": "affinity",
+#                             "scope": "node",
+#                         }
+#                     ]
+#                 },
+#             ],
+#             "pnf_profiles": [
+#                 {
+#                     "pnf_id": "pnf1",
+#                 },
+#             ],
+#             "vl_profiles": [
+#                 {
+#                     "vl_id": "vlid1",
+#                     "bitrate_requirements": {
+#                         "root": 1000,
+#                         "leaf": 100
+#                     },
+#                     "qos": {
+#                         "maximum_latency": "1 ms",
+#                         "maximum_jitter": "10 ms",
+#                         "maximum_packet_loss_ratio": 0.5
+#                     },
+#                 }
+#             ],
+#             "instantiation_levels": [
+#                 {
+#                     "id": "instLevel1",
+#                     "description": "",
+#                     "vnf_levels": [
+#                         {
+#                             "vnf_id": "",
+#                             "vnf_instantiation_level": "small",
+#                             "instances_number": 1
+#                         },
+#                     ],
+#                     "scale_level_id": "scaleLevel1",
+#                 }
+#             ],
+#             "default_instantiation_level": "instLevel1",
+#             "scale_levels": [
+#                 {
+#                     "id": "scaleLevel1",
+#                     "order": 1,
+#                     "vnf_levels": [
+#                         {
+#                             "vnf_id": "",
+#                             "vnf_instantiation_level": "small",
+#                             "instances_number": 1
+#                         },
+#                     ],
+#                 },
+#             ],
+#             "supported_operations": ["Scale", "Heal"],
+#             "affinity_antiaffinity_groups": [
+#                 {
+#                     "group_id": "group1Id",
+#                     "name": "groupName",
+#                     "affinity_antiaffinity": "affinity",
+#                     "scope": "node",
+#                     "members": [
+#                         "vnfId1", "vnfIdN",
+#                     ],
+#                 },
+#             ],
+#         },
+#     ],
+# }
diff --git a/lcm/ns/tests/sfcs/test_sfc_instance.py b/lcm/ns/tests/sfcs/test_sfc_instance.py
new file mode 100644 (file)
index 0000000..f0f9064
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright 2016 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
+# from rest_framework import status
+# from test_data import nsd_model
+# from django.test import Client
+# from django.test import TestCase
+# from lcm.pub.database.models import FPInstModel, VNFFGInstModel
+#
+#
+# class TestSfc(TestCase):
+#     def setUp(self):
+#         self.client = Client()
+#         VNFFGInstModel.objects.all().delete()
+#         FPInstModel.objects.all().delete()
+#         VNFFGInstModel(vnffgdid="vnffg_id1", vnffginstid="vnffg_inst_1", nsinstid="ns_inst_1", endpointnumber=2,
+#                        vllist="vlinst1", cplist="cp1", vnflist="vnf1,vnf2").save()
+#
+#     def tearDown(self):
+#         VNFFGInstModel.objects.all().delete()
+#         FPInstModel.objects.all().delete()
+#
+#     def test_sfc_instance_success(self):
+#         data = {
+#             "nsinstanceid": "ns_inst_1",
+#             "context": json.dumps(nsd_model),
+#             "fpindex": "fpd_1",
+#             "sdncontrollerid": "sdnControllerId_1"
+#         }
+#         resp = self.client.post("/openoapi/nslcm/v1/ns/sfc_instance", data, format='json')
+#
+#         vnffg = VNFFGInstModel.objects.get(vnffginstid="vnffg_inst_1")
+#         ret = FPInstModel.objects.get(fpinstid=resp.data["fpinstid"])
+#         self.assertEqual(resp.status_code, status.HTTP_200_OK)
+#         self.assertEqual(vnffg.fplist, resp.data["fpinstid"])
+#         self.assertIsNotNone(ret)
diff --git a/lcm/ns/tests/sfcs/test_sfcdetailview.py b/lcm/ns/tests/sfcs/test_sfcdetailview.py
new file mode 100644 (file)
index 0000000..d82f224
--- /dev/null
@@ -0,0 +1,86 @@
+# Copyright 2016 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 uuid
+from lcm.pub.msapi import extsys
+import mock
+from django.test import TestCase, Client
+from rest_framework import status
+from lcm.pub.msapi import sdncdriver
+from lcm.pub.database.models import FPInstModel, VNFFGInstModel, NfInstModel
+from lcm.pub.utils import restcall
+from lcm.pub.msapi import resmgr
+class TestSfcDetailViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.ns_inst_id = str(uuid.uuid4())
+        self.sfc_inst_id = str(uuid.uuid4())
+        self.status = "active"
+        self.sdn_controler_id = str(uuid.uuid4())
+        sfc_id = str(uuid.uuid4())
+        flow_classifiers = "flow1,flow2"
+        port_pair_groups = json.JSONEncoder().encode(
+            [{"groupid": "group1", "portpair": [str(uuid.uuid4()), str(uuid.uuid4())]},
+             {"groupid": "group2", "portpair": [str(uuid.uuid4()), str(uuid.uuid4())]}])
+
+
+    def tearDown(self):
+        pass
+    
+    
+    def test_sfc_delete_failed(self):
+        response = self.client.delete("/openoapi/nslcm/v1/ns/sfcs/%s" % "notExist")
+        expect_resp_data = {"result": 0, "detail": "sfc is not exist or has been already deleted"}
+        self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code)
+        self.assertEqual(expect_resp_data, response.data)
+
+    @mock.patch.object(extsys, "get_sdn_controller_by_id")
+    @mock.patch.object(sdncdriver, "delete_port_chain")
+    @mock.patch.object(sdncdriver, "delete_flow_classifier")
+    @mock.patch.object(sdncdriver, "delete_port_pair_group")
+    @mock.patch.object(sdncdriver, "delete_port_pair")
+    @mock.patch.object(resmgr, "delete_sfc")
+    def test_sfc_delete_success(self, mock_delete_sfc, mock_delete_port_pair, mock_delete_port_pair_group, mock_delete_flow_classifier, mock_delete_port_chain, mock_get_sdn_controller_by_id):
+        mock_delete_port_chain.return_value=None
+        mock_delete_flow_classifier.return_value=None
+        mock_delete_port_pair_group.return_value=None
+        mock_delete_port_pair.return_value=None
+        mock_delete_sfc.return_value=None
+        mock_get_sdn_controller_by_id.return_value = json.loads('{"test":"test_name","url":"url_add"}')
+        sfc_inst_id = "10"
+
+        FPInstModel(fpid="1", fpinstid="10", fpname="2", nsinstid="3", vnffginstid="4",
+                    symmetric="5", policyinfo="6", forworderpaths="7", status="8", sdncontrollerid="9",
+                    sfcid="10", flowclassifiers="11",
+                    portpairgroups=json.JSONEncoder().encode([{"groupid":"98","portpair":"99"}])
+                    ).save()
+        response = self.client.delete("/openoapi/nslcm/v1/ns/sfcs/%s" % sfc_inst_id)
+        expect_resp_data = {"result": 0, "detail": "delete sfc success"}
+        self.assertEqual(expect_resp_data, response.data)
+
+    def test_sfc_get_failed(self):
+        sfc_inst_id="10"
+        response = self.client.get("/openoapi/nslcm/v1/ns/sfcs/%s" % sfc_inst_id)
+        self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code)
+
+    def test_sfc_get_success(self):
+        sfc_inst_id ="10"
+        FPInstModel(fpid="1", fpinstid="10", fpname="2", nsinstid="3", vnffginstid="4",
+                    symmetric="5", policyinfo="6", forworderpaths="7", status="8", sdncontrollerid="9",
+                    sfcid="10", flowclassifiers="11",
+                    portpairgroups="12").save()
+        response = self.client.get("/openoapi/nslcm/v1/ns/sfcs/%s" % sfc_inst_id)
+        expect_resp_data={'sfcName': 'xxx', 'sfcInstId': '10', 'sfcStatus': '8'}
+        self.assertEqual(expect_resp_data, response.data)
+
diff --git a/lcm/ns/tests/sfcs/tests.py b/lcm/ns/tests/sfcs/tests.py
new file mode 100644 (file)
index 0000000..f93bc4c
--- /dev/null
@@ -0,0 +1,77 @@
+# Copyright 2016 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 uuid
+
+import mock
+from django.test import TestCase, Client
+from rest_framework import status
+
+from lcm.pub.database.models import FPInstModel, VNFFGInstModel
+from lcm.pub.utils import restcall
+
+
+class TestSfcDetailViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.ns_inst_id = str(uuid.uuid4())
+        self.sfc_inst_id = str(uuid.uuid4())
+        self.status = "active"
+        self.sdn_controler_id = str(uuid.uuid4())
+        sfc_id = str(uuid.uuid4())
+        flow_classifiers = "flow1,flow2"
+        port_pair_groups = json.JSONEncoder().encode(
+            [{"groupid": "group1", "portpair": [str(uuid.uuid4()), str(uuid.uuid4())]},
+             {"groupid": "group2", "portpair": [str(uuid.uuid4()), str(uuid.uuid4())]}])
+        FPInstModel(fpid="", fpinstid=self.sfc_inst_id, nsinstid=self.ns_inst_id, vnffginstid="", policyinfo="",
+                    status=self.status, sdncontrollerid=self.sdn_controler_id, sfcid=sfc_id,
+                    flowclassifiers=flow_classifiers,
+                    portpairgroups=port_pair_groups).save()
+        VNFFGInstModel(vnffgdid="", vnffginstid="", nsinstid=self.ns_inst_id,
+                       fplist="test1," + self.sfc_inst_id + ",test2,test3", endpointnumber=0, cplist="", vnflist="",
+                       vllist="", status="").save()
+
+    def tearDown(self):
+        FPInstModel.objects.all().delete()
+        VNFFGInstModel.objects.all().delete()
+
+    @mock.patch.object(restcall, "call_req")
+    def test_delete_sfc(self, mock_req_by_rest):
+        mock_req_by_rest.return_value = [0, '{"test":"test_name","url":"url_add"}']
+        response = self.client.delete("/openoapi/nslcm/v1/ns/sfcs/%s" % self.sfc_inst_id)
+        self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code)
+        expect_resp_data = {"result": 0, "detail": "delete sfc success"}
+        self.assertEqual(expect_resp_data, response.data)
+
+        for vnffg_info in VNFFGInstModel.objects.filter(nsinstid=self.ns_inst_id):
+            self.assertEqual(vnffg_info.fplist, "test1,test2,test3")
+        if FPInstModel.objects.filter(fpinstid=self.sfc_inst_id):
+            self.fail()
+
+        response = self.client.delete("/openoapi/nslcm/v1/ns/sfcs/%s" % "notExist")
+        self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code)
+        expect_resp_data = {"result": 0, "detail": "sfc is not exist or has been already deleted"}
+        self.assertEqual(expect_resp_data, response.data)
+
+    def test_query_sfc(self):
+        response = self.client.get("/openoapi/nslcm/v1/ns/sfcs/%s" % self.sfc_inst_id)
+        self.assertEqual(status.HTTP_200_OK, response.status_code)
+        expect_resp_data = {'sfcInstId': self.sfc_inst_id,
+                            'sfcStatus': self.status,
+                            'sfcName': "xxx"}
+        self.assertEqual(expect_resp_data, response.data)
+
+        response = self.client.get("/openoapi/nslcm/v1/ns/sfcs/%s" % "notExist")
+        self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code)
diff --git a/lcm/ns/tests/test_ns_create.py b/lcm/ns/tests/test_ns_create.py
new file mode 100644 (file)
index 0000000..1182184
--- /dev/null
@@ -0,0 +1,39 @@
+# Copyright 2016 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.pub.database.models import NSInstModel, NSDModel
+
+
+class TestNsInstantiate(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.nsd_id = str(uuid.uuid4())
+        self.ns_package_id = str(uuid.uuid4())
+        NSDModel(id=self.ns_package_id, nsd_id=self.nsd_id, name='name').save()
+
+    def tearDown(self):
+        NSDModel.objects.all().delete()
+        NSInstModel.objects.all().delete()
+
+    def test_create_ns(self):
+        data = {
+            'nsdid': self.nsd_id,
+            'nsname': 'ns',
+            'description': 'description'}
+        response = self.client.post("/openoapi/nslcm/v1/ns", data=data)
+        self.failUnlessEqual(status.HTTP_201_CREATED, response.status_code)
diff --git a/lcm/ns/tests/test_ns_instant.py b/lcm/ns/tests/test_ns_instant.py
new file mode 100644 (file)
index 0000000..ed20c05
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright 2016 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 mock
+from rest_framework import status
+from django.test import TestCase
+from django.test import Client
+
+from lcm.pub.database.models import NSInstModel
+from lcm.pub.utils import restcall
+from lcm.pub.utils import toscautil
+
+
+class TestNsInstant(TestCase):
+    def setUp(self):
+        self.client = Client()
+        NSInstModel.objects.filter().delete()
+        self.context = '{"vnfs": ["a", "b"], "sfcs": ["c"], "vls": ["d", "e", "f"]}'
+        NSInstModel(id="123", nspackage_id="7", nsd_id="2").save()
+
+    def tearDown(self):
+        pass
+
+    """
+    @mock.patch.object(restcall, 'call_req')
+    @mock.patch.object(toscautil, 'convert_nsd_model')
+    def test_ns_instant_ok(self, mock_convert_nsd_model, mock_call_req):
+        mock_convert_nsd_model.return_value = self.context
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/7/files?relativePath=abc.yaml":
+                [0, '{"downloadUri":"http://test.yaml", "localPath":"./test.yaml"}', '200'],
+            "/openoapi/tosca/v1/indirect/plan":
+                [0, '{"description":"", "metadata":{}, "nodes":[]}', '200'],
+            "/openoapi/catalog/v1/servicetemplates/2/operations":
+                [0, '[{"name":"LCM", "processId":"{http://www.open-o.org/tosca/nfv/2015/12}init-16"}]', '200'],
+            "/openoapi/wso2bpel/v1/process/instance":
+                [0, '{"status": 1}', '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+
+        mock_call_req.side_effect = side_effect
+
+        data = {'iaUrl': "", 'vnfmId': "", 'context': "{\"e\":{\"f\":\"4\"}}", 'statusUrl': "",
+                'serviceTemplateId': "", 'roUrl': "", 'containerapiUrl': "", 'flavor': "",
+                'nsInstanceId': "123", 'instanceId': "234", 'resourceUrl': "", 'callbackId': "",
+                'additionalParamForVnf': "[{\"b\":1},{\"c\":{\"d\":\"2\"}}]",
+                'additionalParamForNs': "[{\"a\":3},{\"e\":{\"f\":\"4\"}}]", 'flavorParams': ""}
+        resp = self.client.post("/openoapi/nslcm/v1/ns/123/instantiate", data, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+    """
+    
+    def test_swagger_ok(self):
+        resp = self.client.get("/openoapi/nslcm/v1/swagger.json", format='json')
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
diff --git a/lcm/ns/tests/test_ns_manual_scale.py b/lcm/ns/tests/test_ns_manual_scale.py
new file mode 100644 (file)
index 0000000..cd7ccc0
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright 2017 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 mock
+import uuid
+from rest_framework import status
+from django.test import TestCase
+from django.test import Client
+from lcm.pub.database.models import NSDModel, NSInstModel
+from lcm.pub.utils.jobutil import JobUtil, JOB_MODEL_STATUS, JOB_TYPE
+from lcm.ns.const import NS_INST_STATUS
+from lcm.pub.utils import restcall
+from lcm.pub.utils import toscautil
+from lcm.ns.ns_manual_scale import NSManualScaleService
+
+class TestNsManualScale(TestCase):
+    def setUp(self):
+        self.nsd_id = str(uuid.uuid4())
+        self.ns_package_id = str(uuid.uuid4())
+        self.ns_inst_id = str(uuid.uuid4())
+        self.job_id = JobUtil.create_job("NS", JOB_TYPE.MANUAL_SCALE_VNF, self.ns_inst_id)
+        NSDModel(id=self.ns_package_id, nsd_id=self.nsd_id, name='name').save()
+
+        self.client = Client()
+        self.context = '{"vnfs": ["a", "b"], "sfcs": ["c"], "vls": ["d", "e", "f"]}'
+        NSInstModel(id=self.ns_inst_id, name="abc",nspackage_id="7", nsd_id="111").save()
+
+    def tearDown(self):
+        NSInstModel.objects.filter().delete()
+
+
+    """
+    @mock.patch.object(restcall, 'call_req')
+    @mock.patch.object(toscautil, 'convert_nsd_model')
+    def test_ns_instant_ok(self, mock_convert_nsd_model, mock_call_req):
+        mock_convert_nsd_model.return_value = self.context
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/7/files?relativePath=abc.yaml":
+                [0, '{"downloadUri":"http://test.yaml", "localPath":"./test.yaml"}', '200'],
+            "/openoapi/tosca/v1/indirect/plan":
+                [0, '{"description":"", "metadata":{}, "nodes":[]}', '200'],
+            "/openoapi/catalog/v1/servicetemplates/2/operations":
+                [0, '[{"name":"LCM", "processId":"{http://www.open-o.org/tosca/nfv/2015/12}init-16"}]', '200'],
+            "/openoapi/wso2bpel/v1/process/instance":
+                [0, '{"status": 1}', '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+
+        mock_call_req.side_effect = side_effect
+
+        data = {'iaUrl': "", 'vnfmId': "", 'context': "{\"e\":{\"f\":\"4\"}}", 'statusUrl': "",
+                'serviceTemplateId': "", 'roUrl': "", 'containerapiUrl': "", 'flavor': "",
+                'nsInstanceId': "123", 'instanceId': "234", 'resourceUrl': "", 'callbackId': "",
+                'additionalParamForVnf': "[{\"b\":1},{\"c\":{\"d\":\"2\"}}]",
+                'additionalParamForNs': "[{\"a\":3},{\"e\":{\"f\":\"4\"}}]", 'flavorParams': ""}
+        resp = self.client.post("/openoapi/nslcm/v1/ns/123/instantiate", data, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+    """
+    @mock.patch.object(NSManualScaleService, 'run')
+    def test_ns_manual_scale(self, mock_run):
+        data = {
+            'nsdid': self.nsd_id,
+            'nsname': 'ns',
+            'description': 'description'}
+        response = self.client.post("/openoapi/nslcm/v1/ns/%s/scale"%self.nsd_id, data=data)
+        self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_ns_manual_scale_thread(self, mock_call):
+
+        data = {
+            'nsdid': self.nsd_id,
+            'nsname': 'ns',
+            'description': 'description'}
+        NSManualScaleService(self.ns_inst_id, data, self.job_id).run()
+        self.assertTrue(NSInstModel.objects.get(id=self.ns_inst_id).status, NS_INST_STATUS.ACTIVE)
+
+    def test_swagger_ok(self):
+        resp = self.client.get("/openoapi/nslcm/v1/swagger.json", format='json')
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
diff --git a/lcm/ns/tests/tests_ns_terminate.py b/lcm/ns/tests/tests_ns_terminate.py
new file mode 100644 (file)
index 0000000..2ea1fa4
--- /dev/null
@@ -0,0 +1,98 @@
+# Copyright 2016-2017 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 uuid
+
+import mock
+from django.test import TestCase, Client
+from rest_framework import status
+
+from lcm.pub.database.models import NfInstModel, NSInstModel
+from lcm.pub.utils import restcall
+from lcm.pub.utils.jobutil import JOB_MODEL_STATUS
+from lcm.ns.ns_terminate import TerminateNsService
+from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE
+
+
+class TestTerminateNsViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.ns_inst_id = '1'
+        self.nf_inst_id = '1'
+        self.vnffg_id = str(uuid.uuid4())
+        self.vim_id = str(uuid.uuid4())
+        self.job_id = str(uuid.uuid4())
+        self.nf_uuid = '1-1-1'
+        self.tenant = "tenantname"
+        model = '{"metadata": {"vnfdId": "1","vnfdName": "PGW001","vnfProvider": "zte","vnfdVersion": "V00001",' \
+                '"vnfVersion": "V5.10.20","productType": "CN","vnfType": "PGW",' \
+                '"description": "PGW VNFD description","isShared":true,"vnfExtendType":"driver"}}'
+        NSInstModel(id=self.ns_inst_id, name="ns_name", status='null').save()
+        NfInstModel.objects.create(nfinstid=self.nf_inst_id, nf_name='name_1', vnf_id='1',
+                                   vnfm_inst_id='1', ns_inst_id='1-1-1,2-2-2',
+                                   max_cpu='14', max_ram='12296', max_hd='101', max_shd="20", max_net=10,
+                                   status='null', mnfinstid=self.nf_uuid, package_id='pkg1',
+                                   vnfd_model=model)
+
+    def tearDown(self):
+        NSInstModel.objects.all().delete()
+        NfInstModel.objects.all().delete()
+
+    @mock.patch.object(TerminateNsService, 'do_biz')
+    def test_terminate_vnf_url(self, mock_run):
+        req_data = {
+            "terminationType": "forceful",
+            "gracefulTerminationTimeout": "600"}
+        response = self.client.post("/openoapi/nslcm/v1/ns/%s/terminate" % self.ns_inst_id, data=req_data)
+        self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
+
+        response = self.client.delete("/openoapi/nslcm/v1/ns/%s" % self.ns_inst_id)
+        self.failUnlessEqual(status.HTTP_204_NO_CONTENT, response.status_code)
+
+    @mock.patch.object(restcall, "call_req")
+    def test_terminate_vnf(self, mock_call_req):
+        job_id = JobUtil.create_job("VNF", JOB_TYPE.TERMINATE_VNF, self.nf_inst_id)
+
+        mock_vals = {
+            "/openoapi/nslcm/v1/ns/vls/1":
+                [0, json.JSONEncoder().encode({"jobId": self.job_id}), '200'],
+            "/openoapi/nslcm/v1/ns/sfcs/1":
+                [0, json.JSONEncoder().encode({"jobId": self.job_id}), '200'],
+            "/openoapi/nslcm/v1/ns/vnfs/1":
+                [0, json.JSONEncoder().encode({}), '200'],
+            "/openoapi/ztevmanagerdriver/v1/jobs/" + self.job_id + "&responseId=0":
+                [0, json.JSONEncoder().encode({"jobid": self.job_id,
+                                               "responsedescriptor": {"progress": "100",
+                                                                      "status": JOB_MODEL_STATUS.FINISHED,
+                                                                      "responseid": "3",
+                                                                      "statusdescription": "creating",
+                                                                      "errorcode": "0",
+                                                                      "responsehistorylist": [
+                                                                          {"progress": "0",
+                                                                           "status": JOB_MODEL_STATUS.PROCESSING,
+                                                                           "responseid": "2",
+                                                                           "statusdescription": "creating",
+                                                                           "errorcode": "0"}]}}), '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+
+        mock_call_req.side_effect = side_effect
+
+        TerminateNsService(self.nf_inst_id, "forceful", "600", job_id).start()
+        nsinst = NSInstModel.objects.get(id=self.ns_inst_id)
+        if nsinst:
+            self.assertTrue(1, 0)
+        else:
+            self.assertTrue(1, 1)
diff --git a/lcm/ns/tests/vls/__init__.py b/lcm/ns/tests/vls/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/tests/vls/tests.py b/lcm/ns/tests/vls/tests.py
new file mode 100644 (file)
index 0000000..3006298
--- /dev/null
@@ -0,0 +1,159 @@
+# Copyright 2016 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 uuid
+
+import mock
+from django.test import TestCase, Client
+from rest_framework import status
+
+from lcm.pub.database.models import VLInstModel, NSInstModel, VNFFGInstModel
+from lcm.pub.nfvi.vim import vimadaptor
+from lcm.pub.utils import restcall
+
+
+class TestVlViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.ns_inst_id = str(uuid.uuid4())
+        self.vnffg_id = str(uuid.uuid4())
+        self.vl_id_1 = 1
+        self.vl_id_2 = 1
+        self.vim_id = str(uuid.uuid4())
+        self.tenant = "tenantname"
+        properties = {"network_type": "vlan", "name": "externalMNetworkName", "dhcp_enabled": False,
+                      "location_info": {"host": True, "vimid": self.vim_id, "region": True, "tenant": self.tenant},
+                      "end_ip": "190.168.100.100", "gateway_ip": "190.168.100.1", "start_ip": "190.168.100.2",
+                      "cidr": "190.168.100.0/24", "mtu": 1500, "network_name": "sub_mnet", "ip_version": 4}
+        self.context = {
+            "vls": [{"vl_id": self.vl_id_1, "description": "", "properties": properties, "route_external": False},
+                    {"vl_id": self.vl_id_2, "description": "", "properties": properties, "route_external": False}],
+            "vnffgs": [{"vnffg_id": self.vnffg_id, "description": "",
+                        "properties": {"vendor": "zte", "version": "1.1.2", "number_of_endpoints": 7,
+                                       "dependent_virtual_link": [self.vl_id_2, self.vl_id_1],
+                                       "connection_point": ["CP01", "CP02"],
+                                       "constituent_vnfs": ["VNF1", "VNF2", "VNF3"],
+                                       "constituent_pnfs": ["pnf1", "pnf2"]},
+                        "members": ["forwarding_path1", "forwarding_path2"]}]}
+        NSInstModel(id=self.ns_inst_id, name="ns_name").save()
+        VNFFGInstModel(vnffgdid=self.vnffg_id, vnffginstid="", nsinstid=self.ns_inst_id, endpointnumber=0, vllist="",
+                       cplist="", vnflist="", fplist="", status="").save()
+
+    def tearDown(self):
+        VLInstModel.objects.all().delete()
+        NSInstModel.objects.all().delete()
+        VNFFGInstModel.objects.all().delete()
+
+    @mock.patch.object(restcall, "call_req")
+    @mock.patch.object(vimadaptor.VimAdaptor, "create_network")
+    def test_create_vl(self, mock_create_network, mock_req_by_rest):
+        network_id = str(uuid.uuid4())
+        subnetwork_id = str(uuid.uuid4())
+        mock_create_network.return_value = [0,
+                                            {"status": "ACTIVE", "id": network_id, "name": "net1",
+                                             "provider:segmentation_id": 204, "provider:network_type": "vlan",
+                                             "res_type": 1,
+                                             "subnet_list": [
+                                                 {"id": subnetwork_id, "name": "subnet1", "res_type": 1}]}]
+        mock_req_by_rest.return_value = [0,
+                                         '{"test":"test_name","name":"vim_name","type":"type_name","url":"url_add"'
+                                         ',"userName":"user_name","password":"password","tenant":"tenant"}']
+
+        self.create_vl(self.vl_id_1)
+        self.create_vl(self.vl_id_2)
+        vl_from_vl_1 = VLInstModel.objects.filter(vldid=self.vl_id_1, ownerid=self.ns_inst_id)
+        self.assertEqual(network_id, vl_from_vl_1[0].relatednetworkid)
+        self.assertEqual(subnetwork_id, vl_from_vl_1[0].relatedsubnetworkid)
+        #self.assertEqual(self.vim_id, vl_from_vl_1[0].vimid)
+        self.assertEqual(self.tenant, vl_from_vl_1[0].tenant)
+        vl_from_vl_2 = VLInstModel.objects.filter(vldid=self.vl_id_2, ownerid=self.ns_inst_id)
+        self.assertEqual(VNFFGInstModel.objects.filter(vnffgdid=self.vnffg_id, nsinstid=self.ns_inst_id)[0].vllist,
+                         vl_from_vl_2[0].vlinstanceid + "," + vl_from_vl_1[0].vlinstanceid)
+
+    def create_vl(self, vl_id):
+        req_data = {
+            "nsInstanceId": self.ns_inst_id,
+            "context": json.JSONEncoder().encode(self.context),
+            "vlindex": vl_id}
+        response = self.client.post("/openoapi/nslcm/v1/ns/vls", data=req_data)
+        self.assertEqual(status.HTTP_201_CREATED, response.status_code)
+        self.assertEqual(0, response.data["result"])
+
+    @mock.patch.object(restcall, "call_req")
+    @mock.patch.object(vimadaptor.VimAdaptor, "create_network")
+    @mock.patch.object(uuid, "uuid4")
+    def test_create_network_fail_when_send_to_vim(self, mock_uuid4, mock_create_network, mock_req_by_rest):
+        req_data = {
+            "nsInstanceId": self.ns_inst_id,
+            "context": json.JSONEncoder().encode(self.context),
+            "vlindex": self.vl_id_1}
+        mock_uuid4.return_value = '999'
+        mock_req_by_rest.return_value = [0,
+                                         '{"test":"test_name","name":"vim_name","type":"type_name","url":"url_add"'
+                                         ',"userName":"user_name","password":"password","tenant":"tenant"}']
+        mock_create_network.return_value = [1, (1)]
+        response = self.client.post("/openoapi/nslcm/v1/ns/vls", data=req_data)
+        retinfo = {"detail": "vl instantiation failed, detail message: Send post vl request to vim failed."}
+        self.assertEqual(retinfo["detail"], response.data["detail"])
+
+
+class TestVlDetailViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.vl_inst_id = str(uuid.uuid4())
+        self.vl_name = str(uuid.uuid4())
+        self.ns_inst_id = str(uuid.uuid4())
+        VLInstModel(vlinstanceid=self.vl_inst_id, vldid="", vlinstancename=self.vl_name, ownertype=1,
+                    ownerid=self.ns_inst_id, relatednetworkid="network1", relatedsubnetworkid="subnet1,subnet2",
+                    vimid="",
+                    tenant="").save()
+        VNFFGInstModel(vnffgdid="", vnffginstid="", nsinstid=self.ns_inst_id,
+                       vllist="test1," + self.vl_inst_id + ",test2,test3", endpointnumber=0, cplist="", vnflist="",
+                       fplist="", status="").save()
+
+    def tearDown(self):
+        VLInstModel.objects.all().delete()
+        VNFFGInstModel.objects.all().delete()
+
+    @mock.patch.object(restcall, "call_req")
+    @mock.patch.object(vimadaptor.VimAdaptor, "delete_network")
+    @mock.patch.object(vimadaptor.VimAdaptor, "delete_subnet")
+    def test_delete_vl(self, mock_delete_subnet, mock_delete_network, mock_req_by_rest):
+        mock_req_by_rest.return_value = [0,
+                                         '{"test":"test_name","name":"vim_name","type":"type_name","url":"url_add"'
+                                         ',"userName":"user_name","password":"password","tenant":"tenant"}']
+        response = self.client.delete("/openoapi/nslcm/v1/ns/vls/%s" % self.vl_inst_id)
+        self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code)
+        expect_resp_data = {"result": 0, "detail": "delete vl success"}
+        self.assertEqual(expect_resp_data, response.data)
+
+        for vnffg_info in VNFFGInstModel.objects.filter(nsinstid=self.ns_inst_id):
+            self.assertEqual(vnffg_info.vllist, "test1,test2,test3")
+        if VLInstModel.objects.filter(vlinstanceid=self.vl_inst_id):
+            self.fail()
+
+        response = self.client.delete("/openoapi/nslcm/v1/ns/vls/%s" % "notExist")
+        self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code)
+        expect_resp_data = {"result": 0, "detail": "vl is not exist or has been already deleted"}
+        self.assertEqual(expect_resp_data, response.data)
+
+    def test_query_vl(self):
+        response = self.client.get("/openoapi/nslcm/v1/ns/vls/%s" % self.vl_inst_id)
+        self.assertEqual(status.HTTP_200_OK, response.status_code)
+        expect_resp_data = {'vlId': self.vl_inst_id, 'vlName': self.vl_name, 'vlStatus': "active"}
+        self.assertEqual(expect_resp_data, response.data)
+
+        response = self.client.get("/openoapi/nslcm/v1/ns/vls/%s" % "notExist")
+        self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code)
diff --git a/lcm/ns/tests/vnfs/__init__.py b/lcm/ns/tests/vnfs/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/tests/vnfs/tests.py b/lcm/ns/tests/vnfs/tests.py
new file mode 100644 (file)
index 0000000..ffd0eea
--- /dev/null
@@ -0,0 +1,637 @@
+# Copyright 2016-2017 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 uuid
+
+import mock
+from django.test import TestCase, Client
+from rest_framework import status
+
+from lcm.ns.vnfs import create_vnfs
+from lcm.ns.vnfs.const import VNF_STATUS
+from lcm.ns.vnfs.create_vnfs import CreateVnfs
+from lcm.pub.database.models import NfInstModel, JobModel, NfPackageModel, NSInstModel
+from lcm.pub.utils import restcall
+from lcm.pub.utils.jobutil import JOB_MODEL_STATUS
+from lcm.pub.utils.timeutil import now_time
+from lcm.pub.utils.values import ignore_case_get
+from lcm.ns.vnfs.terminate_nfs import TerminateVnfs
+from lcm.ns.vnfs.scale_vnfs import NFManualScaleService
+from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE
+
+
+class TestGetVnfViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.nf_inst_id = str(uuid.uuid4())
+        NfInstModel(nfinstid=self.nf_inst_id, nf_name='vnf1', vnfm_inst_id='1', vnf_id='vnf_id1',
+                    status=VNF_STATUS.ACTIVE, create_time=now_time(), lastuptime=now_time()).save()
+
+    def tearDown(self):
+        NfInstModel.objects.all().delete()
+
+    def test_get_vnf(self):
+        response = self.client.get("/openoapi/nslcm/v1/ns/vnfs/%s" % self.nf_inst_id)
+        self.failUnlessEqual(status.HTTP_200_OK, response.status_code)
+        context = json.loads(response.content)
+        self.failUnlessEqual(self.nf_inst_id, context['vnfInstId'])
+
+
+class TestCreateVnfViews(TestCase):
+    def setUp(self):
+        self.ns_inst_id = str(uuid.uuid4())
+        self.job_id = str(uuid.uuid4())
+        self.data = {
+            'nsInstanceId': self.ns_inst_id,
+            'additionalParamForNs': {"inputs": json.dumps({})},
+            'additionalParamForVnf': [{
+                'vnfprofileid': 'VBras',
+                'additionalparam': {
+                    'inputs': json.dumps({'vnf_param1': '11', 'vnf_param2': '22'}),
+                    'vnfminstanceid': "1"}}],
+            'vnfIndex': '1'}
+        self.client = Client()
+        NfPackageModel(uuid=str(uuid.uuid4()), nfpackageid='package_id1', vnfdid='zte_vbras', vendor='zte',
+                       vnfdversion='1.0.0', vnfversion='1.0.0', vnfdmodel=json.dumps(vnfd_model_dict)).save()
+        NSInstModel(id=self.ns_inst_id, name='ns', nspackage_id='1', nsd_id='nsd_id', description='description',
+                    status='instantiating', nsd_model=json.dumps(nsd_model_dict), create_time=now_time(),
+                    lastuptime=now_time()).save()
+
+    def tearDown(self):
+        NfInstModel.objects.all().delete()
+        JobModel.objects.all().delete()
+
+    @mock.patch.object(CreateVnfs, 'run')
+    def test_create_vnf(self, mock_run):
+        response = self.client.post("/openoapi/nslcm/v1/ns/vnfs", data=self.data)
+        self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
+        context = json.loads(response.content)
+        self.assertTrue(NfInstModel.objects.filter(nfinstid=context['vnfInstId']).exists())
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_create_vnf_thread(self, mock_call_req):
+        mock_vals = {
+            "/openoapi/ztevmanagerdriver/v1/1/vnfs":
+                [0, json.JSONEncoder().encode({"jobId": self.job_id, "vnfInstanceId": 3}), '200'],
+            "/openoapi/extsys/v1/vnfms/1":
+                [0, json.JSONEncoder().encode({"name": 'vnfm1'}), '200'],
+            "/openoapi/resmgr/v1/vnf":
+                [0, json.JSONEncoder().encode({}), '200'],
+            "/openoapi/resmgr/v1/vnfinfo":
+                [0, json.JSONEncoder().encode({}), '200'],
+            "/openoapi/ztevmanagerdriver/v1/jobs/" + self.job_id + "&responseId=0":
+                [0, json.JSONEncoder().encode({"jobid": self.job_id,
+                                               "responsedescriptor": {"progress": "100",
+                                                                      "status": JOB_MODEL_STATUS.FINISHED,
+                                                                      "responseid": "3",
+                                                                      "statusdescription": "creating",
+                                                                      "errorcode": "0",
+                                                                      "responsehistorylist": [
+                                                                          {"progress": "0",
+                                                                           "status": JOB_MODEL_STATUS.PROCESSING,
+                                                                           "responseid": "2",
+                                                                           "statusdescription": "creating",
+                                                                           "errorcode": "0"}]}}), '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+        data = {'ns_instance_id': ignore_case_get(self.data, 'nsInstanceId'),
+                'additional_param_for_ns': ignore_case_get(self.data, 'additionalParamForNs'),
+                'additional_param_for_vnf': ignore_case_get(self.data, 'additionalParamForVnf'),
+                'vnf_index': ignore_case_get(self.data, 'vnfIndex')}
+        nf_inst_id, job_id = create_vnfs.prepare_create_params()
+        CreateVnfs(data, nf_inst_id, job_id).run()
+        self.assertTrue(NfInstModel.objects.get(nfinstid=nf_inst_id).status, VNF_STATUS.ACTIVE)
+
+
+class TestTerminateVnfViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.ns_inst_id = str(uuid.uuid4())
+        self.nf_inst_id = '1'
+        self.vnffg_id = str(uuid.uuid4())
+        self.vim_id = str(uuid.uuid4())
+        self.job_id = str(uuid.uuid4())
+        self.nf_uuid = '111'
+        self.tenant = "tenantname"
+        NSInstModel.objects.all().delete()
+        NfInstModel.objects.all().delete()
+        NSInstModel(id=self.ns_inst_id, name="ns_name").save()
+        NfInstModel.objects.create(nfinstid=self.nf_inst_id, nf_name='name_1', vnf_id='1',
+                                   vnfm_inst_id='1', ns_inst_id='111,2-2-2',
+                                   max_cpu='14', max_ram='12296', max_hd='101', max_shd="20", max_net=10,
+                                   status='active', mnfinstid=self.nf_uuid, package_id='pkg1',
+                                   vnfd_model='{"metadata": {"vnfdId": "1","vnfdName": "PGW001",'
+                                              '"vnfProvider": "zte","vnfdVersion": "V00001","vnfVersion": "V5.10.20",'
+                                              '"productType": "CN","vnfType": "PGW",'
+                                              '"description": "PGW VNFD description",'
+                                              '"isShared":true,"vnfExtendType":"driver"}}')
+
+    def tearDown(self):
+        NSInstModel.objects.all().delete()
+        NfInstModel.objects.all().delete()
+
+    @mock.patch.object(TerminateVnfs, 'run')
+    def test_terminate_vnf_url(self, mock_run):
+        req_data = {
+            "terminationType": "forceful",
+            "gracefulTerminationTimeout": "600"}
+
+        response = self.client.post("/openoapi/nslcm/v1/ns/vnfs/%s" % self.nf_inst_id, data=req_data)
+        self.failUnlessEqual(status.HTTP_201_CREATED, response.status_code)
+
+    @mock.patch.object(restcall, "call_req")
+    def test_terminate_vnf(self, mock_call_req):
+        job_id = JobUtil.create_job("VNF", JOB_TYPE.TERMINATE_VNF, self.nf_inst_id)
+
+        nfinst = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
+        if nfinst:
+            self.failUnlessEqual(1, 1)
+        else:
+            self.failUnlessEqual(1, 0)
+
+        mock_vals = {
+            "/openoapi/ztevmanagerdriver/v1/1/vnfs/111/terminate":
+                [0, json.JSONEncoder().encode({"jobId": job_id}), '200'],
+            "/openoapi/extsys/v1/vnfms/1":
+                [0, json.JSONEncoder().encode({"name": 'vnfm1', "type": 'ztevmanagerdriver'}), '200'],
+            "/openoapi/resmgr/v1/vnf/1":
+                [0, json.JSONEncoder().encode({"jobId": job_id}), '200'],
+            "/openoapi/ztevmanagerdriver/v1/1/jobs/" + job_id + "?responseId=0":
+                [0, json.JSONEncoder().encode({"jobId": job_id,
+                                               "responsedescriptor": {"progress": "100",
+                                                                      "status": JOB_MODEL_STATUS.FINISHED,
+                                                                      "responseid": "3",
+                                                                      "statusdescription": "creating",
+                                                                      "errorcode": "0",
+                                                                      "responsehistorylist": [
+                                                                          {"progress": "0",
+                                                                           "status": JOB_MODEL_STATUS.PROCESSING,
+                                                                           "responseid": "2",
+                                                                           "statusdescription": "creating",
+                                                                           "errorcode": "0"}]}}), '200']}
+
+        req_data = {
+            "terminationType": "forceful",
+            "gracefulTerminationTimeout": "600"}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+
+        TerminateVnfs(req_data, self.nf_inst_id, job_id).run()
+        nfinst = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
+        if nfinst:
+            self.failUnlessEqual(1, 0)
+        else:
+            self.failUnlessEqual(1, 1)
+
+class TestScaleVnfViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.ns_inst_id = str(uuid.uuid4())
+        self.nf_inst_id = str(uuid.uuid4())
+        self.vnffg_id = str(uuid.uuid4())
+        self.vim_id = str(uuid.uuid4())
+        self.job_id = str(uuid.uuid4())
+        self.nf_uuid = '111'
+        self.tenant = "tenantname"
+        NSInstModel(id=self.ns_inst_id, name="ns_name").save()
+        NfInstModel.objects.create(nfinstid=self.nf_inst_id, nf_name='name_1', vnf_id='1',
+                                   vnfm_inst_id='1', ns_inst_id='111,2-2-2',
+                                   max_cpu='14', max_ram='12296', max_hd='101', max_shd="20", max_net=10,
+                                   status='active', mnfinstid=self.nf_uuid, package_id='pkg1',
+                                   vnfd_model='{"metadata": {"vnfdId": "1","vnfdName": "PGW001",'
+                                              '"vnfProvider": "zte","vnfdVersion": "V00001","vnfVersion": "V5.10.20",'
+                                              '"productType": "CN","vnfType": "PGW",'
+                                              '"description": "PGW VNFD description",'
+                                              '"isShared":true,"vnfExtendType":"driver"}}')
+
+    def tearDown(self):
+        NSInstModel.objects.all().delete()
+        NfInstModel.objects.all().delete()
+
+    @mock.patch.object(restcall, "call_req")
+    def test_scale_vnf(self, mock_call_req):
+        job_id = JobUtil.create_job("VNF", JOB_TYPE.TERMINATE_VNF, self.nf_inst_id)
+
+        vnfd_info = {
+            "vnf_flavours":[
+                {
+                    "flavour_id":"flavour1",
+                    "description":"",
+                    "vdu_profiles":[
+                        {
+                            "vdu_id":"vdu1Id",
+                            "instances_minimum_number": 1,
+                            "instances_maximum_number": 4,
+                            "local_affinity_antiaffinity_rule":[
+                                {
+                                    "affinity_antiaffinity":"affinity",
+                                    "scope":"node",
+                                }
+                            ]
+                        }
+                    ],
+                    "scaling_aspects":[
+                        {
+                            "id": "demo_aspect",
+                            "name": "demo_aspect",
+                            "description": "demo_aspect",
+                            "associated_group": "elementGroup1",
+                            "max_scale_level": 5
+                        }
+                    ]
+                }
+            ],
+            "element_groups": [
+                  {
+                      "group_id": "elementGroup1",
+                      "description": "",
+                      "properties":{
+                          "name": "elementGroup1",
+                      },
+                      "members": ["gsu_vm","pfu_vm"],
+                  }
+            ]
+        }
+
+        req_data = {
+            "scaleVnfData": [
+                {
+                    "type":"SCALE_OUT",
+                    "aspectId":"demo_aspect1",
+                    "numberOfSteps":1,
+                    "additionalParam":vnfd_info
+                },
+                {
+                    "type":"SCALE_OUT",
+                    "aspectId":"demo_aspect2",
+                    "numberOfSteps":1,
+                    "additionalParam":vnfd_info
+                }
+            ]
+        }
+
+
+        mock_vals = {
+            "/openoapi/ztevmanagerdriver/v1/1/vnfs/111/terminate":
+                [0, json.JSONEncoder().encode({"jobId": job_id}), '200'],
+            "/openoapi/ztevmanagerdriver/v1/1/vnfs/111/terminate":
+                [0, json.JSONEncoder().encode({"jobId": job_id}), '200']
+        }
+        NFManualScaleService(self.nf_inst_id, req_data).run()
+        nsIns = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
+        if nsIns:
+            self.failUnlessEqual(1, 1)
+        else:
+            self.failUnlessEqual(1, 0)
+
+vnfd_model_dict = {
+    'local_storages': [],
+    'vdus': [
+        {
+            'volumn_storages': [],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'2'},
+            'local_storages': [],
+            'vdu_id': u'vdu_omm.001',
+            'image_file': u'opencos_sss_omm_img_release_20150723-1-disk1',
+            'dependencies': [],
+            'vls': [],
+            'cps': [],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''},
+                'inject_data_list': [],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''},
+                'local_affinity_antiaffinity_rule': {},
+                'template_id': u'omm.001',
+                'manual_scale_select_vim': False},
+            'description': u'singleommvm'},
+        {
+            'volumn_storages': [],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'4'},
+            'local_storages': [],
+            'vdu_id': u'vdu_1',
+            'image_file': u'sss',
+            'dependencies': [],
+            'vls': [],
+            'cps': [],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''},
+                'inject_data_list': [],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''},
+                'local_affinity_antiaffinity_rule': {},
+                'template_id': u'1',
+                'manual_scale_select_vim': False},
+            'description': u'ompvm'},
+        {
+            'volumn_storages': [],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'},
+            'local_storages': [],
+            'vdu_id': u'vdu_2',
+            'image_file': u'sss',
+            'dependencies': [],
+            'vls': [],
+            'cps': [],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''},
+                'inject_data_list': [],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''},
+                'local_affinity_antiaffinity_rule': {},
+                'template_id': u'2',
+                'manual_scale_select_vim': False},
+            'description': u'ompvm'},
+        {
+            'volumn_storages': [],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'},
+            'local_storages': [],
+            'vdu_id': u'vdu_3',
+            'image_file': u'sss',
+            'dependencies': [],
+            'vls': [],
+            'cps': [],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''},
+                'inject_data_list': [],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''},
+                'local_affinity_antiaffinity_rule': {},
+                'template_id': u'3',
+                'manual_scale_select_vim': False},
+            'description': u'ompvm'},
+        {
+            'volumn_storages': [],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'4'},
+            'local_storages': [],
+            'vdu_id': u'vdu_10',
+            'image_file': u'sss',
+            'dependencies': [],
+            'vls': [],
+            'cps': [],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''},
+                'inject_data_list': [],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''},
+                'local_affinity_antiaffinity_rule': {},
+                'template_id': u'10',
+                'manual_scale_select_vim': False},
+            'description': u'ppvm'},
+        {
+            'volumn_storages': [],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'},
+            'local_storages': [],
+            'vdu_id': u'vdu_11',
+            'image_file': u'sss',
+            'dependencies': [],
+            'vls': [],
+            'cps': [],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''},
+                'inject_data_list': [],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''},
+                'local_affinity_antiaffinity_rule': {},
+                'template_id': u'11',
+                'manual_scale_select_vim': False},
+            'description': u'ppvm'},
+        {
+            'volumn_storages': [],
+            'nfv_compute': {
+                'mem_size': '',
+                'num_cpus': u'14'},
+            'local_storages': [],
+            'vdu_id': u'vdu_12',
+            'image_file': u'sss',
+            'dependencies': [],
+            'vls': [],
+            'cps': [],
+            'properties': {
+                'key_vdu': '',
+                'support_scaling': False,
+                'vdu_type': '',
+                'name': '',
+                'storage_policy': '',
+                'location_info': {
+                    'vimId': '',
+                    'availability_zone': '',
+                    'region': '',
+                    'dc': '',
+                    'host': '',
+                    'tenant': ''},
+                'inject_data_list': [],
+                'watchdog': {
+                    'action': '',
+                    'enabledelay': ''},
+                'local_affinity_antiaffinity_rule': {},
+                'template_id': u'12',
+                'manual_scale_select_vim': False},
+            'description': u'ppvm'}],
+    'volumn_storages': [],
+    'policies': {
+        'scaling': {
+            'targets': {},
+            'policy_id': u'policy_scale_sss-vnf-template',
+            'properties': {
+                'policy_file': '*-vnfd.zip/*-vnf-policy.xml'},
+            'description': ''}},
+    'image_files': [
+        {
+            'description': '',
+            'properties': {
+                'name': u'opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+                'checksum': '',
+                'disk_format': u'VMDK',
+                'file_url': u'./zte-cn-sss-main-image/OMM/opencos_sss_omm_img_release_20150723-1-disk1.vmdk',
+                'container_type': 'vm',
+                'version': '',
+                'hypervisor_type': 'kvm'},
+            'image_file_id': u'opencos_sss_omm_img_release_20150723-1-disk1'},
+        {
+            'description': '',
+            'properties': {
+                'name': u'sss.vmdk',
+                'checksum': '',
+                'disk_format': u'VMDK',
+                'file_url': u'./zte-cn-sss-main-image/NE/sss.vmdk',
+                'container_type': 'vm',
+                'version': '',
+                'hypervisor_type': 'kvm'},
+            'image_file_id': u'sss'}],
+    'vls': [],
+    'cps': [],
+    'metadata': {
+        'vendor': u'zte',
+        'is_shared': False,
+        'description': '',
+        'domain_type': u'CN',
+        'version': u'v4.14.10',
+        'vmnumber_overquota_alarm': False,
+        'cross_dc': False,
+        'vnf_type': u'SSS',
+        'vnfd_version': u'V00000001',
+        'id': u'sss-vnf-template',
+        'name': u'sss-vnf-template'}}
+
+nsd_model_dict = {
+    "vnffgs": [],
+    "inputs": {
+        "externalDataNetworkName": {
+            "default": "",
+            "type": "string",
+            "description": ""}},
+    "pnfs": [],
+    "fps": [],
+    "server_groups": [],
+    "ns_flavours": [],
+    "vnfs": [
+        {
+            "dependency": [],
+            "properties": {
+                "plugin_info": "vbrasplugin_1.0",
+                "vendor": "zte",
+                "is_shared": "False",
+                "request_reclassification": "False",
+                "vnfd_version": "1.0.0",
+                "version": "1.0",
+                "nsh_aware": "True",
+                "cross_dc": "False",
+                "externalDataNetworkName": {
+                    "get_input": "externalDataNetworkName"},
+                "id": "zte_vbras",
+                "name": "vbras"},
+            "vnf_id": "VBras",
+            "networks": [],
+            "description": ""}],
+    "ns_exposed": {
+        "external_cps": [],
+        "forward_cps": []},
+    "vls": [
+        {
+            "vl_id": "ext_mnet_network",
+            "description": "",
+            "properties": {
+                "network_type": "vlan",
+                "name": "externalMNetworkName",
+                "dhcp_enabled": False,
+                "location_info": {
+                    "host": True,
+                    "vimid": 2,
+                    "region": True,
+                    "tenant": "admin",
+                    "dc": ""},
+                "end_ip": "190.168.100.100",
+                "gateway_ip": "190.168.100.1",
+                "start_ip": "190.168.100.2",
+                "cidr": "190.168.100.0/24",
+                "mtu": 1500,
+                "network_name": "sub_mnet",
+                "ip_version": 4}}],
+    "cps": [],
+    "policies": [],
+    "metadata": {
+        "invariant_id": "vbras_ns",
+        "description": "vbras_ns",
+        "version": 1,
+        "vendor": "zte",
+        "id": "vbras_ns",
+        "name": "vbras_ns"}}
diff --git a/lcm/ns/tests/vnfs/verify_test.py b/lcm/ns/tests/vnfs/verify_test.py
new file mode 100644 (file)
index 0000000..59cdbea
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright 2017 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.test import TestCase, Client
+from rest_framework import status
+
+class TestGetVnfViews(TestCase):
+    def setUp(self):
+        self.client = Client()
+        self.data = {"PackageID":"1223334"}
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_verify_vnfs(self):
+        response = self.client.post("/openoapi/nslcm/v1/vnfonboarding", data=self.data)
+        self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
\ No newline at end of file
diff --git a/lcm/ns/urls.py b/lcm/ns/urls.py
new file mode 100644 (file)
index 0000000..1efd963
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright 2016-2017 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 patterns, url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from lcm.ns.views import CreateNSView, NSInstView, TerminateNSView, NSDetailView, SwaggerJsonView, NSInstPostDealView, \
+    NSManualScaleView
+
+urlpatterns = patterns('',
+                       url(r'^openoapi/nslcm/v1/ns$', CreateNSView.as_view()),
+                       url(r'^openoapi/nslcm/v1/swagger.json$', SwaggerJsonView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/instantiate$',
+                           NSInstView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/terminate$',
+                           TerminateNSView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)$', NSDetailView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/postdeal$',
+                           NSInstPostDealView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/scale$',
+                           NSManualScaleView.as_view()),
+                       )
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns/views.py b/lcm/ns/views.py
new file mode 100644 (file)
index 0000000..ffe35a4
--- /dev/null
@@ -0,0 +1,160 @@
+# Copyright 2016-2017 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
+import os
+import traceback
+
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from lcm.ns.ns_create import CreateNSService
+from lcm.ns.ns_get import GetNSInfoService
+from lcm.ns.ns_instant import InstantNSService
+from lcm.ns.ns_manual_scale import NSManualScaleService
+from lcm.ns.ns_terminate import TerminateNsService, DeleteNsService
+from lcm.pub.database.models import NSInstModel, ServiceBaseInfoModel
+from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.utils.restcall import req_by_msb
+from lcm.pub.exceptions import NSLCMException
+
+logger = logging.getLogger(__name__)
+
+
+class CreateNSView(APIView):
+    def get(self, request):
+        logger.debug("CreateNSView::get")
+        ret = GetNSInfoService().get_ns_info()
+        logger.debug("CreateNSView::get::ret=%s", ret)
+        return Response(data=ret, status=status.HTTP_200_OK)
+
+    def post(self, request):
+        logger.debug("Enter CreateNS: %s", request.data)
+        nsd_id = ignore_case_get(request.data, 'nsdId')
+        ns_name = ignore_case_get(request.data, 'nsName')
+        description = ignore_case_get(request.data, 'description')
+        try:
+            ns_inst_id = CreateNSService(nsd_id, ns_name, description).do_biz()
+        except Exception as e:
+            logger.error("Exception in CreateNS: %s", e.message)
+            return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        logger.debug("CreateNSView::post::ret={'nsInstanceId':%s}", ns_inst_id)
+        return Response(data={'nsInstanceId': ns_inst_id}, status=status.HTTP_201_CREATED)
+
+
+class NSInstView(APIView):
+    def post(self, request, ns_instance_id):
+        ack = InstantNSService(ns_instance_id, request.data).do_biz()
+        logger.debug("Leave NSInstView::post::ack=%s", ack)
+        return Response(data=ack['data'], status=ack['status'])
+
+
+class TerminateNSView(APIView):
+    def post(self, request, ns_instance_id):
+        logger.debug("Enter TerminateNSView::post %s", request.data)
+        termination_type = ignore_case_get(request.data, 'terminationType')
+        graceful_termination_timeout = ignore_case_get(request.data, 'gracefulTerminationTimeout')
+        job_id = JobUtil.create_job("VNF", JOB_TYPE.TERMINATE_VNF, ns_instance_id)
+        try:
+            TerminateNsService(ns_instance_id, termination_type, graceful_termination_timeout, job_id).start()
+        except Exception as e:
+            logger.error("Exception in CreateNS: %s", e.message)
+            return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        ret = {'jobId': job_id}
+        logger.debug("Leave TerminateNSView::post ret=%s", ret)
+        return Response(data=ret, status=status.HTTP_202_ACCEPTED)
+
+
+class NSDetailView(APIView):
+    def get(self, request, ns_instance_id):
+        logger.debug("Enter NSDetailView::get ns(%s)", ns_instance_id)
+        ret = GetNSInfoService(ns_instance_id).get_ns_info()
+        if not ret:
+            return Response(status=status.HTTP_404_NOT_FOUND)
+        logger.debug("Leave NSDetailView::get::ret=%s", ret)
+        return Response(data=ret, status=status.HTTP_200_OK)
+
+    def delete(self, request, ns_instance_id):
+        logger.debug("Enter NSDetailView::delete ns(%s)", ns_instance_id)
+        DeleteNsService(ns_instance_id).do_biz()
+        return Response(data={}, status=status.HTTP_204_NO_CONTENT)
+
+
+class SwaggerJsonView(APIView):
+    def get(self, request):
+        json_file = os.path.join(os.path.dirname(__file__), 'swagger.json')
+        f = open(json_file)
+        json_data = json.JSONDecoder().decode(f.read())
+        f.close()
+        return Response(json_data)
+
+
+class NSInstPostDealView(APIView):
+
+
+    def post(self, request, ns_instance_id):
+        logger.debug("Enter NSInstPostDealView::post %s, %s", request.data, ns_instance_id)
+        ns_post_status = ignore_case_get(request.data, 'status')
+        ns_status = 'ACTIVE' if ns_post_status == 'true' else 'FAILED'
+        ns_opr_status = 'success' if ns_post_status == 'true' else 'failed'
+        try:
+            NSInstModel.objects.filter(id=ns_instance_id).update(status=ns_status)
+            ServiceBaseInfoModel.objects.filter(service_id=ns_instance_id).update(
+                active_status=ns_status, status=ns_opr_status)
+            nsd_info = NSInstModel.objects.filter(id=ns_instance_id)
+            nsd_id = nsd_info[0].nsd_id
+            nsd_model = json.loads(nsd_info[0].nsd_model)
+            if "policies" in nsd_model and nsd_model["policies"]:
+                policy = nsd_model["policies"][0]
+                if "properties" in policy and policy["properties"]:
+                    file_url = ignore_case_get(policy["properties"][0], "drl_file_url")
+                else:
+                    file_url = ""
+                self.send_policy_request(ns_instance_id, nsd_id, file_url)
+        except:
+            logger.error(traceback.format_exc())
+            return Response(data={'error': 'Failed to update status of NS(%s)' % ns_instance_id},
+                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        logger.debug("*****NS INST %s, %s******", ns_status, ns_opr_status)
+        return Response(data={'success': 'Update status of NS(%s) to %s' % (ns_instance_id, ns_status)},
+                        status=status.HTTP_202_ACCEPTED)
+
+    def send_policy_request(self,ns_instance_id, nsd_id, file_url):
+        input_data = {
+            "nsid": ns_instance_id,
+            "nsdid": nsd_id,
+            "fileUri":file_url
+        }
+        req_param = json.JSONEncoder().encode(input_data)
+        policy_engine_url = 'openoapi/polengine/v1/policyinfo'
+        ret = req_by_msb(policy_engine_url, "POST", req_param)
+        if ret[0] != 0:
+            logger.error("Failed to send ns policy req")
+            #raise NSLCMException('Failed to send ns policy req)')
+
+
+class NSManualScaleView(APIView):
+    def post(self, request, ns_instance_id):
+        logger.debug("Enter NSManualScaleView::post %s, %s", request.data, ns_instance_id)
+        job_id = JobUtil.create_job("NS", JOB_TYPE.MANUAL_SCALE_VNF, ns_instance_id)
+        try:
+            NSManualScaleService(ns_instance_id, request.data, job_id).start()
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            JobUtil.add_job_status(job_id, 255, 'NS scale failed: %s' % e.message)
+            return Response(data={'error': 'NS scale failed: %s' % ns_instance_id},
+                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        return Response(data={'jobId': job_id}, status=status.HTTP_202_ACCEPTED)
\ No newline at end of file
diff --git a/lcm/ns/vls/__init__.py b/lcm/ns/vls/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/vls/create_vls.py b/lcm/ns/vls/create_vls.py
new file mode 100644 (file)
index 0000000..0065ff6
--- /dev/null
@@ -0,0 +1,181 @@
+# Copyright 2016-2017 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
+import traceback
+import uuid
+
+from lcm.ns.const import OWNER_TYPE
+from lcm.pub.database.models import VLInstModel, NSInstModel, VNFFGInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi import extsys, resmgr
+from lcm.pub.nfvi.vim import const
+from lcm.pub.nfvi.vim import vimadaptor
+from lcm.pub.utils.values import ignore_case_get
+
+logger = logging.getLogger(__name__)
+
+
+class CreateVls(object):
+    def __init__(self, data):
+        self.owner_id = ignore_case_get(data, "nsInstanceId")
+        self.index = int(float(ignore_case_get(data, "vlIndex")))
+        self.context = ignore_case_get(data, "context")
+        self.additionalParam = ignore_case_get(data, "additionalParamForNs")
+        self.vl_inst_id = str(uuid.uuid4())
+        self.owner_type = OWNER_TYPE.NS
+        self.vld_id = ""
+        self.vl_properties = ""
+        self.vl_inst_name = ""
+        self.related_network_id = ""
+        self.related_subnetwork_id = ""
+        self.vim_id = ""
+        self.vim_name = ""
+        self.tenant = ""
+        self.description = ""
+        self.route_external = ""
+        self.ns_name = ""
+
+    def do(self):
+        try:
+            self.get_data()
+            self.create_vl_to_vim()
+            self.create_vl_to_resmgr()
+            self.save_vl_to_db()
+            return {"result": 0, "detail": "instantiation vl success", "vlId": self.vl_inst_id}
+        except NSLCMException as e:
+            return self.exception_handle(e)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            return self.exception_handle(e)
+
+    def exception_handle(self, e):
+        detail = "vl instantiation failed, detail message: %s" % e.message
+        logger.error(detail)
+        return {"result": 1, "detail": detail, "vlId": self.vl_inst_id}
+
+    def get_data(self):
+        if isinstance(self.context, (unicode, str)):
+            self.context = json.JSONDecoder().decode(self.context)
+        vl_info = self.get_vl_info(ignore_case_get(self.context, "vls"))
+        self.vld_id = ignore_case_get(vl_info, "vl_id")
+        self.description = ignore_case_get(vl_info, "description")
+        self.vl_properties = ignore_case_get(vl_info, "properties")
+        self.vl_inst_name = ignore_case_get(self.vl_properties, "name")
+        self.route_external = ignore_case_get(vl_info, "route_external")
+        ns_info = NSInstModel.objects.filter(id=self.owner_id)
+        self.ns_name = ns_info[0].name if ns_info else ""
+
+    def get_vl_info(self, vl_all_info):
+        return vl_all_info[self.index - 1]
+
+    def create_vl_to_vim(self):
+        self.vim_id = self.vl_properties["location_info"]["vimid"]
+        if not self.vim_id:
+            self.vim_id = ignore_case_get(self.additionalParam, "location")
+        self.tenant = ignore_case_get(self.vl_properties["location_info"], "tenant")
+        network_data = {
+            "tenant": self.tenant,
+            "network_name": self.vl_properties.get("network_name", ""),
+            "shared": const.SHARED_NET,
+            "network_type": self.vl_properties.get("network_type", ""),
+            "segmentation_id": self.vl_properties.get("segmentation_id", ""),
+            "physical_network": self.vl_properties.get("physical_network", ""),
+            "mtu": self.vl_properties.get("mtu", const.DEFAULT_MTU),
+            "vlan_transparent": self.vl_properties.get("vlan_transparent", False),
+            "subnet_list": [{
+                "subnet_name": self.vl_properties.get("name", ""),
+                "cidr": self.vl_properties.get("cidr", "192.168.0.0/24"),
+                "ip_version": self.vl_properties.get("ip_version", const.IPV4),
+                "enable_dhcp": self.vl_properties.get("dhcp_enabled", False),
+                "gateway_ip": self.vl_properties.get("gateway_ip", ""),
+                "dns_nameservers": self.vl_properties.get("dns_nameservers", ""),
+                "host_routes": self.vl_properties.get("host_routes", "")}]}
+        startip = self.vl_properties.get("start_ip", "")
+        endip = self.vl_properties.get("end_ip", "")
+        if startip and endip:
+            network_data["subnet_list"][0]["allocation_pools"] = [
+                {"start": startip, "end": endip}]
+
+        vl_resp = self.create_network_to_vim(network_data)
+        self.related_network_id = vl_resp["id"]
+        self.related_subnetwork_id = vl_resp["subnet_list"][0]["id"] if vl_resp["subnet_list"] else ""
+
+    def create_network_to_vim(self, network_data):
+        vim_resp_body = extsys.get_vim_by_id(self.vim_id)
+        self.vim_name = vim_resp_body["name"]
+        data = {
+            "vimid": self.vim_id,
+            "vimtype": vim_resp_body["type"],
+            "url": vim_resp_body["url"],
+            "user": vim_resp_body["userName"],
+            "passwd": vim_resp_body["password"],
+            "tenant": vim_resp_body["tenant"]}
+        vim_api = vimadaptor.VimAdaptor(data)
+        if not network_data["tenant"]:
+            network_data["tenant"] = vim_resp_body["tenant"]
+        vl_ret = vim_api.create_network(network_data)
+        if vl_ret[0] != 0:
+            logger.error("Send post vl request to vim failed, detail is %s" % vl_ret[1])
+            raise NSLCMException("Send post vl request to vim failed.")
+        return vl_ret[1]
+
+    def save_vl_to_db(self):
+        VLInstModel(vlinstanceid=self.vl_inst_id, vldid=self.vld_id, vlinstancename=self.vl_inst_name,
+                    ownertype=self.owner_type, ownerid=self.owner_id, relatednetworkid=self.related_network_id,
+                    relatedsubnetworkid=self.related_subnetwork_id, vimid=self.vim_id, tenant=self.tenant).save()
+        # do_biz_with_share_lock("create-vllist-in-vnffg-%s" % self.owner_id, self.create_vl_inst_id_in_vnffg)
+        self.create_vl_inst_id_in_vnffg()
+
+    def create_vl_to_resmgr(self):
+        req_param = {
+            "vlInstanceId": self.vl_inst_id,
+            "name": self.vl_properties.get("network_name", ""),
+            "backendId": str(self.related_network_id),
+            "isPublic": "True",
+            "dcName": "",
+            "vimId": str(self.vim_id),
+            "vimName": self.vim_name,
+            "physicialNet": self.vl_properties.get("physical_network", ""),
+            "nsId": self.owner_id,
+            "nsName": self.ns_name,
+            "description": self.description,
+            "networkType": self.vl_properties.get("network_type", ""),
+            "segmentation": str(self.vl_properties.get("segmentation_id", "")),
+            "mtu": str(self.vl_properties.get("mtu", "")),
+            "vlanTransparent": str(self.vl_properties.get("vlan_transparent", "")),
+            "routerExternal": self.route_external,
+            "resourceProviderType": "",
+            "resourceProviderId": ""}
+        resmgr.create_vl(req_param)
+
+    def create_vl_inst_id_in_vnffg(self):
+        if "vnffgs" in self.context:
+            for vnffg_info in self.context["vnffgs"]:
+                vl_id_list = vnffg_info.get("properties", {}).get("dependent_virtual_link", "")
+                if vl_id_list:
+                    vl_inst_id_list = []
+                    for vl_id in vl_id_list:
+                        vl_inst_info = VLInstModel.objects.filter(vldid=vl_id)
+                        if vl_inst_info:
+                            vl_inst_id_list.append(vl_inst_info[0].vlinstanceid)
+                        else:
+                            vl_inst_id_list.append("")
+                    vl_inst_id_str = ""
+                    for vl_inst_id in vl_inst_id_list:
+                        vl_inst_id_str += vl_inst_id + ","
+                    vl_inst_id_str = vl_inst_id_str[:-1]
+                    VNFFGInstModel.objects.filter(vnffgdid=vnffg_info["vnffg_id"], nsinstid=self.owner_id).update(
+                        vllist=vl_inst_id_str)
diff --git a/lcm/ns/vls/delete_vls.py b/lcm/ns/vls/delete_vls.py
new file mode 100644 (file)
index 0000000..d2d8640
--- /dev/null
@@ -0,0 +1,85 @@
+# Copyright 2016 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 lcm.pub.database.models import VLInstModel, VNFFGInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi import resmgr, extsys
+from lcm.pub.nfvi.vim import vimadaptor
+
+logger = logging.getLogger(__name__)
+
+
+class DeleteVls(object):
+    def __init__(self, vl_inst_id):
+        self.vl_inst_id = vl_inst_id
+        self.ns_inst_id = ""
+
+    def do(self):
+        try:
+            vl_inst_info = VLInstModel.objects.filter(vlinstanceid=self.vl_inst_id)
+            if not vl_inst_info:
+                logger.info("vl inst id(%s) is not exist or has been already deleted" % self.vl_inst_id)
+                return {"result": 0, "detail": "vl is not exist or has been already deleted"}
+            self.ns_inst_id = vl_inst_info[0].ownerid
+            vim_id = vl_inst_info[0].vimid
+            subnetwork_id_list = vl_inst_info[0].relatedsubnetworkid.split(",")
+            network_id = vl_inst_info[0].relatednetworkid
+            self.delete_vl_from_vim(vim_id, subnetwork_id_list, network_id)
+            self.delete_vl_from_resmgr()
+            self.delete_vl_from_db(vl_inst_info)
+            return {"result": 0, "detail": "delete vl success"}
+        except NSLCMException as e:
+            return self.exception_handle(e)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            return self.exception_handle(e)
+
+    def exception_handle(self, e):
+        detail = "vl delete failed, detail message: %s" % e.message
+        logger.error(detail)
+        return {"result": 0, "detail": detail}
+
+    def delete_vl_from_vim(self, vim_id, subnetwork_id_list, network_id):
+        vim_resp_body = extsys.get_vim_by_id(vim_id)
+        data = {
+            "vimid": vim_id,
+            "vimtype": vim_resp_body["type"],
+            "url": vim_resp_body["url"],
+            "user": vim_resp_body["userName"],
+            "passwd": vim_resp_body["password"],
+            "tenant": vim_resp_body["tenant"]}
+        vim_api = vimadaptor.VimAdaptor(data)
+        for subnetwork_id in subnetwork_id_list:
+            vim_api.delete_subnet(subnet_id=subnetwork_id)
+        vim_api.delete_network(network_id=network_id)
+
+    def delete_vl_from_db(self, vl_inst_info):
+        # do_biz_with_share_lock("delete-vllist-in-vnffg-%s" % self.ns_inst_id, self.delete_vl_inst_id_in_vnffg)
+        self.delete_vl_inst_id_in_vnffg()
+        vl_inst_info.delete()
+
+    def delete_vl_from_resmgr(self):
+        resmgr.delete_vl(self.vl_inst_id)
+
+    def delete_vl_inst_id_in_vnffg(self):
+        for vnffg_info in VNFFGInstModel.objects.filter(nsinstid=self.ns_inst_id):
+            new_vl_id_list = ""
+            for old_vl_id in vnffg_info.vllist.split(","):
+                if old_vl_id != self.vl_inst_id:
+                    new_vl_id_list += old_vl_id + ","
+            new_vl_id_list = new_vl_id_list[:-1]
+            VNFFGInstModel.objects.filter(vnffginstid=vnffg_info.vnffginstid).update(vllist=new_vl_id_list)
diff --git a/lcm/ns/vls/get_vls.py b/lcm/ns/vls/get_vls.py
new file mode 100644 (file)
index 0000000..37692c5
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2016 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 VLInstModel
+
+
+class GetVls(object):
+    def __init__(self, vl_inst_id):
+        self.vl_inst_id = vl_inst_id
+
+    def do(self):
+        return VLInstModel.objects.filter(vlinstanceid=self.vl_inst_id)
diff --git a/lcm/ns/vls/urls.py b/lcm/ns/vls/urls.py
new file mode 100644 (file)
index 0000000..cad8ba3
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright 2016 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 patterns, url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from lcm.ns.vls.views import VlView, VlDetailView
+
+urlpatterns = patterns('',
+                       url(r'^openoapi/nslcm/v1/ns/vls$', VlView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/vls/(?P<vl_inst_id>[0-9a-zA-Z_-]+)$', VlDetailView.as_view()),
+                       )
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns/vls/views.py b/lcm/ns/vls/views.py
new file mode 100644 (file)
index 0000000..94ae5e2
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright 2016 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 status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from lcm.ns.vls.create_vls import CreateVls
+from lcm.ns.vls.delete_vls import DeleteVls
+from lcm.ns.vls.get_vls import GetVls
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class VlView(APIView):
+    def post(self, request):
+        logger.debug("VlsCreateView--post::> %s" % request.data)
+        resp = CreateVls(request.data).do()
+        return Response(data=resp, status=status.HTTP_201_CREATED)
+
+
+class VlDetailView(APIView):
+    def get(self, request, vl_inst_id):
+        logger.debug("VlDetailView--get::> %s" % vl_inst_id)
+        vl_inst_info = GetVls(vl_inst_id).do()
+        if not vl_inst_info:
+            return Response(status=status.HTTP_404_NOT_FOUND)
+        return Response(status=status.HTTP_200_OK, data={'vlId': vl_inst_id,
+                                                         'vlName': vl_inst_info[0].vlinstancename,
+                                                         'vlStatus': "active"})
+
+    def delete(self, request_paras, vl_inst_id):
+        logger.debug("VlDetailView--delete::> %s" % vl_inst_id)
+        resp = DeleteVls(vl_inst_id).do()
+        return Response(data=resp, status=status.HTTP_202_ACCEPTED)
diff --git a/lcm/ns/vnfs/__init__.py b/lcm/ns/vnfs/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/vnfs/const.py b/lcm/ns/vnfs/const.py
new file mode 100644 (file)
index 0000000..0bef8fe
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright 2016 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.utils.enumutil import enum
+
+VNF_STATUS = enum(NULL='null', INSTANTIATING="instantiating", INACTIVE='inactive', ACTIVE="active", FAILED="failed",
+                  TERMINATING="terminating", SCALING="scaling")
+INST_TYPE = enum(VNF=0, VNFM=1)
+INST_TYPE_NAME = enum(VNF='VNF', VNFM='VNFM')
+PACKAGE_TYPE = enum(VNFD='VNFD', NSD='NSD')
+
+NFVO_VNF_INST_TIMEOUT_SECOND = 1800
+
+DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
diff --git a/lcm/ns/vnfs/create_vnfs.py b/lcm/ns/vnfs/create_vnfs.py
new file mode 100644 (file)
index 0000000..83bb444
--- /dev/null
@@ -0,0 +1,267 @@
+# Copyright 2016 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
+import traceback
+import uuid
+from threading import Thread
+from lcm.ns.const import OWNER_TYPE
+
+from lcm.ns.vnfs.const import VNF_STATUS, NFVO_VNF_INST_TIMEOUT_SECOND, INST_TYPE, INST_TYPE_NAME
+from lcm.ns.vnfs.wait_job import wait_job_finish
+from lcm.pub.database.models import NfPackageModel, NfInstModel, NSInstModel, VmInstModel, VNFFGInstModel, VLInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi.extsys import get_vnfm_by_id
+from lcm.pub.msapi.resmgr import create_vnf, create_vnf_creation_info
+from lcm.pub.msapi.vnfmdriver import send_nf_init_request
+from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil, JOB_TYPE
+from lcm.pub.utils.share_lock import do_biz_with_share_lock
+from lcm.pub.utils.timeutil import now_time
+from lcm.pub.utils.values import ignore_case_get
+
+logger = logging.getLogger(__name__)
+
+
+def prepare_create_params():
+    nf_inst_id = str(uuid.uuid4())
+    NfInstModel(nfinstid=nf_inst_id, status=VNF_STATUS.INSTANTIATING, create_time=now_time(),
+                lastuptime=now_time()).save()
+    job_id = JobUtil.create_job(INST_TYPE_NAME.VNF, JOB_TYPE.CREATE_VNF, nf_inst_id)
+    JobUtil.add_job_status(job_id, 0, 'create vnf record in database.', 0)
+    return nf_inst_id, job_id
+
+
+class CreateVnfs(Thread):
+    def __init__(self, data, nf_inst_id, job_id):
+        super(CreateVnfs, self).__init__()
+        self.data = data
+        self.nf_inst_id = nf_inst_id
+        self.job_id = job_id
+        self.ns_inst_id = ''
+        self.vnf_id = ''
+        self.vnfd_id = ''
+        self.ns_inst_name = ''
+        self.nsd_model = ''
+        self.vnfd_model = ''
+        self.vnf_inst_name = ''
+        self.vnfm_inst_id = ''
+        self.inputs = ''
+        self.nf_package_info = ''
+        self.vnfm_nf_inst_id = ''
+        self.vnfm_job_id = ''
+        self.vnfm_inst_name = ''
+        self.vim_id = ''
+
+    def run(self):
+        try:
+            self.get_params()
+            self.check_nf_name_exist()
+            self.get_vnfd_id()
+            self.check_nf_package_valid()
+            self.send_nf_init_request_to_vnfm()
+            self.send_get_vnfm_request_to_extsys()
+            self.send_create_vnf_request_to_resmgr()
+            self.wait_vnfm_job_finish()
+            self.write_vnf_creation_info()
+            self.save_info_to_db()
+        except NSLCMException as e:
+            self.vnf_inst_failed_handle(e.message)
+        except Exception:
+            logger.error(traceback.format_exc())
+            self.vnf_inst_failed_handle('unexpected exception')
+
+    def get_params(self):
+        self.ns_inst_id = self.data['ns_instance_id']
+        vnf_index = int(float(self.data['vnf_index'])) - 1
+        additional_vnf_info = self.data['additional_param_for_vnf'][vnf_index]
+        self.vnf_id = ignore_case_get(additional_vnf_info, 'vnfProfileId')
+        additional_param = ignore_case_get(additional_vnf_info, 'additionalParam')
+        self.vnfm_inst_id = ignore_case_get(additional_param, 'vnfmInstanceId')
+        para = ignore_case_get(additional_param, 'inputs')
+        self.inputs = json.loads(para) if isinstance(para, (str, unicode)) else para
+        self.vim_id = ignore_case_get(additional_param, 'vimId')
+        self.vnfd_id = ignore_case_get(additional_param, 'vnfdId')
+
+    def check_nf_name_exist(self):
+        is_exist = NfInstModel.objects.filter(nf_name=self.vnf_inst_name).exists()
+        if is_exist:
+            logger.error('The name of NF instance already exists.')
+            raise NSLCMException('The name of NF instance already exists.')
+
+    def get_vnfd_id(self):
+        if self.vnfd_id:
+            logger.debug("need not get vnfd_id")
+            self.nsd_model={'vnfs': [], 'vls': [], 'vnffgs': []}
+            self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
+            self.vnf_inst_name = self.vnf_inst_name[:30]
+            return
+        ns_inst_info = NSInstModel.objects.get(id=self.ns_inst_id)
+        self.ns_inst_name = ns_inst_info.name
+        self.nsd_model = json.loads(ns_inst_info.nsd_model)
+        for vnf_info in self.nsd_model['vnfs']:
+            if self.vnf_id == vnf_info['vnf_id']:
+                self.vnfd_id = vnf_info['properties']['id']
+                if 'name' not in vnf_info['properties']:
+                    self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
+                else:
+                    self.vnf_inst_name = vnf_info['properties']['name'] + str(uuid.uuid4())
+                self.vnf_inst_name = self.vnf_inst_name[:30]
+                return
+        logger.error('Can not found vnf in nsd model')
+        raise NSLCMException('Can not found vnf in nsd model')
+
+    def check_nf_package_valid(self):
+        nf_package_info = NfPackageModel.objects.filter(vnfdid=self.vnfd_id)
+        if not nf_package_info:
+            logger.info('NF package not exist.')
+            raise NSLCMException('NF package not exist.')
+        self.nf_package_info = nf_package_info[0]
+        self.vnfd_model = json.loads(self.nf_package_info.vnfdmodel)
+
+    def get_virtual_link_info(self, vnf_id):
+        virtual_link_list, ext_virtual_link = [], []
+        for vnf_info in self.nsd_model['vnfs']:
+            if vnf_info['vnf_id'] != vnf_id:
+                continue
+            for network_info in vnf_info['networks']:
+                vl_instance = VLInstModel.objects.get(
+                    vldid=network_info['vl_id'], 
+                    ownertype=OWNER_TYPE.NS,
+                    ownerid=self.ns_inst_id)
+                vl_instance_id = vl_instance.vlinstanceid
+                network_name, subnet_name = self.get_network_info_of_vl(network_info['vl_id'])
+                virtual_link_list.append({
+                    'network_name': network_name, 
+                    'key_name': network_info['key_name'],
+                    'subnetwork_name': subnet_name, 
+                    'vl_instance_id': vl_instance_id
+                })
+                ext_virtual_link.append({
+                    "vlInstanceId": vl_instance_id,
+                    "resourceId": vl_instance.relatednetworkid,
+                    "resourceSubnetId": vl_instance.relatedsubnetworkid,
+                    "cpdId": self.get_cpd_id_of_vl(network_info['key_name']),
+                    "vim": {
+                        "vimid": vl_instance.vimid
+                    }
+                })
+        return virtual_link_list, ext_virtual_link
+
+    def get_cpd_id_of_vl(self, vl_key):
+        for cpd in self.vnfd_model["vnf_exposed"]["external_cps"]:
+            if vl_key == cpd["key_name"]:
+                return cpd["cpd_id"]
+        return ""
+
+    def get_network_info_of_vl(self, vl_id):
+        for vnf_info in self.nsd_model['vls']:
+            if vnf_info['vl_id'] == vl_id:
+                return vnf_info['properties']['network_name'], vnf_info['properties']['name']
+        return '', ''
+
+    def send_nf_init_request_to_vnfm(self):
+        virtual_link_list, ext_virtual_link = self.get_virtual_link_info(self.vnf_id)
+        req_param = json.JSONEncoder().encode({
+            'vnfInstanceName': self.vnf_inst_name, 
+            'vnfPackageId': self.nf_package_info.nfpackageid, 
+            'vnfDescriptorId': self.vnfd_id,
+            'extVirtualLink': ext_virtual_link,
+            'additionalParam': {"inputs": self.inputs, 
+                "vimId": self.vim_id,
+                "extVirtualLinks": virtual_link_list}})
+        rsp = send_nf_init_request(self.vnfm_inst_id, req_param)
+        self.vnfm_job_id = ignore_case_get(rsp, 'jobId')
+        self.vnfm_nf_inst_id = ignore_case_get(rsp, 'vnfInstanceId')
+
+        NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
+            mnfinstid=self.vnfm_nf_inst_id,
+            nf_name=self.vnf_inst_name,
+            vnf_id=self.vnf_id,
+            package_id=self.nf_package_info.nfpackageid,
+            vnfm_inst_id=self.vnfm_inst_id,
+            ns_inst_id=self.ns_inst_id,
+            version=self.nf_package_info.vnfversion,
+            vendor=self.nf_package_info.vendor,
+            vnfd_model=self.vnfd_model,
+            input_params=json.JSONEncoder().encode(self.inputs),
+            lastuptime=now_time())
+
+    def send_get_vnfm_request_to_extsys(self):
+        resp_body = get_vnfm_by_id(self.vnfm_inst_id)
+        self.vnfm_inst_name = ignore_case_get(resp_body, 'name')
+
+    def send_create_vnf_request_to_resmgr(self):
+        pkg_vnfd = json.loads(self.nf_package_info.vnfdmodel)
+        data = {
+            'nf_inst_id': self.nf_inst_id,
+            'vnfm_nf_inst_id': self.vnfm_nf_inst_id,
+            'vnf_inst_name': self.vnf_inst_name,
+            'ns_inst_id': self.ns_inst_id,
+            'ns_inst_name': self.ns_inst_name,
+            'nf_inst_name': self.vnf_inst_name,
+            'vnfm_inst_id': self.vnfm_inst_id,
+            'vnfm_inst_name': self.vnfm_inst_name,
+            'vnfd_name': pkg_vnfd['metadata'].get('name', 'undefined'),
+            'vnfd_id': self.vnfd_id,
+            'job_id': self.job_id,
+            'nf_inst_status': VNF_STATUS.INSTANTIATING,
+            'vnf_type': pkg_vnfd['metadata'].get('vnf_type', 'undefined'),
+            'nf_package_id': self.nf_package_info.nfpackageid}
+        create_vnf(data)
+
+    def wait_vnfm_job_finish(self):
+        ret = wait_job_finish(vnfm_id=self.vnfm_inst_id, vnfo_job_id=self.job_id, 
+            vnfm_job_id=self.vnfm_job_id, progress_range=[10, 90],
+            timeout=NFVO_VNF_INST_TIMEOUT_SECOND)
+
+        if ret != JOB_MODEL_STATUS.FINISHED:
+            logger.error('VNF instantiation failed on VNFM side.')
+            raise NSLCMException('VNF instantiation failed on VNFM side.')
+
+    def write_vnf_creation_info(self):
+        logger.debug("write_vnf_creation_info start")
+        vm_inst_infos = VmInstModel.objects.filter(insttype=INST_TYPE.VNF, instid=self.nf_inst_id)
+        data = {
+            'nf_inst_id': self.nf_inst_id,
+            'ns_inst_id': self.ns_inst_id,
+            'vnfm_inst_id': self.vnfm_inst_id,
+            'vms': [{'vmId': vm_inst_info.resouceid, 'vmName': vm_inst_info.vmname, 'vmStatus': 'ACTIVE'} for
+                    vm_inst_info in vm_inst_infos]}
+        create_vnf_creation_info(data)
+        logger.debug("write_vnf_creation_info end")
+
+    def save_info_to_db(self):
+        logger.debug("save_info_to_db start")
+        do_biz_with_share_lock("set-vnflist-in-vnffginst-%s" % self.ns_inst_id, self.save_vnf_inst_id_in_vnffg)
+        NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.ACTIVE, lastuptime=now_time())
+        JobUtil.add_job_status(self.job_id, 100, 'vnf instantiation success', 0)
+        logger.debug("save_info_to_db end")
+
+    def vnf_inst_failed_handle(self, error_msg):
+        logger.error('VNF instantiation failed, detail message: %s' % error_msg)
+        NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.FAILED,
+                                                                    lastuptime=now_time())
+        JobUtil.add_job_status(self.job_id, 255, 'VNF instantiation failed, detail message: %s' % error_msg, 0)
+
+    def save_vnf_inst_id_in_vnffg(self):
+        vnffgs = self.nsd_model['vnffgs']
+        for vnffg in vnffgs:
+            if self.vnf_id not in vnffg['members']:
+                continue
+            vnffg_inst_infos = VNFFGInstModel.objects.filter(vnffgdid=vnffg['vnffg_Id'], nsinstid=self.ns_inst_id)
+            if not vnffg_inst_infos:
+                logger.error('Vnffg instance not exist.')
+                raise NSLCMException('Vnffg instance not exist.')
+            vnf_list = vnffg_inst_infos[0].vnflist
+            vnffg_inst_infos.update(vnf_list=vnf_list + ',' + self.nf_inst_id if vnf_list else self.nf_inst_id)
diff --git a/lcm/ns/vnfs/get_vnfs.py b/lcm/ns/vnfs/get_vnfs.py
new file mode 100644 (file)
index 0000000..0ca8e66
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2016 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 NfInstModel
+
+
+class GetVnf(object):
+    def __init__(self, nf_inst_id):
+        self.nf_inst_id = nf_inst_id
+
+    def do_biz(self):
+        nf_inst_info = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
+        return nf_inst_info
diff --git a/lcm/ns/vnfs/grant_vnfs.py b/lcm/ns/vnfs/grant_vnfs.py
new file mode 100644 (file)
index 0000000..c93647f
--- /dev/null
@@ -0,0 +1,125 @@
+# Copyright 2016 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 json
+
+from lcm.pub.msapi import resmgr
+from lcm.pub.database.models import NfPackageModel, NfInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.values import ignore_case_get
+
+logger = logging.getLogger(__name__)
+
+
+class GrantVnfs(object):
+    def __init__(self, data, job_id):
+        self.job_id = job_id
+        self.vnfm_inst_id = ''
+        self.vnf_uuid = ''
+        self.vnfm_job_id = ''
+        self.data = data
+
+    def send_grant_vnf_to_resMgr(self):
+        logger.debug("grant data from vnfm:%s", self.data)
+        if isinstance(self.data, (unicode, str)):
+            self.data = json.JSONDecoder().decode(self.data)
+        has_res_tpl = False
+        grant_type = None
+        if ignore_case_get(self.data, "addResource"):
+            grant_type = "addResource"
+        elif ignore_case_get(self.data, "removeResource"):
+            grant_type = "removeResource"
+        else:
+            #raise NSLCMException("No grant resource is found.")
+            has_res_tpl = True
+
+        for res in ignore_case_get(self.data, grant_type):
+            if "resourceTemplate" in res:
+                has_res_tpl = True
+                break
+
+        if not has_res_tpl:
+            m_vnf_inst_id = ignore_case_get(self.data, "vnfInstanceId")
+            additional_param = ignore_case_get(self.data, "additionalparam")
+            vnfm_inst_id = ignore_case_get(additional_param, "vnfmid")
+            vim_id = ignore_case_get(additional_param, "vimid")
+
+            vnfinsts = NfInstModel.objects.filter(
+                mnfinstid=m_vnf_inst_id, vnfm_inst_id=vnfm_inst_id)
+            if not vnfinsts:
+                raise NSLCMException("Vnfinst(%s) is not found in vnfm(%s)" % (
+                    m_vnf_inst_id, vnfm_inst_id))
+                
+            vnf_pkg_id = vnfinsts[0].package_id
+            vnf_pkgs = NfPackageModel.objects.filter(nfpackageid=vnf_pkg_id)
+            if not vnf_pkgs:
+                raise NSLCMException("vnfpkg(%s) is not found" % vnf_pkg_id)
+
+            vnfd = json.JSONDecoder().decode(vnf_pkgs[0].vnfdmodel)
+
+            req_param = {
+                "vnfInstanceId": m_vnf_inst_id, 
+                "vimId": vim_id, 
+                "additionalParam": additional_param,
+                grant_type: []
+            }
+            for res in ignore_case_get(self.data, grant_type):
+                vdu_name = ignore_case_get(res, "vdu")
+                grant_res = {
+                    "resourceDefinitionId": ignore_case_get(res, "resourceDefinitionId"),
+                    "type": ignore_case_get(res,"type"),
+                    "vdu": vdu_name
+                }
+                for vdu in vnfd["vdus"]:
+                    if vdu_name in (vdu["vdu_id"], vdu["properties"].get("name", "")):
+                        grant_res["resourceTemplate"] = self.get_res_tpl(vdu, vnfd)
+                        break
+                req_param[grant_type].append(grant_res)
+            self.data = req_param
+        return resmgr.grant_vnf(self.data)
+
+    def get_res_tpl(self, vdu, vnfd):
+        storage_size = 0
+        for storage_id in vdu["local_storages"]:
+            storage_size = storage_size + self.get_storage_size(storage_id, vnfd)
+        resourceTemplate = {
+            "virtualComputeDescriptor": {
+                "virtualCpu": {
+                    "numVirtualCpu": int(vdu["nfv_compute"]["num_cpus"])
+                },
+                "virtualMemory": {
+                    "virtualMemSize": int(vdu["nfv_compute"]["mem_size"]) 
+                }
+            },
+            "virtualStorageDescriptor": {
+                "typeOfStorage": "",
+                "sizeOfStorage": storage_size,
+                "swImageDescriptor": ""
+            }
+        }
+        return resourceTemplate
+
+    def get_storage_size(self, storage_id, vnfd):
+        for storage in vnfd["local_storages"]:
+            if storage_id == storage["local_storage_id"]:
+                return int(storage["properties"]["size"])
+        return 0
+
+
+
+
+
+
+
diff --git a/lcm/ns/vnfs/notify_lcm.py b/lcm/ns/vnfs/notify_lcm.py
new file mode 100644 (file)
index 0000000..6342f7a
--- /dev/null
@@ -0,0 +1,172 @@
+# Copyright 2016 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 logging
+import traceback
+
+from rest_framework import status
+from rest_framework.response import Response
+from lcm.ns.vnfs.const import INST_TYPE
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.database.models import VNFCInstModel, VLInstModel, NfInstModel, PortInstModel, CPInstModel, VmInstModel
+from lcm.pub.utils.values import ignore_case_get
+
+
+logger = logging.getLogger(__name__)
+
+
+class NotifyLcm(object):
+    def __init__(self, vnfmid, vnfInstanceId, data):
+        logger.debug("[Notify LCM] vnfmid=%s, vnfInstanceId=%s, data=%s" % (vnfmid, vnfInstanceId, data))
+        self.vnf_instid = ''
+        self.vnfmid = vnfmid
+        self.m_vnfInstanceId = vnfInstanceId
+        self.status = ignore_case_get(data, 'status')
+        self.operation = ignore_case_get(data, 'operation')
+        self.lcm_jobid = ignore_case_get(data, 'jobId')
+        self.vnfdmodule = ignore_case_get(data, 'vnfdmodule')
+        self.affectedVnfc = ignore_case_get(data, 'affectedVnfc')
+        self.affectedVl = ignore_case_get(data, 'affectedVl')
+        self.affectedCp = ignore_case_get(data, 'affectedCp')
+        self.affectedVirtualStorage = ignore_case_get(data, 'affectedVirtualStorage')
+
+    def do_biz(self):
+        try:
+            self.vnf_instid = self.get_vnfinstid(self.m_vnfInstanceId, self.vnfmid)
+            self.update_Vnfc()
+            self.update_Vl()
+            self.update_Cp()
+            self.update_Storage()
+            #self.update_vnf_by_vnfdmodule()
+            logger.debug("notify lcm end")
+        except NSLCMException as e:
+            self.exception(e.message)
+        except Exception:
+            logger.error(traceback.format_exc())
+            self.exception('unexpected exception')
+
+    def get_vnfinstid(self, mnfinstid, vnfm_inst_id):
+        nfinst = NfInstModel.objects.filter(mnfinstid=mnfinstid, vnfm_inst_id=vnfm_inst_id).first()
+        if nfinst:
+            return nfinst.nfinstid
+        else:
+            self.exception('vnfinstid not exist')
+
+    def exception(self, error_msg):
+        logger.error('Notify Lcm failed, detail message: %s' % error_msg)
+        return Response(data={'error': '%s' % error_msg}, status=status.HTTP_409_CONFLICT)
+
+    def update_Vnfc(self):
+        for vnfc in self.affectedVnfc:
+            vnfcInstanceId = ignore_case_get(vnfc, 'vnfcInstanceId')
+            vduId = ignore_case_get(vnfc, 'vduId')
+            changeType = ignore_case_get(vnfc, 'changeType')
+            vimId = ignore_case_get(vnfc, 'vimid')
+            vmId = ignore_case_get(vnfc, 'vmid')
+            vmName = ignore_case_get(vnfc, 'vmname')
+            # resourceType = ignore_case_get(vmResource, 'resourceType')
+            # resourceId = ignore_case_get(vmId, 'resourceId')
+
+
+            # if resourceType != 'vm':
+            #     self.exception('affectedVnfc struct error: resourceType not euqal vm')
+
+            if changeType == 'added':
+                VNFCInstModel(vnfcinstanceid=vnfcInstanceId, vduid=vduId,
+                              nfinstid=self.vnf_instid, vmid=vmId).save()
+                VmInstModel(vmid=vmId, vimid=vimId, resouceid=vmId, insttype=INST_TYPE.VNF,
+                            instid=self.vnf_instid, vmname=vmName, hostid='1').save()
+            elif changeType == 'removed':
+                VNFCInstModel.objects.filter(vnfcinstanceid=vnfcInstanceId).delete()
+            elif changeType == 'modified':
+                VNFCInstModel.objects.filter(vnfcinstanceid=vnfcInstanceId).update(vduid=vduId,
+                                                                                   nfinstid=self.vnf_instid,
+                                                                                   vmid=vmId)
+            else:
+                self.exception('affectedVnfc struct error: changeType not in {added,removed,modified}')
+
+    def update_Vl(self):
+        for vl in self.affectedVl:
+            vlInstanceId = ignore_case_get(vl, 'vlInstanceId')
+            vldid = ignore_case_get(vl, 'vldid')
+            changeType = ignore_case_get(vl, 'changeType')
+            networkResource = ignore_case_get(vl, 'networkResource')
+            resourceType = ignore_case_get(networkResource, 'resourceType')
+            resourceId = ignore_case_get(networkResource, 'resourceId')
+
+            if resourceType != 'network':
+                self.exception('affectedVl struct error: resourceType not euqal network')
+
+            ownerId = self.vnf_instid
+            ownerId = self.get_vnfinstid(self.vnf_instid, self.vnfmid)
+
+            if changeType == 'added':
+                VLInstModel(vlInstanceId=vlInstanceId, vldId=vldid, ownerType=0, ownerId=ownerId,
+                            relatedNetworkId=resourceId, vlType=0).save()
+            elif changeType == 'removed':
+                VLInstModel.objects.filter(vlInstanceId=vlInstanceId).delete()
+            elif changeType == 'modified':
+                VLInstModel.objects.filter(vlInstanceId=vlInstanceId)\
+                    .update(vldId=vldid, ownerType=0, ownerId=ownerId, relatedNetworkId=resourceId, vlType=0)
+            else:
+                self.exception('affectedVl struct error: changeType not in {added,removed,modified}')
+
+    def update_Cp(self):
+        for cp in self.affectedCp:
+            virtualLinkInstanceId = ignore_case_get(cp, 'virtualLinkInstanceId')
+            #ownerid = ignore_case_get(cp, 'ownerid')
+            ownertype = ignore_case_get(cp, 'ownertype')
+            if not ownertype:
+                ownertype = 0
+            ownerid = self.vnf_instid if str(ownertype) == "0" else ignore_case_get(cp, 'ownerid')
+            cpInstanceId = ignore_case_get(cp, 'cpinstanceid')
+            cpdId = ignore_case_get(cp, 'cpdid')
+            changeType = ignore_case_get(cp, 'changetype')
+            relatedportId = ''
+            portResource = ignore_case_get(cp, 'portResource')
+            if portResource:
+                vimId = ignore_case_get(portResource, 'vimid')
+                resourceId = ignore_case_get(portResource, 'resourceid')
+                resourceName = ignore_case_get(portResource, 'resourceName')
+                tenant = ignore_case_get(portResource, 'tenant')
+                ipAddress = ignore_case_get(portResource, 'ipAddress')
+                macAddress = ignore_case_get(portResource, 'macAddress')
+                sfcEncapsulation = ignore_case_get(portResource, 'sfcEncapsulation')
+                instId = ignore_case_get(portResource, 'instId')
+                portid = str(uuid.uuid4())
+                PortInstModel(portid=portid, networkid='unknown', subnetworkid='unknown', vimid=vimId,
+                              resourceid=resourceId, name=resourceName, instid=instId, cpinstanceid=cpInstanceId,
+                              bandwidth='unknown', operationalstate='active', ipaddress=ipAddress, macaddress=macAddress,
+                              floatipaddress='unknown', serviceipaddress='unknown', typevirtualnic='unknown',
+                              sfcencapsulation='gre', direction='unknown', tenant=tenant).save()
+                relatedportId = portid
+
+            if changeType == 'added':
+                CPInstModel(cpinstanceid=cpInstanceId, cpdid=cpdId, ownertype=ownertype, ownerid=ownerid,
+                            relatedtype=2, relatedport=relatedportId, status='active').save()
+            elif changeType == 'removed':
+                CPInstModel.objects.filter(cpinstanceid=cpInstanceId).delete()
+            elif changeType == 'changed':
+                CPInstModel.objects.filter(cpinstanceid=cpInstanceId).update(cpdid=cpdId, ownertype=ownertype,
+                                                                             ownerid=ownerid,
+                                                                             vlinstanceid=virtualLinkInstanceId,
+                                                                             relatedtype=2, relatedport=relatedportId)
+            else:
+                self.exception('affectedVl struct error: changeType not in {added,removed,modified}')
+
+    def update_Storage(self):
+        pass
+
+    def update_vnf_by_vnfdmodule(self):
+        NfInstModel.objects.filter(nfinstid=self.vnf_instid).update(vnfd_model=self.vnfdmodule)
diff --git a/lcm/ns/vnfs/scale_vnfs.py b/lcm/ns/vnfs/scale_vnfs.py
new file mode 100644 (file)
index 0000000..fb4f2be
--- /dev/null
@@ -0,0 +1,105 @@
+# Copyright 2017 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
+import threading
+import traceback
+
+from lcm.ns.vnfs.const import VNF_STATUS
+from lcm.ns.vnfs.wait_job import wait_job_finish
+from lcm.pub.database.models import NfInstModel
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi.vnfmdriver import send_nf_scaling_request
+from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE, JOB_MODEL_STATUS
+from lcm.pub.utils.values import ignore_case_get
+
+JOB_ERROR = 255
+SCALE_TYPE = ("SCALE_OUT", "SCALE_IN")
+logger = logging.getLogger(__name__)
+
+
+class NFManualScaleService(threading.Thread):
+    def __init__(self, vnf_instance_id, data):
+        super(NFManualScaleService, self).__init__()
+        self.vnf_instance_id = vnf_instance_id
+        self.data = data
+        self.job_id = JobUtil.create_job("NF", JOB_TYPE.MANUAL_SCALE_VNF, vnf_instance_id)
+        self.scale_vnf_data = ''
+        self.nf_model = {}
+        self.nf_scale_params = []
+        self.m_nf_inst_id = ''
+        self.vnfm_inst_id = ''
+
+    def run(self):
+        try:
+            self.do_biz()
+        except NSLCMException as e:
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, 'nf scale fail')
+        finally:
+            self.update_nf_status()
+
+    def do_biz(self):
+        self.update_job(1, desc='nf scale start')
+        self.update_nf_status(VNF_STATUS.SCALING)
+        self.get_and_check_params()
+        self.send_nf_scaling_requests()
+        self.update_job(100, desc='nf scale success')
+
+    def get_and_check_params(self):
+        nf_info = NfInstModel.objects.filter(nfinstid=self.vnf_instance_id)
+        if not nf_info:
+            logger.error('NF instance[id=%s] does not exist' % self.vnf_instance_id)
+            raise NSLCMException('NF instance[id=%s] does not exist' % self.vnf_instance_id)
+        logger.debug('vnfd_model = %s, vnf_instance_id = %s' % (nf_info[0].vnfd_model, self.vnf_instance_id))
+        self.nf_model = json.loads(nf_info[0].vnfd_model)
+        self.m_nf_inst_id = nf_info[0].mnfinstid
+        self.vnfm_inst_id = nf_info[0].vnfm_inst_id
+        self.scale_vnf_data = ignore_case_get(self.data, 'scaleVnfData')
+        if not self.scale_vnf_data:
+            logger.error('scaleVnfData parameter does not exist or value incorrect')
+            raise NSLCMException('scaleVnfData parameter does not exist or value incorrect')
+        for vnf_data in self.scale_vnf_data:
+            scale_type = ignore_case_get(vnf_data, 'type')
+            aspect_id = ignore_case_get(vnf_data, 'aspectId')
+            number_of_steps = ignore_case_get(vnf_data, 'numberOfSteps')
+            self.nf_scale_params.append({
+                'type': scale_type,
+                'aspectId': aspect_id,
+                'numberOfSteps': number_of_steps,
+                'additionalParam': {'vnfdModel': self.nf_model}
+            })
+
+    def send_nf_scaling_requests(self):
+        for i in range(len(self.nf_scale_params)):
+            progress_range = [10 + 80 / len(self.nf_scale_params) * i, 10 + 80 / len(self.nf_scale_params) * (i + 1)]
+            self.send_nf_scaling_request(self.nf_scale_params[i], progress_range)
+
+    def send_nf_scaling_request(self, scale_param, progress_range):
+        req_param = json.JSONEncoder().encode(scale_param)
+        rsp = send_nf_scaling_request(self.vnfm_inst_id, self.m_nf_inst_id, req_param)
+        vnfm_job_id = ignore_case_get(rsp, 'jobId')
+        ret = wait_job_finish(self.vnfm_inst_id, self.job_id, vnfm_job_id, progress_range=progress_range, timeout=1200,
+                              mode='1')
+        if ret != JOB_MODEL_STATUS.FINISHED:
+            logger.error('[NF scale] nf scale failed')
+            raise NSLCMException("nf scale failed")
+
+    def update_nf_status(self, status=VNF_STATUS.ACTIVE):
+        NfInstModel.objects.filter(nfinstid=self.vnf_instance_id).update(status=status)
+
+    def update_job(self, progress, desc=''):
+        JobUtil.add_job_status(self.job_id, progress, desc)
\ No newline at end of file
diff --git a/lcm/ns/vnfs/terminate_nfs.py b/lcm/ns/vnfs/terminate_nfs.py
new file mode 100644 (file)
index 0000000..7b0b21b
--- /dev/null
@@ -0,0 +1,125 @@
+# Copyright 2016 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
+import json
+
+import threading
+
+from lcm.ns.vnfs.wait_job import wait_job_finish
+from lcm.pub.database.models import NfInstModel
+from lcm.ns.vnfs.const import VNF_STATUS, NFVO_VNF_INST_TIMEOUT_SECOND
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi.vnfmdriver import send_nf_terminate_request
+from lcm.pub.msapi import resmgr
+
+logger = logging.getLogger(__name__)
+
+
+class TerminateVnfs(threading.Thread):
+    def __init__(self, data, vnf_inst_id, job_id):
+        threading.Thread.__init__(self)
+        self.vnf_inst_id = vnf_inst_id
+        self.job_id = job_id
+        self.vnfm_inst_id = ''
+        self.vnf_uuid = ''
+        self.vnfm_job_id = ''
+        self.terminationType = data['terminationType']
+        self.gracefulTerminationTimeout = data['gracefulTerminationTimeout']
+        self.initdata()
+
+    def run(self):
+        try:
+            self.check_nf_valid()
+            self.send_nf_terminate_to_vnfmDriver()
+            self.wait_vnfm_job_finish()
+            self.send_terminate_vnf_to_resMgr()
+            self.delete_data_from_db()
+        except NSLCMException as e:
+            self.exception(e.message)
+        except Exception:
+            logger.error(traceback.format_exc())
+            self.exception('unexpected exception')
+
+    def set_vnf_status(self, vnf_inst_info):
+        vnf_status = vnf_inst_info.status
+        if (vnf_status == VNF_STATUS.TERMINATING):
+            logger.info('[VNF terminate] VNF is dealing by other application,try again later.')
+            raise NSLCMException('[VNF terminate] VNF is dealing by other application,try again later.')
+        else:
+            vnf_inst_info.status = VNF_STATUS.TERMINATING
+            vnf_inst_info.save()
+
+    def check_vnf_is_exist(self):
+        vnf_inst = NfInstModel.objects.filter(nfinstid=self.vnf_inst_id)
+        if not vnf_inst.exists():
+            logger.warning('[VNF terminate] Vnf terminate [%s] is not exist.' % self.vnf_inst_id)
+            return None
+        return vnf_inst[0]
+
+    def add_progress(self, progress, status_decs, error_code=""):
+        JobUtil.add_job_status(self.job_id, progress, status_decs, error_code)
+
+    def initdata(self):
+        vnf_inst_info = self.check_vnf_is_exist()
+        if not vnf_inst_info:
+            self.add_progress(100, "TERM_VNF_NOT_EXIST_SUCCESS", "finished")
+        self.add_progress(2, "GET_VNF_INST_SUCCESS")
+        self.vnfm_inst_id = vnf_inst_info.vnfm_inst_id
+        self.vnf_uuid = vnf_inst_info.mnfinstid
+        if not self.vnf_uuid:
+            self.add_progress(100, "TERM_VNF_NOT_EXIST_SUCCESS", "finished")
+
+    def check_nf_valid(self):
+        vnf_inst = NfInstModel.objects.filter(nfinstid=self.vnf_inst_id)
+        if not vnf_inst.exists():
+            logger.warning('[VNF terminate] Vnf instance [%s] is not exist.' % self.vnf_inst_id)
+            raise NSLCMException('[VNF terminate] Vnf instance is not exist.')
+        if not vnf_inst:
+            self.add_progress(100, "TERM_VNF_NOT_EXIST_SUCCESS", "finished")
+            raise NSLCMException('[VNF terminate] Vnf instance is not exist.')
+        self.set_vnf_status(vnf_inst[0])
+
+    def exception(self, error_msg):
+        logger.error('VNF Terminate failed, detail message: %s' % error_msg)
+        NfInstModel.objects.filter(nfinstid=self.vnf_inst_id).update(status=VNF_STATUS.FAILED)
+        JobUtil.add_job_status(self.job_id, 255, 'VNF Terminate failed, detail message: %s' % error_msg, 0)
+
+    def send_nf_terminate_to_vnfmDriver(self):
+        req_param = json.JSONEncoder().encode({
+            'terminationType': self.terminationType, 
+            'gracefulTerminationTimeout': self.gracefulTerminationTimeout})
+        rsp = send_nf_terminate_request(self.vnfm_inst_id, self.vnf_uuid, req_param)
+        self.vnfm_job_id = ignore_case_get(rsp, 'jobId')
+
+    def send_terminate_vnf_to_resMgr(self):
+        resmgr.terminate_vnf(self.vnf_inst_id)
+
+    def wait_vnfm_job_finish(self):
+        if not self.vnfm_job_id:
+            logger.warn("No Job, need not wait")
+            return
+        ret = wait_job_finish(vnfm_id=self.vnfm_inst_id, vnfo_job_id=self.job_id, 
+            vnfm_job_id=self.vnfm_job_id, progress_range=[10, 90],
+            timeout=NFVO_VNF_INST_TIMEOUT_SECOND)
+
+        if ret != JOB_MODEL_STATUS.FINISHED:
+            logger.error('VNF terminate failed on VNFM side.')
+            raise NSLCMException('VNF terminate failed on VNFM side.')
+
+    def delete_data_from_db(self):
+        NfInstModel.objects.filter(nfinstid=self.vnf_inst_id).delete()
+        JobUtil.add_job_status(self.job_id, 100, 'vnf terminate success', 0)
diff --git a/lcm/ns/vnfs/urls.py b/lcm/ns/vnfs/urls.py
new file mode 100644 (file)
index 0000000..4ab427b
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2016-2017 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 patterns, url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from lcm.ns.vnfs.views import NfView, NfDetailView, NfGrant, LcmNotify, NfScaleView, NfVerifyView
+
+urlpatterns = patterns('',
+                       url(r'^openoapi/nslcm/v1/ns/vnfs$', NfView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/vnfs/(?P<vnfinstid>[0-9a-zA-Z_-]+)$', NfDetailView.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/grantvnf$', NfGrant.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/(?P<vnfmid>[0-9a-zA-Z_-]+)'
+                           r'/vnfs/(?P<vnfInstanceId>[0-9a-zA-Z_-]+)/Notify$',
+                           LcmNotify.as_view()),
+                       url(r'^openoapi/nslcm/v1/ns/vnfs/(?P<vnfinstid>[0-9a-zA-Z_-]+)/scaling$', NfScaleView.as_view()),
+                       url(r'^openoapi/nslcm/v1/vnfonboarding$', NfVerifyView.as_view()),
+                       )
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns/vnfs/verify_vnfs.py b/lcm/ns/vnfs/verify_vnfs.py
new file mode 100644 (file)
index 0000000..e40e27a
--- /dev/null
@@ -0,0 +1,218 @@
+# Copyright 2017 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
+import os
+import threading
+import traceback
+import time
+
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE, JOB_MODEL_STATUS
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.utils.restcall import req_by_msb
+
+logger = logging.getLogger(__name__)
+
+JOB_ERROR = 255
+
+class VerifyVnfs(threading.Thread):
+    def __init__(self, data, job_id):
+        super(VerifyVnfs, self).__init__()
+        self.data = data
+        self.job_id = job_id
+        self.vnf_inst_id = ''
+        self.verify_ok = False
+        self.verify_config = ''
+
+    def run(self):
+        try:
+            self.verify_config = self.load_config()
+            JobUtil.create_job("VNF", JOB_TYPE.CREATE_VNF, self.job_id, 'vnfsdk', self.job_id)
+            self.do_on_boarding()
+            self.do_inst_vnf()
+            self.do_func_test()
+            self.verify_ok = True
+        except NSLCMException as e:
+            self.update_job(JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            self.update_job(JOB_ERROR, 'Unknown error in vnf verify.')
+        finally:
+            logger.warn("Ignore terminate vnf operation")
+            if self.verify_ok:
+                self.update_job(100, "Ignore terminate vnf operation.")
+            #self.do_term_vnf()
+
+    def do_on_boarding(self):
+        self.update_job(10, "Start vnf on boarding.")
+        onboarding_data = {
+            "csarId":self.data["PackageID"],
+            "labVimId":ignore_case_get(self.verify_config, "labVimId")
+        }
+        ret = req_by_msb("/openoapi/nslcm/v1/vnfpackage", "POST", json.JSONEncoder().encode(onboarding_data))
+        if ret[0] != 0:
+            raise NSLCMException("Failed to call vnf onboarding: %s" % ret[1])
+        rsp_data = json.JSONDecoder().decode(ret[1])
+        if not self.wait_until_job_done(rsp_data["jobId"], 15):
+            raise NSLCMException("Vnf onboarding failed")
+        self.update_job(20, "Vnf on boarding success.")
+        
+    def do_inst_vnf(self):
+        self.update_job(30, "Start inst vnf.")
+        vnf_param = ignore_case_get(self.verify_config, "additionalParamForVnf")
+        if vnf_param and "additionalParam" in vnf_param[0]:
+            vnf_param[0]["additionalParam"]["vimId"] = ignore_case_get(self.verify_config, "lab_vim_id")
+        inst_data = {
+            "nsInstanceId": "",
+            "additionalParamForVnf": vnf_param,
+            "vnfIndex": "1"
+        }
+        ret = req_by_msb("/openoapi/nslcm/v1/ns/vnfs", "POST", json.JSONEncoder().encode(inst_data))
+        if ret[0] != 0:
+            raise NSLCMException("Failed to call inst vnf: %s" % ret[1])
+        rsp_data = json.JSONDecoder().decode(ret[1])
+        self.vnf_inst_id = rsp_data["vnfInstId"]
+        if not self.wait_until_job_done(rsp_data["jobId"], 40):
+            raise NSLCMException("Vnf(%s) inst failed" % self.vnf_inst_id)
+        self.update_job(50, "Inst vnf success.")
+        
+    def do_func_test(self):
+        self.update_job(60, "Start vnf function test.")
+        func_data = {"PackageID":self.data["PackageID"]}
+        ret = req_by_msb("/openapi/vnfsdk/v1/functest/taskmanager/testtasks", "POST", json.JSONEncoder().encode(func_data))
+        if ret[0] != 0:
+            raise NSLCMException("Failed to call func test: %s" % ret[1])
+        rsp_data = json.JSONDecoder().decode(ret[1])
+
+        if not self.wait_func_test_job_done(rsp_data["TaskID"], 40):
+            raise NSLCMException("Func test failed")
+        logger.info("Query(%s) job success.", rsp_data["TaskID"])
+
+        ret = req_by_msb("/openapi/vnfsdk/v1/functest/taskmanager/testtasks/%s/result" % rsp_data["TaskID"], "GET")
+        if ret[0] != 0:
+            raise NSLCMException("Failed to get func test result: %s" % ret[1])
+        rsp_result_data = json.JSONDecoder().decode(ret[1])
+        logger.info("Func test(%s) result: %s", rsp_result_data)
+        self.update_job(80, "Vnf function test success.")
+        
+    def do_term_vnf(self):
+        if not self.vnf_inst_id:
+            return
+        self.update_job(90, "Start term vnf.")
+        term_data = {
+            "terminationType": "forceful",
+            "gracefulTerminationTimeout": "600"
+        }
+        ret = req_by_msb("/openoapi/nslcm/v1/ns/vnfs/%s" % self.vnf_inst_id, "POST", json.JSONEncoder().encode(term_data))
+        if ret[0] != 0:
+            raise NSLCMException("Failed to call term vnf: %s" % ret[1])
+        rsp_data = json.JSONDecoder().decode(ret[1])
+        end_progress = 100 if self.verify_ok else JOB_ERROR
+        term_progress = 95 if self.verify_ok else JOB_ERROR
+        if not self.wait_until_job_done(rsp_data["jobId"], term_progress):
+            logger.error("Vnf(%s) term failed", self.vnf_inst_id)
+            end_progress = JOB_ERROR
+        self.update_job(end_progress, "Term vnf end.")
+        
+    def update_job(self, progress, desc=''):
+        JobUtil.add_job_status(self.job_id, progress, desc)
+        
+    def wait_until_job_done(self, job_id, global_progress, retry_count=60, interval_second=3):
+        count = 0
+        response_id, new_response_id = 0, 0
+        job_end_normal, job_timeout = False, True
+        while count < retry_count:
+            count = count + 1
+            time.sleep(interval_second)
+            ret = req_by_msb("/openoapi/nslcm/v1/jobs/%s?responseId=%s" % (job_id, response_id), "GET")
+            if ret[0] != 0:
+                logger.error("Failed to query job: %s:%s", ret[2], ret[1])
+                continue
+            job_result = json.JSONDecoder().decode(ret[1])
+            if "responseDescriptor" not in job_result:
+                logger.error("Job(%s) does not exist.", job_id)
+                continue
+            progress = job_result["responseDescriptor"]["progress"]
+            new_response_id = job_result["responseDescriptor"]["responseId"]
+            job_desc = job_result["responseDescriptor"]["statusDescription"]
+            if new_response_id != response_id:
+                self.update_job(global_progress, job_desc)
+                logger.debug("%s:%s:%s", progress, new_response_id, job_desc)
+                response_id = new_response_id
+                count = 0
+            if progress == JOB_ERROR:
+                if 'already onBoarded' in job_desc:
+                    logger.warn("%s:%s", job_id, job_desc)
+                    job_end_normal, job_timeout = True, False
+                    logger.info("Job(%s) ended", job_id)
+                    break
+                job_timeout = False
+                logger.error("Job(%s) failed: %s", job_id, job_desc)
+                break
+            elif progress == 100:
+                job_end_normal, job_timeout = True, False
+                logger.info("Job(%s) ended normally", job_id)
+                break
+        if job_timeout:
+            logger.error("Job(%s) timeout", job_id)
+        return job_end_normal
+
+    def wait_func_test_job_done(self, job_id, global_progress, retry_count=60, interval_second=3):
+        count = 0
+        response_id, new_response_id = 0, 0
+        job_end_normal, job_timeout = False, True
+        while count < retry_count:
+            count = count + 1
+            time.sleep(interval_second)
+            ret = req_by_msb("/openapi/vnfsdk/v1/functest/taskmanager/testtasks/%s?responseId=%s" %
+                (job_id, response_id), "GET")
+            if ret[0] != 0:
+                logger.error("Failed to query job: %s:%s", ret[2], ret[1])
+                continue
+            job_result = json.JSONDecoder().decode(ret[1])
+            if "responseDescriptor" not in job_result:
+                logger.error("Job(%s) does not exist.", job_id)
+                continue
+            progress = job_result["responseDescriptor"]["progress"]
+            new_response_id = job_result["responseDescriptor"]["responseId"]
+            job_desc = job_result["responseDescriptor"]["statusDescription"]
+            if new_response_id != response_id:
+                self.update_job(global_progress, job_desc)
+                logger.debug("%s:%s:%s", progress, new_response_id, job_desc)
+                response_id = new_response_id
+                count = 0
+            if progress == JOB_ERROR:
+                if 'already onBoarded' in job_desc:
+                    logger.warn("%s:%s", job_id, job_desc)
+                    job_end_normal, job_timeout = True, False
+                    logger.info("Job(%s) ended", job_id)
+                    break
+                job_timeout = False
+                logger.error("Job(%s) failed: %s", job_id, job_desc)
+                break
+            elif progress == 100:
+                job_end_normal, job_timeout = True, False
+                logger.info("Job(%s) ended normally", job_id)
+                break
+        if job_timeout:
+            logger.error("Job(%s) timeout", job_id)
+        return job_end_normal
+
+    def load_config(self):
+        json_file = os.path.join(os.path.dirname(__file__), 'verify_vnfs_config.json')
+        f = open(json_file)
+        json_data = json.JSONDecoder().decode(f.read())
+        f.close()
+        return json_data
diff --git a/lcm/ns/vnfs/verify_vnfs_config.json b/lcm/ns/vnfs/verify_vnfs_config.json
new file mode 100644 (file)
index 0000000..712a070
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "labVimId":"1111",
+  "additionalParamForVnf":[
+    {
+      "vnfProfileId":"2222",
+      "additionalParam":{
+        "vnfmInstanceId":"vnfmid_4",
+        "inputs":{"vnf_param1": "inputs_11", "vnf_param2": "inputs_22"},
+        "vnfdId":"777"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/lcm/ns/vnfs/views.py b/lcm/ns/vnfs/views.py
new file mode 100644 (file)
index 0000000..5c92569
--- /dev/null
@@ -0,0 +1,124 @@
+# Copyright 2016-2017 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
+import uuid
+
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from lcm.ns.vnfs import create_vnfs
+from lcm.ns.vnfs.create_vnfs import CreateVnfs
+from lcm.ns.vnfs.verify_vnfs import VerifyVnfs
+from lcm.ns.vnfs.get_vnfs import GetVnf
+from lcm.ns.vnfs.scale_vnfs import NFManualScaleService
+from lcm.ns.vnfs.terminate_nfs import TerminateVnfs
+from lcm.ns.vnfs.grant_vnfs import GrantVnfs
+from lcm.ns.vnfs.notify_lcm import NotifyLcm
+from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE
+from lcm.pub.utils.values import ignore_case_get
+
+logger = logging.getLogger(__name__)
+
+
+class NfView(APIView):
+    def post(self, request):
+        logger.debug("VnfCreateView--post::> %s" % request.data)
+        data = {'ns_instance_id': ignore_case_get(request.data, 'nsInstanceId'),
+                'additional_param_for_ns': ignore_case_get(request.data, 'additionalParamForVnf'),
+                'additional_param_for_vnf': ignore_case_get(request.data, 'additionalParamForVnf'),
+                'vnf_index': ignore_case_get(request.data, 'vnfIndex')}
+        nf_inst_id, job_id = create_vnfs.prepare_create_params()
+        CreateVnfs(data, nf_inst_id, job_id).start()
+        rsp = {
+            "vnfInstId": nf_inst_id,
+            "jobId": job_id}
+        return Response(data=rsp, status=status.HTTP_202_ACCEPTED)
+
+
+class NfDetailView(APIView):
+    def get(self, request, vnfinstid):
+        logger.debug("VnfQueryView--get::> %s" % vnfinstid)
+        nf_inst_info = GetVnf(vnfinstid).do_biz()
+        if not nf_inst_info:
+            return Response(status=status.HTTP_404_NOT_FOUND)
+        return Response(status=status.HTTP_200_OK,
+                        data={'vnfInstId': nf_inst_info[0].nfinstid, 'vnfName': nf_inst_info[0].nf_name,
+                              'vnfStatus': nf_inst_info[0].status})
+
+    def post(self, request_paras, vnfinstid):
+        logger.debug("VnfTerminateView--post::> %s, %s", vnfinstid, request_paras.data)
+        vnf_inst_id = vnfinstid
+        terminationType = ignore_case_get(request_paras.data, 'terminationType')
+        gracefulTerminationTimeout = ignore_case_get(request_paras.data, 'gracefulTerminationTimeout')
+        job_id = JobUtil.create_job("VNF", JOB_TYPE.TERMINATE_VNF, vnf_inst_id)
+        data = {'terminationType': terminationType, 'gracefulTerminationTimeout': gracefulTerminationTimeout}
+        logger.debug("data=%s", data)
+        try:
+            TerminateVnfs(data, vnf_inst_id, job_id).start()
+        except Exception as e:
+            return Response(data={'error': '%s' % e.message}, status=status.HTTP_409_CONFLICT)
+        rsp = {'jobId': job_id}
+        return Response(data=rsp, status=status.HTTP_201_CREATED)
+
+
+class NfGrant(APIView):
+    def post(self, request):
+        logger.debug("NfGrant--post::> %s" % request.data)
+        try:
+            vnf_inst_id = ignore_case_get(request.data, 'vnfInstanceId')
+            job_id = JobUtil.create_job("VNF", JOB_TYPE.GRANT_VNF, vnf_inst_id)
+            rsp = GrantVnfs(request.data, job_id).send_grant_vnf_to_resMgr()
+            """
+            rsp = {
+                "vim": {
+                    "vimid": ignore_case_get(ignore_case_get(request.data, 'additionalparam'), 'vimid'),
+                    "accessinfo": {
+                        "tenant": "admin"
+                    }
+                }
+            }
+            """
+            return Response(data=rsp, status=status.HTTP_201_CREATED)
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            return Response(data={'error': '%s' % e.message}, status=status.HTTP_409_CONFLICT)
+
+
+class LcmNotify(APIView):
+    def post(self, request_paras, vnfmid, vnfInstanceId):
+        logger.debug("LcmNotify--post::> %s" % request_paras.data)
+        try:
+            NotifyLcm(vnfmid, vnfInstanceId, request_paras.data).do_biz()
+            return Response(data={}, status=status.HTTP_201_CREATED)
+        except Exception as e:
+            return Response(data={'error': '%s' % e.message}, status=status.HTTP_409_CONFLICT)
+
+
+class NfScaleView(APIView):
+    def post(self, request_paras, vnfinstid):
+        logger.debug("NfScaleView--post::> %s" % request_paras.data)
+        try:
+            NFManualScaleService(vnfinstid, request_paras.data).start()
+            return Response(data={}, status=status.HTTP_202_ACCEPTED)
+        except Exception as e:
+            return Response(data={'error': '%s' % e.message}, status=status.HTTP_409_CONFLICT)
+
+class NfVerifyView(APIView):
+    def post(self, request):
+        job_id = "VNFSDK_" + str(uuid.uuid4())
+        logger.debug("NfVerifyView--post::%s> %s", job_id, request.data)
+        VerifyVnfs(request.data, job_id).start()
+        return Response(data={"jobId": job_id}, status=status.HTTP_202_ACCEPTED)
\ No newline at end of file
diff --git a/lcm/ns/vnfs/wait_job.py b/lcm/ns/vnfs/wait_job.py
new file mode 100644 (file)
index 0000000..39a9555
--- /dev/null
@@ -0,0 +1,81 @@
+# Copyright 2016 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 time
+import datetime
+import logging
+
+import math
+
+from lcm.pub.utils.jobutil import JobUtil, JOB_MODEL_STATUS
+from lcm.pub.msapi.vnfmdriver import query_vnfm_job
+from lcm.pub.utils.values import ignore_case_get
+
+logger = logging.getLogger(__name__)
+
+
+def calc_progress(vnfm_progress, target_range=None):
+    target_range = [0, 100] if not target_range else target_range
+    progress = int(vnfm_progress) if vnfm_progress else 0
+    if progress > 100:
+        return progress
+    floor_progress = int(math.floor(float(target_range[1] - target_range[0]) / 100 * progress))
+    target_range = floor_progress + target_range[0]
+    return target_range
+
+
+def default_callback(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
+    for job in jobs:
+        progress = calc_progress(
+            ignore_case_get(job, 'progress'), 
+            progress_range)
+        JobUtil.add_job_status(vnfo_job_id, progress, 
+            ignore_case_get(job, 'statusdescription'), 
+            ignore_case_get(job, 'errorcode'))
+    latest_progress = calc_progress(
+        ignore_case_get(job_status, 'progress'), 
+        progress_range)
+    JobUtil.add_job_status(vnfo_job_id, latest_progress, 
+        ignore_case_get(job_status, 'statusdescription'),
+        ignore_case_get(job_status, 'errorcode'))
+    jobstatus = ignore_case_get(job_status, 'status')
+    if jobstatus in (JOB_MODEL_STATUS.ERROR, JOB_MODEL_STATUS.FINISHED):
+        return True, jobstatus
+    return False, JOB_MODEL_STATUS.PROCESSING
+
+
+def wait_job_finish(vnfm_id, vnfo_job_id, vnfm_job_id, progress_range=None, timeout=600, 
+    job_callback=default_callback, **kwargs):
+    progress_range = [0, 100] if not progress_range else progress_range
+    response_id = 0
+    query_interval = 2
+    start_time = end_time = datetime.datetime.now()
+    while (end_time - start_time).seconds < timeout:
+        query_status, result = query_vnfm_job(vnfm_id, vnfm_job_id, response_id)
+        time.sleep(query_interval)
+        end_time = datetime.datetime.now()
+        if not query_status:
+            continue
+        job_status = ignore_case_get(result, 'responsedescriptor')
+        response_id_new = ignore_case_get(job_status, 'responseid')
+        if response_id_new == response_id:
+            continue
+        response_id = response_id_new
+        jobs = ignore_case_get(job_status, 'responsehistorylist', [])
+        if jobs:
+            jobs.reverse()
+        is_end, status = job_callback(vnfo_job_id, vnfm_job_id, job_status, 
+            jobs, progress_range, **kwargs)
+        if is_end:
+            return status
+    return JOB_MODEL_STATUS.TIMEOUT
diff --git a/lcm/packages/__init__.py b/lcm/packages/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/packages/nf_package.py b/lcm/packages/nf_package.py
new file mode 100644 (file)
index 0000000..6c845d5
--- /dev/null
@@ -0,0 +1,439 @@
+# Copyright 2016-2017 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
+import uuid
+import os
+import time
+import threading
+import traceback
+import sys
+
+from lcm.pub.database.models import NfPackageModel, VnfPackageFileModel, NfInstModel
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.utils import fileutil
+from lcm.pub.msapi.catalog import STATUS_ONBOARDED, P_STATUS_ENABLED
+from lcm.pub.msapi.catalog import P_STATUS_DELETEFAILED, P_STATUS_DELETING
+from lcm.pub.msapi.catalog import P_STATUS_NORMAL, P_STATUS_ONBOARDING, P_STATUS_ONBOARDFAILED
+from lcm.pub.msapi.catalog import query_csar_from_catalog, set_csar_state
+from lcm.pub.msapi.catalog import query_rawdata_from_catalog, delete_csar_from_catalog
+from lcm.pub.msapi.catalog import get_download_url_from_catalog
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.msapi.extsys import get_vims
+from lcm.pub.config.config import IMAGE_ROOT_PATH, IGNORE_DEL_IMG_WEHN_DEL_CSAR
+from lcm.pub.nfvi.vim.vimadaptor import VimAdaptor
+from lcm.pub.nfvi.vim import const
+from lcm.pub.utils.jobutil import JobUtil
+from lcm.pub.utils import toscautil
+
+logger = logging.getLogger(__name__)
+
+SUPPORT_MULTI_VIM, UNSUPPORT_MULTI_VIM = 1, 0
+ZTE_PRIVATE = 0
+DEPLOY_TYPE_IAAS = 1
+IMAGE_FILE = 2
+IMAGE_STATUS_ENABLE = "Enable"
+MAX_RETRY_TIMES = 300
+SLEEP_INTERVAL_SECONDS = 2
+IMAGE_ACTIVE = 'active'
+JOB_ERROR = 255
+
+
+class NfOnBoardingThread(threading.Thread):
+    """
+    NF package onBoarding
+    """
+
+    def __init__(self, csar_id, vim_ids, lab_vim_id, job_id):
+        threading.Thread.__init__(self)
+        self.csar_id = csar_id
+        self.vim_ids = vim_ids
+        self.lab_vim_id = lab_vim_id
+        self.job_id = job_id
+
+        self.csar_info = None
+        self.nfd = None
+        self.nfd_id = None
+        self.img_save_path = os.path.join(IMAGE_ROOT_PATH, self.job_id)
+
+        self.need_rollback_when_failed = False
+
+    def run(self):
+        try:
+            self.on_boarding()
+        except NSLCMException as e:
+            self.rollback_on_boarding()
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+            self.rollback_on_boarding()
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to onBoarding CSAR(%s)" % self.csar_id)
+
+    def on_boarding(self):
+        JobUtil.create_job(
+            inst_type='nf',
+            jobaction='on_boarding',
+            inst_id=self.csar_id,
+            job_id=self.job_id)
+        JobUtil.add_job_status(self.job_id, 5, "Start CSAR(%s) onBoarding." % self.csar_id)
+        self.on_boarding_pre_deal()
+        self.nf_package_save()
+        self.need_rollback_when_failed = True
+        nf_images = self.download_nf_images()
+        self.upload_nf_images(nf_images)
+        set_csar_state(self.csar_id, "onBoardState", STATUS_ONBOARDED)
+        set_csar_state(self.csar_id, "processState", P_STATUS_NORMAL)
+        set_csar_state(self.csar_id, "operationalState", P_STATUS_ENABLED)
+        JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) onBoarding successfully." % self.csar_id)
+
+    def on_boarding_pre_deal(self):
+        JobUtil.add_job_status(self.job_id, 10, "Check status of CSAR(%s) from catalog." % self.csar_id)
+
+        self.csar_info = query_csar_from_catalog(self.csar_id)
+
+        on_board_state = ignore_case_get(self.csar_info, "onBoardState")
+        if on_board_state == STATUS_ONBOARDED:
+            raise NSLCMException("CSAR(%s) already onBoarded." % self.csar_id)
+
+        process_state = ignore_case_get(self.csar_info, "processState")
+        if process_state == P_STATUS_ONBOARDING:
+            raise NSLCMException("CSAR(%s) is onBoarding now." % self.csar_id)
+
+        JobUtil.add_job_status(self.job_id, 20, "Get model of CSAR(%s) from catalog." % self.csar_id)
+
+        raw_data = query_rawdata_from_catalog(self.csar_id)
+        self.nfd = toscautil.convert_vnfd_model(raw_data["rawData"]) # convert to inner json
+        self.nfd = json.JSONDecoder().decode(self.nfd)
+        self.nfd_id = self.nfd["metadata"]["id"]
+        if NfPackageModel.objects.filter(vnfdid=self.nfd_id):
+            raise NSLCMException("NFD(%s) already exists." % self.nfd_id)
+
+    def nf_package_save(self):
+        JobUtil.add_job_status(self.job_id, 30, "Save CSAR(%s) to database." % self.csar_id)
+        vnfd_ver = self.nfd["metadata"].get("vnfd_version")
+        if not vnfd_ver:
+            vnfd_ver = self.nfd["metadata"].get("vnfdVersion")
+        NfPackageModel(
+            uuid=str(uuid.uuid4()),
+            nfpackageid=self.csar_id,
+            vnfdid=self.nfd_id,
+            vendor=self.nfd["metadata"].get("vendor", "undefined"),
+            vnfdversion=vnfd_ver,
+            vnfversion=self.nfd["metadata"].get("version", "undefined"),
+            vnfdmodel=json.JSONEncoder().encode(self.nfd)
+            ).save()
+
+    def download_nf_images(self):
+        nf_images = []
+        for image_file in self.nfd["image_files"]:
+            img_name = image_file["properties"]["name"]
+            img_relative_path = image_file["properties"]["file_url"]
+            img_type = image_file["properties"]["disk_format"]
+            img_desc = image_file.get("description", "")
+            img_url, img_local_path = get_download_url_from_catalog(self.csar_id, img_relative_path)
+            JobUtil.add_job_status(self.job_id, 50, "Start to download Image(%s)." % img_name)
+            is_download_ok, img_save_full_path = fileutil.download_file_from_http(img_url, 
+                self.img_save_path, img_name)
+            if not is_download_ok:
+                raise NSLCMException("Failed to download image from %s" % img_url)
+            logger.debug("Download Image(%s) to %s successfully.", img_name, img_save_full_path)
+            nf_images.append({
+                "image_url": img_url,
+                "img_name": img_name,
+                "img_save_full_path": img_save_full_path,
+                "img_type": img_type,
+                "img_desc": img_desc})
+        return nf_images
+
+    def upload_nf_images(self, nf_images):
+        vims = get_vims()
+        if self.lab_vim_id and (not self.vim_ids):
+            self.vim_ids = [self.lab_vim_id]
+        for vim_id in self.vim_ids:
+            sel_vim = [vim for vim in vims if vim["vimId"] == vim_id]
+            if not sel_vim:
+                logger.warn("VIMID(%s) does not exist.", vim_id)
+                continue
+            vim_api = VimAdaptor({
+                "vimid": vim_id,
+                "vimtype": sel_vim[0]["type"],
+                "url": sel_vim[0]["url"],
+                "user": sel_vim[0]["userName"],
+                "passwd": sel_vim[0]["password"],
+                "tenant": sel_vim[0]["tenant"]})
+            for nf_image in nf_images:
+                self.upload_one_nf_image(vim_api, nf_image, vim_id, sel_vim)
+        fileutil.delete_dirs(self.img_save_path)
+
+    def upload_one_nf_image(self, vim_api, nf_image, vim_id, sel_vim):
+        JobUtil.add_job_status(self.job_id, 80, "Start to upload Image(%s) to VIM(%s)." %
+                               (nf_image["img_name"], vim_id))
+        ret = vim_api.create_image({
+            "image_url": nf_image["image_url"],
+            "image_name": nf_image["img_name"],
+            "image_path": nf_image["img_save_full_path"],
+            "image_type": nf_image["img_type"]})
+        if ret[0] != 0:
+            raise NSLCMException("Failed to create image:%s" % ret[1])
+        image_id = ret[1]["id"]
+
+        self.wait_until_upload_done(vim_api, image_id)
+
+        VnfPackageFileModel(
+            vnfpid=self.csar_id,
+            filename=nf_image["img_name"],
+            filetype=IMAGE_FILE,
+            imageid=image_id,
+            vimid=vim_id,
+            vimuser=sel_vim[0]["userName"],
+            tenant=sel_vim[0]["tenant"],
+            purpose=nf_image["img_desc"],
+            status=IMAGE_STATUS_ENABLE).save()
+
+    def wait_until_upload_done(self, vim_api, image_id):
+        retry_times = 0
+        image_create_success = False
+
+        while retry_times < MAX_RETRY_TIMES:
+            retry_times += 1
+            ret = vim_api.get_image(image_id=image_id)
+            if ret[0] != 0:
+                logging.warn("Failed to query image:%s", ret[1])
+                continue
+            if ret[1]["status"] == IMAGE_ACTIVE:
+                image_create_success = True
+                break
+            time.sleep(SLEEP_INTERVAL_SECONDS)
+
+        if not image_create_success:
+            timeout_seconds = MAX_RETRY_TIMES * SLEEP_INTERVAL_SECONDS
+            raise NSLCMException("Failed to create image:timeout(%s seconds.)" % timeout_seconds)
+
+    def rollback_on_boarding(self):
+        if not self.need_rollback_when_failed:
+            return
+        try:
+            set_csar_state(self.csar_id, "processState", P_STATUS_ONBOARDFAILED)
+            NfPackageModel.objects.filter(nfpackageid=self.csar_id).delete()
+            VnfPackageFileModel.objects.filter(vnfpid=self.csar_id).delete()
+            fileutil.delete_dirs(self.img_save_path)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+
+
+######################################################################################################################
+
+
+class NfPkgDeleteThread(threading.Thread):
+    """
+    NF Package Deleting
+    """
+
+    def __init__(self, csar_id, job_id):
+        threading.Thread.__init__(self)
+        self.csar_id = csar_id
+        self.job_id = job_id
+
+    def run(self):
+        try:
+            self.delete_csar()
+        except NSLCMException as e:
+            set_csar_state(self.csar_id, "processState", P_STATUS_DELETEFAILED)
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+            set_csar_state(self.csar_id, "processState", P_STATUS_DELETEFAILED)
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to delete CSAR(%s)" % self.csar_id)
+
+    def delete_csar(self):
+        JobUtil.create_job(
+            inst_type='nf',
+            jobaction='delete',
+            inst_id=self.csar_id,
+            job_id=self.job_id)
+        JobUtil.add_job_status(self.job_id, 5, "Start to delete CSAR(%s)." % self.csar_id)
+        if query_csar_from_catalog(self.csar_id, "processState") == P_STATUS_DELETING:
+            JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) is deleting now." % self.csar_id)
+            return
+
+        if NfInstModel.objects.filter(package_id=self.csar_id):
+            ret = set_csar_state(self.csar_id, "deletionPending", True)
+            JobUtil.add_job_status(self.job_id, 100, ret[1])
+            return
+
+        NfPackage().delete_csar(self.csar_id, self.job_id)
+
+
+class NfPkgDeletePendingThread(threading.Thread):
+    """
+    NF Package Delete Pending
+    """
+
+    def __init__(self, csar_id, job_id):
+        threading.Thread.__init__(self)
+        self.csar_id = csar_id
+        self.job_id = job_id
+
+    def run(self):
+        try:
+            self.delete_pending_csar()
+        except NSLCMException as e:
+            set_csar_state(self.csar_id, "processState", P_STATUS_DELETEFAILED)
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+            set_csar_state(self.csar_id, "processState", P_STATUS_DELETEFAILED)
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to delete CSAR(%s)" % self.csar_id)
+
+    def delete_pending_csar(self):
+        JobUtil.create_job(
+            inst_type='nf',
+            jobaction='delete_pending',
+            inst_id=self.csar_id,
+            job_id=self.job_id)
+        JobUtil.add_job_status(self.job_id, 5, "Start to delete pending CSAR(%s)." % self.csar_id)
+
+        if not NfPackageModel.objects.filter(nfpackageid=self.csar_id):
+            JobUtil.add_job_status(self.job_id, 100, "Delete pending CSAR(%s) successfully." % self.csar_id)
+            return
+
+        csar_info = query_csar_from_catalog(self.csar_id)
+
+        process_state = ignore_case_get(csar_info, "processState")
+        if process_state == P_STATUS_DELETING:
+            JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) is deleting now." % self.csar_id)
+            return
+
+        deletion_pending = ignore_case_get(csar_info, "deletionPending")
+        if deletion_pending.lower() == "false":
+            JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) need not to be deleted." % self.csar_id)
+            return
+
+        if NfInstModel.objects.filter(package_id=self.csar_id):
+            JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) is in using, cannot be deleted." % self.csar_id)
+            return
+
+        NfPackage().delete_csar(self.csar_id, self.job_id)
+
+
+####################################################################################################################
+class NfPackage(object):
+    """
+    Actions for nf package.
+    """
+
+    def __init__(self):
+        pass
+
+    def get_csars(self):
+        ret = {"csars": []}
+        nf_pkgs = NfPackageModel.objects.filter()
+        for nf_pkg in nf_pkgs:
+            ret["csars"].append({
+                "csarId": nf_pkg.nfpackageid,
+                "vnfdId": nf_pkg.vnfdid
+            })
+        return ret
+        
+    def get_csar(self, csar_id):
+        pkg_info = {}
+        nf_pkg = NfPackageModel.objects.filter(nfpackageid=csar_id)
+        if nf_pkg:
+            pkg_info["vnfdId"] = nf_pkg[0].vnfdid
+            pkg_info["vnfdProvider"] = nf_pkg[0].vendor
+            pkg_info["vnfdVersion"] = nf_pkg[0].vnfdversion
+            pkg_info["vnfVersion"] = nf_pkg[0].vnfversion
+
+        casrinfo = query_csar_from_catalog(csar_id)
+        props_of_catalog = [
+            "name", "provider", "version", "operationalState", "usageState",
+            "onBoardState", "processState", "deletionPending", "downloadUri",
+            "createTime", "modifyTime", "format", "size"]
+        for prop in props_of_catalog:
+            pkg_info[prop] = ignore_case_get(casrinfo, prop)
+
+        nf_pkg_files = VnfPackageFileModel.objects.filter(vnfpid=csar_id)
+        img_info = [{
+            "index": str(i),
+            "fileName": nf_pkg_files[i].filename,
+            "imageId": nf_pkg_files[i].imageid,
+            "vimId": nf_pkg_files[i].vimid,
+            "vimUser": nf_pkg_files[i].vimuser,
+            "tenant": nf_pkg_files[i].tenant,
+            "status": nf_pkg_files[i].status}
+            for i in range(len(nf_pkg_files))]
+
+        vnf_insts = NfInstModel.objects.filter(package_id=csar_id)
+        vnf_inst_info = [{"vnfInstanceId": vnf_inst.nfinstid,
+                          "vnfInstanceName": vnf_inst.nf_name} for vnf_inst in vnf_insts]
+
+        return [0, {"csarId": csar_id,
+                    "packageInfo": pkg_info,
+                    "imageInfo": img_info,
+                    "vnfInstanceInfo": vnf_inst_info}]
+
+    def delete_csar(self, csar_id, job_id):
+        JobUtil.add_job_status(job_id, 10, "Set processState of CSAR(%s)." % csar_id)
+        set_csar_state(csar_id, "processState", P_STATUS_DELETING)
+
+        JobUtil.add_job_status(job_id, 20, "Get package files of CSAR(%s)." % csar_id)
+        all_nf_pkg_files = VnfPackageFileModel.objects.all()
+        nf_pkg_files = VnfPackageFileModel.objects.filter(vnfpid=csar_id)
+        vims = get_vims()
+
+        for pkg_file in nf_pkg_files:
+            if IGNORE_DEL_IMG_WEHN_DEL_CSAR:
+                logger.warn("ignore delete image(%s)" % pkg_file.filename)
+                continue
+            JobUtil.add_job_status(job_id, 50, "Delete image(%s) of CSAR(%s)." %
+                                   (pkg_file.filename, csar_id))
+            if self.is_image_refed_by_other_nf_pkg(all_nf_pkg_files, pkg_file.imageid, csar_id, pkg_file.vimid):
+                logger.warn("Image(%s) is refered by CSAR(%s).", pkg_file.filename, csar_id)
+                continue
+            sel_vim = [vim for vim in vims if vim["vimId"] == pkg_file.vimid]
+            if not sel_vim:
+                logger.warn("Vim(%s) does not exist.", pkg_file.vimid)
+                continue
+            vim_api = VimAdaptor({
+                "vimid": pkg_file.vimid,
+                "vimtype": sel_vim[0]["type"],
+                "url": sel_vim[0]["url"],
+                "user": sel_vim[0]["userName"],
+                "passwd": sel_vim[0]["password"],
+                "tenant": sel_vim[0]["tenant"]})
+            ret = vim_api.delete_image(pkg_file.imageid)
+            if ret[0] != 0:
+                logger.error("Failed to delete image(%s) from vim(%s)", pkg_file.filename, pkg_file.vimid)
+
+        JobUtil.add_job_status(job_id, 70, "Delete CSAR(%s) from catalog." % csar_id)
+        ret = delete_csar_from_catalog(csar_id)
+        if ret[0] != 0:
+            raise NSLCMException(ret[1])
+
+        JobUtil.add_job_status(job_id, 90, "Delete CSAR(%s) from database." % csar_id)
+        VnfPackageFileModel.objects.filter(vnfpid=csar_id).delete()
+        NfPackageModel.objects.filter(nfpackageid=csar_id).delete()
+
+        JobUtil.add_job_status(job_id, 100, "Delete CSAR(%s) successfully." % csar_id)
+
+    def is_image_refed_by_other_nf_pkg(self, nf_pkg_files, imageid, csar_id, vim_id):
+        for f in nf_pkg_files:
+            if f.imageid == imageid and f.vimid == vim_id and f.vnfpid != csar_id:
+                return True
+        return False
diff --git a/lcm/packages/ns_package.py b/lcm/packages/ns_package.py
new file mode 100644 (file)
index 0000000..4a7fb30
--- /dev/null
@@ -0,0 +1,188 @@
+# Copyright 2016 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
+
+import traceback
+import sys
+
+from lcm.pub.database.models import NSDModel, NSInstModel, NfPackageModel
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.msapi.catalog import STATUS_ONBOARDED, P_STATUS_ENABLED
+from lcm.pub.msapi.catalog import query_csar_from_catalog, set_csar_state
+from lcm.pub.msapi.catalog import query_rawdata_from_catalog, delete_csar_from_catalog
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils import toscautil
+
+logger = logging.getLogger(__name__)
+
+STATUS_SUCCESS, STATUS_FAILED = "success", "failed"
+
+
+def fmt_ns_pkg_rsp(status, desc, error_code="500"):
+    return [0, {"status": status, "statusDescription": desc, "errorCode": error_code}]
+
+
+def ns_common_call(fun, csar_id, operation=""):
+    ret = None
+    try:
+        if operation == "":
+            ret = fun(csar_id)
+        else:
+            ret = fun(csar_id, operation)
+
+        if ret[0] != 0:
+            return fmt_ns_pkg_rsp(STATUS_FAILED, ret[1])
+    except NSLCMException as e:
+        return fmt_ns_pkg_rsp(STATUS_FAILED, e.message)
+    except:
+        logger.error(traceback.format_exc())
+        return fmt_ns_pkg_rsp(STATUS_FAILED, str(sys.exc_info()))
+    return fmt_ns_pkg_rsp(STATUS_SUCCESS, ret[1], "")
+
+def ns_on_boarding(csar_id):
+    return ns_common_call(NsPackage().on_boarding, csar_id)
+
+
+def ns_delete_csar(csar_id):
+    return ns_common_call(NsPackage().delete_csar, csar_id)
+
+
+def ns_delete_pending_csar(csar_id):
+    return ns_common_call(NsPackage().delete_pending_csar, csar_id)
+
+
+def ns_set_state_csar(csar_id, operation):
+    return ns_common_call(NsPackage().set_state_csar, csar_id, operation)
+
+
+def ns_get_csar(csar_id):
+    ret = None
+    try:
+        ret = NsPackage().get_csar(csar_id)
+    except NSLCMException as e:
+        return [1, e.message]
+    except:
+        logger.error(traceback.format_exc())
+        return [1, str(sys.exc_info())]
+    return ret
+
+
+###############################################################################################################
+
+
+class NsPackage(object):
+    """
+    Actions for ns package.
+    """
+
+    def __init__(self):
+        pass
+
+    def on_boarding(self, csar_id):
+        csar = query_csar_from_catalog(csar_id)
+        if ignore_case_get(csar, "onBoardState") == STATUS_ONBOARDED:
+            raise NSLCMException("CSAR(%s) already onBoarded." % csar_id)
+
+        raw_data = query_rawdata_from_catalog(csar_id)
+        nsd = toscautil.convert_nsd_model(raw_data["rawData"]) # convert to inner json
+        nsd = json.JSONDecoder().decode(nsd)
+        nsd_id = nsd["metadata"]["id"]
+        if NSDModel.objects.filter(nsd_id=nsd_id):
+            raise NSLCMException("NSD(%s) already exists." % nsd_id)
+
+        for vnf in nsd["vnfs"]:
+            vnfd_id = vnf["properties"]["id"]
+            pkg = NfPackageModel.objects.filter(vnfdid=vnfd_id)
+            if not pkg:
+                raise NSLCMException("VNF package(%s) is not onBoarded." % vnfd_id)
+            pkg_id = pkg[0].nfpackageid
+            if query_csar_from_catalog(pkg_id, "onBoardState") != STATUS_ONBOARDED:
+                raise NSLCMException("VNF package(%s) is not onBoarded on catalog." % pkg_id)
+
+        NSDModel(
+            id=csar_id,
+            nsd_id=nsd_id,
+            name=nsd["metadata"].get("name", nsd_id),
+            vendor=nsd["metadata"].get("vendor", "undefined"),
+            description=nsd["metadata"].get("description", ""),
+            version=nsd["metadata"].get("version", "undefined"),
+            nsd_model=json.JSONEncoder().encode(nsd)).save()
+
+        set_csar_state(csar_id, "onBoardState", STATUS_ONBOARDED)
+        set_csar_state(csar_id, "operationalState", P_STATUS_ENABLED)
+
+        return [0, "CSAR(%s) onBoarded successfully." % csar_id]
+
+    def delete_csar(self, csar_id):
+        if not NSDModel.objects.filter(id=csar_id):
+            return delete_csar_from_catalog(csar_id)
+
+        if NSInstModel.objects.filter(nspackage_id=csar_id):
+            return set_csar_state(csar_id, "deletionPending", True)
+
+        ret = delete_csar_from_catalog(csar_id)
+        if ret[0] == 0:
+            NSDModel.objects.filter(id=csar_id).delete()
+        return ret
+
+    def delete_pending_csar(self, csar_id):
+        if not NSDModel.objects.filter(id=csar_id):
+            return [0, "Delete pending CSAR(%s) successfully." % csar_id]
+
+        pending = query_csar_from_catalog(csar_id, "deletionPending")
+
+        if pending.lower() == "false":
+            return [1, "CSAR(%s) need not to be deleted." % csar_id]
+
+        if NSInstModel.objects.filter(nspackage_id=csar_id):
+            return [1, "CSAR(%s) is in using, cannot be deleted." % csar_id]
+
+        ret = delete_csar_from_catalog(csar_id)
+        if ret[0] == 0:
+            NSDModel.objects.filter(id=csar_id).delete()
+        return ret
+
+    def get_csar(self, csar_id):
+        package_info = {}
+
+        csar_in_catalog = query_csar_from_catalog(csar_id)
+        props_of_catalog = [
+            "name", "provider", "version", "operationalState", "usageState",
+            "onBoardState", "processState", "deletionPending", "downloadUri",
+            "createTime", "modifyTime", "format", "size"]
+        for prop in props_of_catalog:
+            package_info[prop] = ignore_case_get(csar_in_catalog, prop)
+
+        csars = NSDModel.objects.filter(id=csar_id)
+        if csars:
+            package_info["nsdId"] = csars[0].nsd_id
+            package_info["nsdProvider"] = csars[0].vendor
+            package_info["nsdVersion"] = csars[0].version
+
+        nss = NSInstModel.objects.filter(nspackage_id=csar_id)
+        ns_instance_info = [{"nsInstanceId": ns.id, "nsInstanceName": ns.name} for ns in nss]
+
+        return [0, {"csarId": csar_id, "packageInfo": package_info, "nsInstanceInfo": ns_instance_info}]
+
+
+    def set_state_csar(self, csar_id, operation):
+        if not NSDModel.objects.filter(id=csar_id):
+            raise NSLCMException("CSAR(%s) does not exist." % csar_id)
+
+        csar = query_csar_from_catalog(csar_id)
+        if ignore_case_get(csar, "operationalState") == operation.capitalize():
+            raise NSLCMException("CSAR(%s) already %s." % (csar_id, operation))
+        return set_csar_state(csar_id, 'operationState', operation.capitalize())
diff --git a/lcm/packages/tests/__init__.py b/lcm/packages/tests/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/packages/tests/test_nf.py b/lcm/packages/tests/test_nf.py
new file mode 100644 (file)
index 0000000..fad4cbe
--- /dev/null
@@ -0,0 +1,471 @@
+# Copyright 2016-2017 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 mock
+from rest_framework import status
+from django.test import TestCase
+from django.test import Client
+
+from lcm.pub.utils import restcall
+from lcm.pub.utils import fileutil
+from lcm.pub.nfvi.vim.vimadaptor import VimAdaptor
+from lcm.pub.database.models import NfPackageModel, VnfPackageFileModel, NfInstModel
+from lcm.pub.database.models import JobStatusModel, JobModel
+from lcm.packages.nf_package import NfOnBoardingThread, NfPkgDeletePendingThread
+from lcm.packages.nf_package import NfPkgDeleteThread
+from lcm.packages import nf_package
+from lcm.pub.nfvi.vim.const import VIM_OPENSTACK
+
+
+class TestNfPackage(TestCase):
+    def setUp(self):
+        self.client = Client()
+        NfPackageModel.objects.filter().delete()
+        VnfPackageFileModel.objects.filter().delete()
+        NfInstModel.objects.filter().delete()
+        JobModel.objects.filter().delete()
+        JobStatusModel.objects.filter().delete()
+        self.vnfd_raw_data = {
+            "rawData":{
+                "instance":{
+                    "metadata":{
+                        "is_shared":False,
+                        "plugin_info":"vbrasplugin_1.0",
+                        "vendor":"zte",
+                        "request_reclassification":False,
+                        "name":"vbras",
+                        "version":1,
+                        "vnf_type":"vbras",
+                        "cross_dc":False,
+                        "vnfd_version":"1.0.0",
+                        "id":"zte_vbras_1.0",
+                        "nsh_aware":True
+                    },
+                    "nodes":[
+                        {
+                            "id":"aaa_dnet_cp_0xu2j5sbigxc8h1ega3if0ld1",
+                            "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                            "template_name":"aaa_dnet_cp",
+                            "properties":{
+                                "bandwidth":{
+                                    "type_name":"integer",
+                                    "value":0
+                                },
+                                "direction":{
+                                    "type_name":"string",
+                                    "value":"bidirectional"
+                                },
+                                "vnic_type":{
+                                    "type_name":"string",
+                                    "value":"normal"
+                                },
+                                "sfc_encapsulation":{
+                                    "type_name":"string",
+                                    "value":"mac"
+                                },
+                                "order":{
+                                    "type_name":"integer",
+                                    "value":2
+                                }
+                            },
+                            "relationships":[
+                                {
+                                    "name":"guest_os",
+                                    "source_requirement_index":0,
+                                    "target_node_id":"AAA_image_d8aseebr120nbm7bo1ohkj194",
+                                    "target_capability_name":"feature"
+                                }
+                            ]
+                        },
+                        {
+                            "id":"LB_Image_oj5l2ay8l2g6vcq6fsswzduha",
+                            "type_name":"tosca.nodes.nfv.ext.ImageFile",
+                            "template_name":"LB_Image",
+                            "properties":{
+                                "disk_format":{
+                                    "type_name":"string",
+                                    "value":"qcow2"
+                                },
+                                "file_url":{
+                                    "type_name":"string",
+                                    "value":"/SoftwareImages/image-lb"
+                                },
+                                "name":{
+                                    "type_name":"string",
+                                    "value":"image-lb"
+                                }
+                            }
+                        }
+                    ]
+                },
+                "model":{
+                    "metadata":{
+                        "is_shared":False,
+                        "plugin_info":"vbrasplugin_1.0",
+                        "vendor":"zte",
+                        "request_reclassification":False,
+                        "name":"vbras",
+                        "version":1,
+                        "vnf_type":"vbras",
+                        "cross_dc":False,
+                        "vnfd_version":"1.0.0",
+                        "id":"zte_vbras_1.0",
+                        "nsh_aware":True
+                    },
+                    "node_templates":[
+                        {
+                            "name":"aaa_dnet_cp",
+                            "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                            "default_instances":1,
+                            "min_instances":0,
+                            "properties":{
+                                "bandwidth":{
+                                    "type_name":"integer",
+                                    "value":0
+                                }
+                            },
+                            "requirement_templates":[
+                                {
+                                    "name":"virtualbinding",
+                                    "target_node_template_name":"AAA",
+                                    "target_capability_name":"virtualbinding"
+                                }
+                            ]
+                        }
+                    ]
+                }
+            }
+        }
+
+    def tearDown(self):
+        pass
+
+    def assert_job_result(self, job_id, job_progress, job_detail):
+        jobs = JobStatusModel.objects.filter(
+            jobid=job_id,
+            progress=job_progress,
+            descp=job_detail)
+        self.assertEqual(1, len(jobs))
+
+    @mock.patch.object(NfOnBoardingThread, 'run')
+    def test_nf_pkg_on_boarding_normal(self, mock_run):
+        resp = self.client.post("/openoapi/nslcm/v1/vnfpackage", {
+            "csarId": "1",
+            "vimIds": ["1"]
+            }, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_nf_pkg_on_boarding_when_on_boarded(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({"onBoardState": "onBoarded"}), '200']
+        NfOnBoardingThread(csar_id="1",
+                           vim_ids=["1"],
+                           lab_vim_id="",
+                           job_id="2").run()
+        self.assert_job_result("2", 255, "CSAR(1) already onBoarded.")
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_nf_pkg_on_boarding_when_on_boarding(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            "onBoardState": "non-onBoarded",
+            "processState": "onBoarding"
+            }), '200']
+        NfOnBoardingThread(csar_id="2",
+                           vim_ids=["1"],
+                           lab_vim_id="",
+                           job_id="3").run()
+        self.assert_job_result("3", 255, "CSAR(2) is onBoarding now.")
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_nf_on_boarding_when_nfd_already_exists(self, mock_call_req):
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/2":
+                [0, json.JSONEncoder().encode({
+                    "onBoardState": "onBoardFailed", "processState": "deleteFailed"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+
+        mock_call_req.side_effect = side_effect
+        NfPackageModel(uuid="1", nfpackageid="2", vnfdid="zte_vbras_1.0").save()
+        NfOnBoardingThread(csar_id="2", vim_ids=["1"], lab_vim_id="", job_id="4").run()
+        self.assert_job_result("4", 255, "NFD(zte_vbras_1.0) already exists.")
+
+    @mock.patch.object(restcall, 'call_req')
+    @mock.patch.object(fileutil, 'download_file_from_http')
+    @mock.patch.object(VimAdaptor, '__init__')
+    @mock.patch.object(VimAdaptor, 'create_image')
+    @mock.patch.object(VimAdaptor, 'get_image')
+    def test_nf_on_boarding_when_successfully(self, mock_get_image, mock_create_image,
+                                              mock__init__, mock_download_file_from_http, mock_call_req):
+        mock_download_file_from_http.return_value = True, "/root/package"
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/2":
+                [0, json.JSONEncoder().encode({
+                    "onBoardState": "onBoardFailed", "processState": "deleteFailed"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200'],
+            "/openoapi/catalog/v1/csars/2/files?relativePath=/SoftwareImages/image-lb":
+                [0, json.JSONEncoder().encode({
+                    "csar_file_info": [{"downloadUri": "8"}, {"localPath": "9"}]}), '200'],
+            "/openoapi/extsys/v1/vims":
+                [0, json.JSONEncoder().encode([{
+                    "vimId": "1", "type": VIM_OPENSTACK,
+                    "url": "/root/package", "userName": "tom",
+                    "password": "tom", "tenant": "10"}]), '200'],
+            "/openoapi/catalog/v1/csars/2?onBoardState=onBoarded": [0, '{}', 200],
+            "/openoapi/catalog/v1/csars/2?operationalState=Enabled": [0, '{}', 200],
+            "/openoapi/catalog/v1/csars/2?processState=normal": [0, '{}', 200]}
+        mock_create_image.return_value = [0, {"id": "30", "name": "jerry", "res_type": 0}]
+        mock__init__.return_value = None
+        mock_get_image.return_value = [0, {"id": "30", "name": "jerry", "size": "60", "status": "active"}]
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+
+        NfOnBoardingThread(csar_id="2", vim_ids=["1"], lab_vim_id="", job_id="4").run()
+        self.assert_job_result("4", 100, "CSAR(2) onBoarding successfully.")
+
+    @mock.patch.object(restcall, 'call_req')
+    @mock.patch.object(fileutil, 'download_file_from_http')
+    @mock.patch.object(VimAdaptor, '__init__')
+    @mock.patch.object(VimAdaptor, 'create_image')
+    @mock.patch.object(VimAdaptor, 'get_image')
+    def test_nf_on_boarding_when_timeout(self, mock_get_image, mock_create_image,
+                                         mock__init__, mock_download_file_from_http, mock_call_req):
+        nf_package.MAX_RETRY_TIMES = 2
+        nf_package.SLEEP_INTERVAL_SECONDS = 1
+        mock_download_file_from_http.return_value = True, "/root/package"
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/3":
+            [0, json.JSONEncoder().encode({"onBoardState": "onBoardFailed",
+                                           "processState": "deleteFailed"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200'],
+            "/openoapi/catalog/v1/csars/3/files?relativePath=/SoftwareImages/image-lb":
+                [0, json.JSONEncoder().encode({
+                    "csar_file_info": [{"downloadUri": "8"}, {"localPath": "9"}]}), '200'],
+            "/openoapi/catalog/v1/csars/3?processState=onBoardFailed": [0, '{}', 200],
+            "/openoapi/extsys/v1/vims":
+                [0, json.JSONEncoder().encode([{
+                    "vimId": "1", "type": VIM_OPENSTACK,
+                    "url": "/root/package", "userName": "tom",
+                    "password": "tom", "tenant": "10"}]), 200]}
+        mock_create_image.return_value = [0, {"id": "30", "name": "jerry", "res_type": 0}]
+        mock__init__.return_value = None
+        mock_get_image.return_value = [0, {"id": "30", "name": "jerry", "size": "60", "status": "0"}]
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+
+        mock_call_req.side_effect = side_effect
+        NfOnBoardingThread(csar_id="3", vim_ids=["1"], lab_vim_id="", job_id="6").run()
+        self.assert_job_result("6", 255, "Failed to create image:timeout(2 seconds.)")
+
+    @mock.patch.object(restcall, 'call_req')
+    @mock.patch.object(fileutil, 'download_file_from_http')
+    @mock.patch.object(VimAdaptor, '__init__')
+    @mock.patch.object(VimAdaptor, 'create_image')
+    def test_nf_on_boarding_when_failed_to_create_image(self, mock_create_image,
+                                                        mock__init__, mock_download_file_from_http, mock_call_req):
+        mock_download_file_from_http.return_value = True, "/root/package"
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/5":
+                [0, json.JSONEncoder().encode({
+                    "onBoardState": "onBoardFailed", "processState": "deleteFailed"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200'],
+            "/openoapi/catalog/v1/csars/5/files?relativePath=/SoftwareImages/image-lb":
+                [0, json.JSONEncoder().encode({
+                    "csar_file_info": [{"downloadUri": "8"}, {"localPath": "9"}]}), '200'],
+            "/openoapi/catalog/v1/csars/5?processState=onBoardFailed": [0, '{}', 200],
+            "/openoapi/extsys/v1/vims":
+                [0, json.JSONEncoder().encode([{
+                    "vimId": "1", "type": VIM_OPENSTACK,
+                    "url": "/root/package", "userName": "tom",
+                    "password": "tom", "tenant": "10"}]), '200']}
+        mock_create_image.return_value = [1, 'Unsupported image format.']
+        mock__init__.return_value = None
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+        NfOnBoardingThread(csar_id="5", vim_ids=["1"], lab_vim_id="", job_id="8").run()
+        self.assert_job_result("8", 255, "Failed to create image:Unsupported image format.")
+
+    #########################################################################
+    @mock.patch.object(restcall, 'call_req')
+    def test_get_csar_successfully(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            "name": "1", "provider": "2", "version": "3", "operationalState": "4",
+            "usageState": "5", "onBoardState": "6", "processState": "7",
+            "deletionPending": "8", "downloadUri": "9", "createTime": "10",
+            "modifyTime": "11", "format": "12", "size": "13"
+            }), '200']
+        NfPackageModel(uuid="1", vnfdid="001", vendor="vendor",
+                       vnfdversion="1.2.0", vnfversion="1.1.0", nfpackageid="13").save()
+        VnfPackageFileModel(id="1", filename="filename", imageid="00001",
+                            vimid="1", vimuser="001", tenant="12", status="1", vnfpid="13").save()
+        NfInstModel(nfinstid="1", mnfinstid="001", nf_name="name", package_id="13").save()
+        resp = self.client.get("/openoapi/nslcm/v1/vnfpackage/13")
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+        expect_data = {
+            "csarId": '13',
+            "packageInfo": {
+                "vnfdId": "001",
+                "vnfdProvider": "vendor",
+                "vnfdVersion": "1.2.0",
+                "vnfVersion": "1.1.0",
+                "name": "1",
+                "provider": "2",
+                "version": "3",
+                "operationalState": "4",
+                "usageState": "5",
+                "onBoardState": "6",
+                "processState": "7",
+                "deletionPending": "8",
+                "downloadUri": "9",
+                "createTime": "10",
+                "modifyTime": "11",
+                "format": "12",
+                "size": "13"},
+            "imageInfo": [{
+                "index": "0",
+                "fileName": "filename",
+                "imageId": "00001",
+                "vimId": "1",
+                "vimUser": "001",
+                "tenant": "12",
+                "status": "1"}],
+            "vnfInstanceInfo": [{
+                "vnfInstanceId": "1",
+                "vnfInstanceName": "name"}]}
+        self.assertEqual(expect_data, resp.data)
+
+    #########################################################################
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_pending_csar_when_successfully(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            "processState": "deleting"}), "200"]
+        NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
+        self.assert_job_result("2", 100, "Delete pending CSAR(1) successfully.")
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_pending_csar_when_deleting(self, mock_call_req):
+        NfPackageModel(uuid="01", nfpackageid="1").save()
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            "processState": "deleting"}), "200"]
+        NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
+        self.assert_job_result("2", 100, "CSAR(1) is deleting now.")
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_pending_csar_when_not_deletion_pending(self, mock_call_req):
+        NfPackageModel(uuid="01", nfpackageid="1").save()
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            "deletionPending": "false"}), "200"]
+        NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
+        self.assert_job_result("2", 100, "CSAR(1) need not to be deleted.")
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_pending_csar_when_in_using(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            "processState": "normal"}), "200"]
+        NfPackageModel(uuid="01", nfpackageid="1").save()
+        NfInstModel(nfinstid="01", package_id="1").save()
+        NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
+        self.assert_job_result("2", 100, "CSAR(1) is in using, cannot be deleted.")
+
+    @mock.patch.object(VimAdaptor, '__init__')
+    @mock.patch.object(VimAdaptor, 'delete_image')
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_csarr_when_exception(self, mock_call_req, mock_delete_image, mock_init_):
+        mock_vals = {
+            ("/openoapi/catalog/v1/csars/1", "DELETE"):
+                [1, "{}", "400"],
+            ("/openoapi/catalog/v1/csars/1?processState=deleting", "PUT"):
+                [0, "{}", "200"],
+            ("/openoapi/catalog/v1/csars/1?processState=deleteFailed", "PUT"):
+                [0, "{}", "200"],
+            ("/openoapi/catalog/v1/csars/1", "GET"):
+                [0, json.JSONEncoder().encode({"processState": "normal"}), "200"],
+            ("/openoapi/extsys/v1/vims", "GET"):
+                [0, json.JSONEncoder().encode([{"vimId": "002",
+                                                "url": "url_test",
+                                                "userName": "test01",
+                                                "password": "123456",
+                                                "tenant": "test"}]), "200"]}
+        mock_delete_image.return_value = [0, "", '200']
+
+        def side_effect(*args):
+            return mock_vals[(args[4], args[5])]
+
+        mock_call_req.side_effect = side_effect
+        mock_init_.return_value = None
+        VnfPackageFileModel(vnfpid="1", imageid="001", vimid="002").save()
+        NfPackageModel(uuid="01", nfpackageid="1").save()
+        NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
+        self.assert_job_result("2", 255, "Failed to delete CSAR(1) from catalog.")
+
+    @mock.patch.object(VimAdaptor, '__init__')
+    @mock.patch.object(VimAdaptor, 'delete_image')
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_csar_when_successfully(self, mock_call_req, mock_delete_image, mock_init_):
+        mock_vals = {
+            ("/openoapi/catalog/v1/csars/1", "DELETE"):
+                [0, json.JSONEncoder().encode({"successfully": "successfully"}), "200"],
+            ("/openoapi/catalog/v1/csars/1?processState=deleting", "PUT"):
+                [0, json.JSONEncoder().encode({"successfully": "successfully"}), "200"],
+            ("/openoapi/catalog/v1/csars/1?processState=deleteFailed", "PUT"):
+                [0, json.JSONEncoder().encode({"successfully": "successfully"}), "200"],
+            ("/openoapi/catalog/v1/csars/1", "GET"):
+                [0, json.JSONEncoder().encode({"notProcessState": "notProcessState"}), "200"],
+            ("/openoapi/extsys/v1/vims", "GET"):
+                [0, json.JSONEncoder().encode([{
+                    "vimId": "002",
+                    "url": "url_test",
+                    "userName": "test01",
+                    "password": "123456",
+                    "tenant": "test"}]), "200"]}
+        mock_delete_image.return_value = [0, json.JSONEncoder().encode({"test": "test"}), '200']
+
+        def side_effect(*args):
+            return mock_vals[(args[4], args[5])]
+
+        mock_call_req.side_effect = side_effect
+        mock_init_.return_value = None
+        VnfPackageFileModel(vnfpid="1", imageid="001", vimid="002").save()
+        NfPackageModel(uuid="01", nfpackageid="1").save()
+        NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
+        self.assert_job_result("2", 100, "Delete CSAR(1) successfully.")
+
+    #########################################################################
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_nf_pkg_when_deleting(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({"processState": "deleting"}), '200']
+        NfPkgDeleteThread(csar_id="1", job_id="2").run()
+        self.assert_job_result("2", 100, "CSAR(1) is deleting now.")
+        
+    
+    def test_get_nf_csars_normal(self):
+        NfPackageModel(uuid="01", nfpackageid="1", vnfdid="2").save()
+        resp = self.client.get("/openoapi/nslcm/v1/vnfpackage")
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+        self.assertEqual(1, len(resp.data["csars"]))
+        self.assertEqual("1", resp.data["csars"][0]["csarId"])
+        self.assertEqual("2", resp.data["csars"][0]["vnfdId"])
+        
+        
diff --git a/lcm/packages/tests/test_ns.py b/lcm/packages/tests/test_ns.py
new file mode 100644 (file)
index 0000000..391297d
--- /dev/null
@@ -0,0 +1,418 @@
+# Copyright 2016 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 mock
+from rest_framework import status
+from django.test import TestCase
+from django.test import Client
+
+from lcm.pub.utils import restcall
+from lcm.pub.database.models import NSDModel, NSInstModel, NfPackageModel
+
+
+class TestNsPackage(TestCase):
+    def setUp(self):
+        self.client = Client()
+        NSDModel.objects.filter().delete()
+        NSInstModel.objects.filter().delete()
+        NfPackageModel.objects.filter().delete()
+        self.nsd_raw_data = {
+            "rawData":{
+                "instance":{
+                    "metadata":{
+                        "vendor":"ZTE",
+                        "name":"VBRAS_NS",
+                        "csarVersion":1,
+                        "csarType":"NSAR",
+                        "csarProvider":"ZTE",
+                        "version":1,
+                        "invariant_id":"VBRAS_NS_NO_SFC",
+                        "id":"VBRAS_NS_ZTE_1.0",
+                        "description":"VBRAS_ZTE_NS"
+                    },
+                    "nodes":[
+                        {
+                            "id":"VBras_yfye7lsgi73p8j4p2a6vbguzd",
+                            "type_name":"tosca.nodes.nfv.ext.zte.VNF.VBras",
+                            "template_name":"VBras",
+                            "properties":{
+                                "vendor":{
+                                    "type_name":"string",
+                                    "value":"zte"
+                                },
+                                "name":{
+                                    "type_name":"string",
+                                    "value":"vbras"
+                                },
+                                "version":{
+                                    "type_name":"string",
+                                    "value":"1.0"
+                                },
+                                "vnf_type":{
+                                    "type_name":"string",
+                                    "value":"vbras"
+                                },
+                                "vnfd_version":{
+                                    "type_name":"string",
+                                    "value":"1.0.0"
+                                },
+                                "id":{
+                                    "type_name":"string",
+                                    "value":"zte_vbras_1.0"
+                                }
+                            }
+                        }
+                    ]
+                },
+                "model":{
+                    "metadata":{
+                        "vendor":"ZTE",
+                        "name":"VBRAS_NS",
+                        "csarVersion":1,
+                        "csarType":"NSAR",
+                        "csarProvider":"ZTE",
+                        "version":1,
+                        "invariant_id":"VBRAS_NS_NO_SFC",
+                        "id":"VBRAS_NS_ZTE_1.0",
+                        "description":"VBRAS_ZTE_NS"
+                    },
+                    "node_templates":[
+                        {
+                            "name":"VBras",
+                            "type_name":"tosca.nodes.nfv.ext.zte.VNF.VBras",
+                            "default_instances":1,
+                            "min_instances":0,
+                            "properties":{
+                                "vendor":{
+                                    "type_name":"string",
+                                    "value":"zte"
+                                },
+                                "name":{
+                                    "type_name":"string",
+                                    "value":"vbras"
+                                },
+                                "version":{
+                                    "type_name":"string",
+                                    "value":"1.0"
+                                },
+                                "vnf_type":{
+                                    "type_name":"string",
+                                    "value":"vbras"
+                                },
+                                "vnfd_version":{
+                                    "type_name":"string",
+                                    "value":"1.0.0"
+                                },
+                                "id":{
+                                    "type_name":"string",
+                                    "value":"zte_vbras_1.0"
+                                }
+                            },
+                            "requirement_templates":[
+                                {
+                                    "name":"lb_mnet_vl_cp",
+                                    "target_node_template_name":"ext_mnet_net",
+                                    "target_capability_name":"virtual_linkable"
+                                }
+                            ]
+                        }
+                    ]
+                }
+            }
+        }
+
+    def tearDown(self):
+        pass
+
+    def set_nsd_metadata(self, key, val):
+        self.nsd_raw_data["rawData"]["instance"]["metadata"][key] = val
+
+    def set_nsd_vnf_id(self, val):
+        self.nsd_raw_data["rawData"]["instance"]["nodes"][0]["properties"]["id"]["value"] = val
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_ns_pkg_on_boarding_when_on_boarded(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({"onBoardState": "onBoarded"}), '200']
+        resp = self.client.post("/openoapi/nslcm/v1/nspackage", {"csarId": "1"}, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("CSAR(1) already onBoarded.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_ns_pkg_on_boarding_when_nsd_already_exists(self, mock_call_req):
+        self.set_nsd_metadata(key="id", val="2")
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/2":
+                [0, json.JSONEncoder().encode({"onBoardState": "non-onBoarded"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.nsd_raw_data), '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+
+        NSDModel(id="1", nsd_id="2").save()
+        resp = self.client.post("/openoapi/nslcm/v1/nspackage", {"csarId": "2"}, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("NSD(2) already exists.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_ns_pkg_on_boarding_when_vnf_pkg_not_on_boarded(self, mock_call_req):
+        self.set_nsd_metadata(key="id", val="2")
+        self.set_nsd_vnf_id(val="3")
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/3":
+                [0, json.JSONEncoder().encode({"onBoardState": "non-onBoarded"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.nsd_raw_data), '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+
+        resp = self.client.post("/openoapi/nslcm/v1/nspackage", {"csarId": "3"}, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("VNF package(3) is not onBoarded.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_ns_pkg_on_boarding_when_vnf_pkg_not_on_boarded_on_catalog(self, mock_call_req):
+        self.set_nsd_metadata(key="id", val="2")
+        self.set_nsd_vnf_id(val="6")
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/4":
+                [0, json.JSONEncoder().encode({"onBoardState": "non-onBoarded"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.nsd_raw_data), '200'],
+            "/openoapi/catalog/v1/csars/5":
+                [0, json.JSONEncoder().encode({"onBoardState": "non-onBoarded"}), '200'], }
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+
+        NfPackageModel(uuid="1", nfpackageid="5", vnfdid="6").save()
+        resp = self.client.post("/openoapi/nslcm/v1/nspackage", {"csarId": "4"}, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("VNF package(5) is not onBoarded on catalog.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_ns_pkg_on_boarding_when_on_board_success(self, mock_call_req):
+        self.set_nsd_metadata(key="id", val="2")
+        self.set_nsd_metadata(key="name", val="3")
+        self.set_nsd_metadata(key="vendor", val="4")
+        self.set_nsd_metadata(key="description", val="5")
+        self.set_nsd_metadata(key="version", val="6")
+        self.set_nsd_vnf_id(val="7")
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/5":
+                [0, json.JSONEncoder().encode({
+                    "onBoardState": "non-onBoarded",
+                    "createTime": "2016-05-15 12:30:34",
+                    "modifyTime": "2016-05-15 12:30:34"}), '200'],
+            "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
+                [0, json.JSONEncoder().encode(self.nsd_raw_data), '200'],
+            "/openoapi/catalog/v1/csars/6":
+                [0, json.JSONEncoder().encode({"onBoardState": "onBoarded"}), '200'],
+            "/openoapi/catalog/v1/csars/5?operationalState=Enabled": [0, '{}', 200],
+            "/openoapi/catalog/v1/csars/5?onBoardState=onBoarded": [0, "OK", '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+
+        mock_call_req.side_effect = side_effect
+
+        NfPackageModel(uuid="1", nfpackageid="6", vnfdid="7").save()
+        resp = self.client.post("/openoapi/nslcm/v1/nspackage", {"csarId": "5"}, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("CSAR(5) onBoarded successfully.", resp.data["statusDescription"])
+        nsds = NSDModel.objects.filter(id="5")
+        self.assertEqual(1, len(nsds))
+        self.assertEqual("2", nsds[0].nsd_id)
+
+    ###############################################################################################################
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_csar_when_id_not_exist(self, mock_call_req):
+        mock_call_req.return_value = [0, "", '204']
+        resp = self.client.delete("/openoapi/nslcm/v1/nspackage/6")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("Delete CSAR(6) successfully.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_csar_when_ref_by_ns_inst(self, mock_call_req):
+        mock_call_req.return_value = [0, "OK", '200']
+
+        NSDModel(id="7", nsd_id="2").save()
+        NSInstModel(id="1", nspackage_id="7").save()
+
+        resp = self.client.delete("/openoapi/nslcm/v1/nspackage/7")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("Set deletionPending to True of CSAR(7) successfully.",
+                         resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_csar_when_delete_success(self, mock_call_req):
+        mock_call_req.return_value = [0, "OK", '204']
+
+        NSDModel(id="8", nsd_id="2").save()
+
+        resp = self.client.delete("/openoapi/nslcm/v1/nspackage/8")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("Delete CSAR(8) successfully.", resp.data["statusDescription"])
+
+    ###############################################################################################################
+    def test_delete_pending_csar_when_id_not_exist(self):
+        resp = self.client.delete("/openoapi/nslcm/v1/nspackage/9/deletionpending")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("Delete pending CSAR(9) successfully.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_pending_csar_when_pending_is_false(self, mock_call_req):
+        mock_call_req.return_value = [0, '{"deletionPending": "false"}', '200']
+        NSDModel(id="10", nsd_id="2").save()
+        resp = self.client.delete("/openoapi/nslcm/v1/nspackage/10/deletionpending")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("CSAR(10) need not to be deleted.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_pending_csar_when_refed_by_ns(self, mock_call_req):
+        mock_call_req.return_value = [0, '{"deletionPending": "true"}', '200']
+        NSDModel(id="11", nsd_id="2").save()
+        NSInstModel(id="1", nspackage_id="11").save()
+        resp = self.client.delete("/openoapi/nslcm/v1/nspackage/11/deletionpending")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("CSAR(11) is in using, cannot be deleted.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_delete_pending_csar_when_delete_success(self, mock_call_req):
+        mock_call_req.side_effect = [
+            [0, '{"deletionPending": "true"}', '200'],
+            [0, "OK", '204']]
+        NSDModel(id="12", nsd_id="2").save()
+        resp = self.client.delete("/openoapi/nslcm/v1/nspackage/12/deletionpending")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("Delete CSAR(12) successfully.", resp.data["statusDescription"])
+
+    ###############################################################################################################
+    @mock.patch.object(restcall, 'call_req')
+    def test_get_csar_successfully(self, mock_call_req):
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({
+            "name": "1",
+            "provider": "2",
+            "version": "3",
+            "operationalState": "4",
+            "usageState": "5",
+            "onBoardState": "6",
+            "processState": "7",
+            "deletionPending": "8",
+            "downloadUri": "9",
+            "createTime": "10",
+            "modifyTime": "11",
+            "format": "12",
+            "size": "13"
+            }), '200']
+
+        NSDModel(id="13", nsd_id="2", vendor="3", version="4").save()
+        NSInstModel(id="1", nspackage_id="13", name="11").save()
+        NSInstModel(id="2", nspackage_id="13", name="22").save()
+
+        resp = self.client.get("/openoapi/nslcm/v1/nspackage/13")
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+        expect_data = {"nsInstanceInfo": [{"nsInstanceId": "1", "nsInstanceName": "11"},
+                                          {"nsInstanceId": "2", "nsInstanceName": "22"}], "csarId": "13",
+                       "packageInfo": {"nsdProvider": "3", "usageState": "5",
+                                       "onBoardState": "6", "name": "1", "format": "12",
+                                       "modifyTime": "11", "nsdId": "2", "nsdVersion": "4",
+                                       "deletionPending": "8", "version": "3", "downloadUri": "9",
+                                       "processState": "7", "provider": "2", "operationalState": "4",
+                                       "createTime": "10", "size": "13"}}
+        self.assertEqual(expect_data, resp.data)
+
+    ###############################################################################################################
+    def test_disable_csar_when_id_not_exist_table(self):
+        resp = self.client.put("/openoapi/nslcm/v1/nspackage/14/disabled")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("CSAR(14) does not exist.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_disable_csar_when_csar_is_disabled(self, mock_call_req):
+        NSDModel(id="15", nsd_id="2").save()
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({"operationalState": "Disabled"}), '200']
+        resp = self.client.put("/openoapi/nslcm/v1/nspackage/15/disabled")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("CSAR(15) already disabled.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_disable_csar_successfully(self, mock_call_req):
+        NSDModel(id="16", nsd_id="2").save()
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/16":
+                [0, json.JSONEncoder().encode({"operationalState": "Enabled"}), '200'],
+            "/openoapi/catalog/v1/csars/16?operationState=Disabled":
+                [0, "OK", '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+
+        resp = self.client.put("/openoapi/nslcm/v1/nspackage/16/disabled")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("Set operationState to Disabled of CSAR(16) successfully.", resp.data["statusDescription"])
+
+    ###############################################################################################################
+    def test_enable_csar_when_id_not_exist_table(self):
+        resp = self.client.put("/openoapi/nslcm/v1/nspackage/17/enabled")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("CSAR(17) does not exist.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_enable_csar_when_csar_is_enabled(self, mock_call_req):
+        NSDModel(id="18", nsd_id="2").save()
+        mock_call_req.return_value = [0, json.JSONEncoder().encode({"operationalState": "Enabled"}), '200']
+        resp = self.client.put("/openoapi/nslcm/v1/nspackage/18/enabled")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("failed", resp.data["status"])
+        self.assertEqual("CSAR(18) already enabled.", resp.data["statusDescription"])
+
+    @mock.patch.object(restcall, 'call_req')
+    def test_enable_csar_successfully(self, mock_call_req):
+        NSDModel(id="19", nsd_id="2").save()
+        mock_vals = {
+            "/openoapi/catalog/v1/csars/19":
+                [0, json.JSONEncoder().encode({"operationalState": "Disabled"}), '200'],
+            "/openoapi/catalog/v1/csars/19?operationState=Enabled":
+                [0, "OK", '200']}
+
+        def side_effect(*args):
+            return mock_vals[args[4]]
+        mock_call_req.side_effect = side_effect
+
+        resp = self.client.put("/openoapi/nslcm/v1/nspackage/19/enabled")
+        self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual("success", resp.data["status"])
+        self.assertEqual("Set operationState to Enabled of CSAR(19) successfully.", resp.data["statusDescription"])
\ No newline at end of file
diff --git a/lcm/packages/urls.py b/lcm/packages/urls.py
new file mode 100644 (file)
index 0000000..89432c9
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2016 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.packages import views
+
+urlpatterns = [
+    url(r'^openoapi/nslcm/v1/nspackage/(?P<csarId>[0-9a-zA-Z\-\_]+)$', views.ns_access_csar, name='ns_access_csar'),
+    url(r'^openoapi/nslcm/v1/nspackage$', views.ns_on_boarding, name='ns_on_boarding'),
+    url(r'^openoapi/nslcm/v1/nspackage/(?P<csarId>[0-9a-zA-Z\-\_]+)/deletionpending$',
+        views.ns_delete_pending_csar, name='ns_delete_pending_csar'),
+    url(r'^openoapi/nslcm/v1/nspackage/(?P<csarId>[0-9a-zA-Z\-\_]+)/(?P<operation>(disabled|enabled))$',
+        views.ns_set_state_csar, name='ns_set_state_csar'),
+    url(r'^openoapi/nslcm/v1/vnfpackage/(?P<csarId>[0-9a-zA-Z\-\_]+)$', views.nf_access_csar, name='nf_access_csar'),
+    url(r'^openoapi/nslcm/v1/vnfpackage$', views.nf_on_boarding, name='nf_on_boarding'),
+    url(r'^openoapi/nslcm/v1/vnfpackage/(?P<csarId>[0-9a-zA-Z\-\_]+)/deletionpending$',
+        views.nf_delete_pending_csar, name='nf_delete_pending_csar'), ]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/packages/views.py b/lcm/packages/views.py
new file mode 100644 (file)
index 0000000..c50c741
--- /dev/null
@@ -0,0 +1,123 @@
+# Copyright 2016-2017 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 uuid
+
+from rest_framework import status
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.utils.syscomm import fun_name
+from lcm.packages import ns_package, nf_package
+
+logger = logging.getLogger(__name__)
+
+
+@api_view(http_method_names=['POST'])
+def ns_on_boarding(request, *args, **kwargs):
+    csar_id = ignore_case_get(request.data, "csarId")
+    logger.info("Enter %s, method is %s, csar_id is %s", fun_name(), request.method, csar_id)
+    ret = ns_package.ns_on_boarding(csar_id)
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    if ret[0] != 0:
+        return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+    return Response(data=ret[1], status=status.HTTP_202_ACCEPTED)
+
+
+@api_view(http_method_names=['GET', 'DELETE'])
+def ns_access_csar(request, *args, **kwargs):
+    csar_id = ignore_case_get(kwargs, "csarId")
+    logger.info("Enter %s, method is %s, csar_id is %s", fun_name(), request.method, csar_id)
+    ret, normal_status = None, None
+    if request.method == 'GET':
+        ret = ns_package.ns_get_csar(csar_id)
+        normal_status = status.HTTP_200_OK
+    else:
+        ret = ns_package.ns_delete_csar(csar_id)
+        normal_status = status.HTTP_202_ACCEPTED
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    if ret[0] != 0:
+        return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+    return Response(data=ret[1], status=normal_status)
+
+
+@api_view(http_method_names=['DELETE'])
+def ns_delete_pending_csar(request, *args, **kwargs):
+    csar_id = ignore_case_get(kwargs, "csarId")
+    logger.info("Enter %s, method is %s, csar_id is %s", fun_name(), request.method, csar_id)
+    ret = ns_package.ns_delete_pending_csar(csar_id)
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    if ret[0] != 0:
+        return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+    return Response(data=ret[1], status=status.HTTP_202_ACCEPTED)
+
+
+@api_view(http_method_names=['PUT'])
+def ns_set_state_csar(request, *args, **kwargs):
+    csar_id = ignore_case_get(kwargs, "csarId")
+    operation = ignore_case_get(kwargs, "operation")
+    logger.info("Enter %s, method is %s, csar_id is %s, operation is %s", fun_name(), request.method, csar_id, operation)
+    ret = ns_package.ns_set_state_csar(csar_id, operation)
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    if ret[0] != 0:
+        return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+    return Response(data=ret[1], status=status.HTTP_202_ACCEPTED)
+
+#################################################################################################################
+@api_view(http_method_names=['POST', 'GET'])
+def nf_on_boarding(request, *args, **kwargs):
+    logger.info("Enter %s%s, method is %s", fun_name(), request.data, request.method)
+    if request.method == 'GET':
+        ret = nf_package.NfPackage().get_csars()
+        logger.debug("csars=%s", str(ret))
+        return Response(data=ret, status=status.HTTP_200_OK)
+    csar_id = ignore_case_get(request.data, "csarId")
+    vim_ids = ignore_case_get(request.data, "vimIds")
+    lab_vim_id = ignore_case_get(request.data, "labVimId")
+    job_id = str(uuid.uuid4())
+    nf_package.NfOnBoardingThread(csar_id, vim_ids, lab_vim_id, job_id).start()
+    ret = {"jobId": job_id}
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    return Response(data=ret, status=status.HTTP_202_ACCEPTED)
+
+
+@api_view(http_method_names=['GET', 'DELETE'])
+def nf_access_csar(request, *args, **kwargs):
+    logger.info("Enter %s%s, method is %s", fun_name(), args, request.method)
+    csar_id = ignore_case_get(kwargs, "csarId")
+    if request.method == 'GET':
+        ret = nf_package.NfPackage().get_csar(csar_id)
+        logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+        if ret[0] != 0:
+            return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        return Response(data=ret[1], status=status.HTTP_200_OK)
+    # NF package deleting
+    job_id = str(uuid.uuid4())
+    nf_package.NfPkgDeleteThread(csar_id, job_id).start()
+    ret = {"jobId": job_id}
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    return Response(data=ret, status=status.HTTP_202_ACCEPTED)
+
+
+@api_view(http_method_names=['DELETE'])
+def nf_delete_pending_csar(request, *args, **kwargs):
+    logger.info("Enter %s%s, method is %s", fun_name(), args, request.method)
+    csar_id = ignore_case_get(kwargs, "csarId")
+    job_id = str(uuid.uuid4())
+    nf_package.NfPkgDeletePendingThread(csar_id, job_id).start()
+    ret = {"jobId": job_id}
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    return Response(data=ret, status=status.HTTP_202_ACCEPTED)
\ No newline at end of file
diff --git a/lcm/pub/__init__.py b/lcm/pub/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/config/__init__.py b/lcm/pub/config/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/config/config.py b/lcm/pub/config/config.py
new file mode 100644 (file)
index 0000000..462d1ba
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright 2016 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 os
+
+# [MSB]
+MSB_SERVICE_IP = '127.0.0.1'
+MSB_SERVICE_PORT = '80'
+
+# [IMAGE LOCAL PATH]
+ROOT_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+IMAGE_ROOT_PATH = os.path.join(ROOT_PATH, "/VmNfvo/VnfProduct")
+
+# [REDIS]
+REDIS_HOST = '127.0.0.1'
+REDIS_PORT = '6379'
+REDIS_PASSWD = ''
+
+# [mysql]
+DB_IP = "127.0.0.1"
+DB_PORT = 3306
+DB_NAME = "inventory"
+DB_USER = "inventory"
+DB_PASSWD = "inventory"
+
+# [register]
+REG_TO_MSB_WHEN_START = True
+REG_TO_MSB_REG_URL = "/openoapi/microservices/v1/services"
+REG_TO_MSB_REG_PARAM = {
+    "serviceName": "nslcm",
+    "version": "v1",
+    "url": "/openoapi/nslcm/v1",
+    "protocol": "REST",
+    "visualRange": "1",
+    "nodes": [{
+        "ip": "127.0.0.1",
+        "port": "8403",
+        "ttl": 0
+    }]
+}
+
+# delete image from vim option when delete csar
+IGNORE_DEL_IMG_WEHN_DEL_CSAR = True
diff --git a/lcm/pub/database/__init__.py b/lcm/pub/database/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/database/models.py b/lcm/pub/database/models.py
new file mode 100644 (file)
index 0000000..cb40c08
--- /dev/null
@@ -0,0 +1,303 @@
+# Copyright 2016 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.db import models
+
+
+class NSDModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_NSPACKAGE'
+
+    id = models.CharField(db_column='ID', primary_key=True, max_length=200)
+    nsd_id = models.CharField(db_column='NSDID', max_length=200)
+    name = models.CharField(db_column='NAME', max_length=200)
+    vendor = models.CharField(db_column='VENDOR', max_length=200, null=True, blank=True)
+    description = models.CharField(db_column='DESCRIPTION', max_length=200, null=True, blank=True)
+    version = models.CharField(db_column='VERSION', max_length=200, null=True, blank=True)
+    nsd_model = models.TextField(db_column='NSDMODEL', max_length=65535, null=True, blank=True)
+
+
+class NSInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_NSINST'
+
+    id = models.CharField(db_column='ID', primary_key=True, max_length=200)
+    name = models.CharField(db_column='NAME', max_length=200)
+    nspackage_id = models.CharField(db_column='NSPACKAGEID', max_length=200, null=True, blank=True)
+    nsd_id = models.CharField(db_column='NSDID', max_length=200)
+    description = models.CharField(db_column='DESCRIPTION', max_length=255, null=True, blank=True)
+    sdncontroller_id = models.CharField(db_column='SDNCONTROLLERID', max_length=200, null=True, blank=True)
+    flavour_id = models.CharField(db_column='FLAVOURID', max_length=200, null=True, blank=True)
+    ns_level = models.CharField(db_column='NSLEVEL', max_length=200, null=True, blank=True)
+    status = models.CharField(db_column='STATUS', max_length=200, null=True, blank=True)
+    nsd_model = models.TextField(db_column='NSDMODEL', max_length=20000, null=True, blank=True)
+    input_params = models.TextField(db_column='INPUTPARAMS', max_length=2000, null=True, blank=True)
+    scale_params = models.TextField(db_column='SCALEPARAMS', max_length=2000, null=True, blank=True)
+    create_time = models.CharField(db_column='CREATETIME', max_length=200, null=True, blank=True)
+    lastuptime = models.CharField(db_column='LASTUPTIME', max_length=200, null=True, blank=True)
+
+
+class NfPackageModel(models.Model):
+    uuid = models.CharField(db_column='UUID', primary_key=True, max_length=255)
+    nfpackageid = models.CharField(db_column='NFPACKAGEID', max_length=200)
+    vnfdid = models.CharField(db_column='VNFDID', max_length=255)
+    vendor = models.CharField(db_column='VENDOR', max_length=255)
+    vnfdversion = models.CharField(db_column='VNFDVERSION', max_length=255)
+    vnfversion = models.CharField(db_column='VNFVERSION', max_length=255)
+    vnfdmodel = models.TextField(db_column='VNFDMODEL', max_length=65535, blank=True, null=True)
+
+    class Meta:
+        db_table = 'NFVO_NFPACKAGE'
+
+
+class VnfPackageFileModel(models.Model):
+    id = models.AutoField(db_column='ID', primary_key=True)
+    vnfpid = models.CharField(db_column='NFPACKAGEID', max_length=50)
+    filename = models.CharField(db_column='FILENAME', max_length=100)
+    filetype = models.CharField(db_column='FILETYPE', max_length=2)
+    imageid = models.CharField(db_column='IMAGEID', max_length=50)
+    vimid = models.CharField(db_column='VIMID', max_length=50)
+    vimuser = models.CharField(db_column='VIMUSER', max_length=50)
+    tenant = models.CharField(db_column='TENANT', max_length=50)
+    purpose = models.CharField(db_column='PURPOSE', max_length=1000)
+    status = models.CharField(db_column='STATUS', max_length=10)
+
+    class Meta:
+        db_table = 'NFVO_NFPACKAGEFILE'
+
+
+class FPInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_FPINST'
+
+    fpid = models.CharField(db_column='FPID', max_length=255)
+    fpinstid = models.CharField(db_column='FPINSTID', max_length=255, primary_key=True)
+    fpname = models.CharField(db_column='FPNAME', max_length=255)
+    nsinstid = models.CharField(db_column='NSINSTID', max_length=255)
+    vnffginstid = models.CharField(db_column='VNFFGINSTID', max_length=255)
+    symmetric = models.IntegerField(db_column='SYMMETRIC', null=True)
+    policyinfo = models.TextField(db_column='POLICYINFO', max_length=65535)
+    forworderpaths = models.CharField(db_column='FORWORDERPATHS', max_length=255, null=True, blank=True)
+    status = models.CharField(db_column='STATUS', max_length=255)
+    sdncontrollerid = models.CharField(db_column='SDNCONTROLLERID', max_length=255)
+    sfcid = models.CharField(db_column='SFCID', max_length=255)
+    flowclassifiers = models.CharField(db_column='FLOWCLASSIFIERS', max_length=255)
+    portpairgroups = models.TextField(db_column='PORTPAIRGROUPS', max_length=65535)
+
+
+class VNFFGInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_VNFFGINST'
+
+    vnffgdid = models.CharField(db_column='VNFFGDID', max_length=255)
+    vnffginstid = models.CharField(db_column='VNFFGINSTID', max_length=255, primary_key=True)
+    nsinstid = models.CharField(db_column='NSINSTID', max_length=255)
+    desc = models.CharField(db_column='DESC', max_length=255, blank=True, null=True)
+    vendor = models.CharField(db_column='VENDOR', max_length=255, blank=True, null=True)
+    version = models.CharField(db_column='VERSION', max_length=255, blank=True, null=True)
+    endpointnumber = models.IntegerField(db_column='ENDPOINTNUMBER')
+    vllist = models.CharField(db_column='VLLIST', max_length=1024)
+    cplist = models.CharField(db_column='CPLIST', max_length=1024)
+    vnflist = models.CharField(db_column='VNFLIST', max_length=1024)
+    fplist = models.CharField(db_column='FPLIST', max_length=1024)
+    status = models.CharField(db_column='STATUS', max_length=255)
+
+
+class NfInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_NFINST'
+
+    nfinstid = models.CharField(db_column='NFINSTID', max_length=200, primary_key=True)
+    mnfinstid = models.CharField(db_column='M_NFINSTID', max_length=200, blank=True, null=True)
+    nf_name = models.CharField(db_column='NFNAME', max_length=100, blank=True, null=True)
+    template_id = models.CharField(db_column='TEMPLATEID', max_length=200, blank=True, null=True)
+    vnf_id = models.CharField(db_column='VNFID', max_length=200, blank=True, null=True)
+    package_id = models.CharField(db_column='PACKAGEID', max_length=200, blank=True, null=True)
+    vnfm_inst_id = models.CharField(db_column='VNFMINSTID', max_length=200, blank=True, null=True)
+    ns_inst_id = models.CharField(db_column='NSINSTID', max_length=200, blank=True, null=True)
+    status = models.CharField(db_column='STATUS', max_length=20, blank=True, null=True)
+    flavour_id = models.CharField(db_column='FLAVOURID', max_length=200, blank=True, null=True)
+    vnf_level = models.CharField(db_column='VNFLEVEL', max_length=200, blank=True, null=True)
+    location = models.CharField(db_column='LOCATION', max_length=200, blank=True, null=True)
+    max_vm = models.IntegerField(db_column='MAXVM', null=True)
+    max_cpu = models.IntegerField(db_column='MAXCPU', null=True)
+    max_ram = models.IntegerField(db_column='MAXRAM', null=True)
+    max_hd = models.IntegerField(db_column='MAXHD', null=True)
+    max_shd = models.IntegerField(db_column='MAXSHD', null=True)
+    max_net = models.IntegerField(db_column='MAXNET', null=True)
+    version = models.CharField(db_column='VERSION', max_length=255, null=True)
+    vendor = models.CharField(db_column='VENDOR', max_length=255, null=True, blank=True)
+    vnfd_model = models.TextField(db_column='VNFDMODEL', max_length=20000, blank=True, null=True)
+    input_params = models.TextField(db_column='INPUTPARAMS', max_length=2000, blank=True, null=True)
+    scale_params = models.TextField(db_column='SCALEPARAMS', max_length=2000, null=True, blank=True)
+    create_time = models.CharField(db_column='CREATETIME', max_length=200, null=True, blank=True)
+    lastuptime = models.CharField(db_column='LASTUPTIME', max_length=200, blank=True, null=True)
+    extension = models.TextField(db_column='EXTENSION', max_length=65535, blank=True, null=True)
+
+
+class VmInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_VMINST'
+
+    vmid = models.CharField(db_column='VMID', primary_key=True, max_length=255)
+    vimid = models.CharField(db_column='VIMID', max_length=255)
+    resouceid = models.CharField(db_column='RESOURCEID', max_length=255)
+    insttype = models.IntegerField(db_column='INSTTYPE', null=True)
+    instid = models.CharField(db_column='INSTID', max_length=255, null=True)
+    vmname = models.CharField(db_column='VMNAME', max_length=255)
+    operationalstate = models.IntegerField(db_column='OPERATIONALSTATE', default=1)
+    zoneid = models.CharField(db_column='ZONEID', max_length=255, null=True)
+    tenant = models.CharField(db_column='TENANT', max_length=255, null=True)
+    hostid = models.CharField(db_column='HOSTID', max_length=255)
+    detailinfo = models.CharField(db_column='DETAILINFO', max_length=255, null=True)
+
+
+class VNFCInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_VNFCINST'
+
+    vnfcinstanceid = models.CharField(db_column='VNFCINSTANCEID', max_length=255, primary_key=True)
+    vduid = models.CharField(db_column='VDUID', max_length=255)
+    nfinstid = models.CharField(db_column='NFINSTID', max_length=255)
+    vmid = models.CharField(db_column='VMID', max_length=255)
+    status = models.CharField(db_column='STATUS', max_length=255)
+
+
+class CPInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_CPINST'
+
+    cpinstanceid = models.CharField(db_column='CPINSTANCEID', max_length=255, primary_key=True)
+    cpdid = models.CharField(db_column='CPDID', max_length=255)
+    cpinstancename = models.CharField(db_column='CPINSTANCENAME', max_length=255)
+    ownertype = models.IntegerField(db_column='OWNERTYPE')
+    ownerid = models.CharField(db_column='OWNERID', max_length=255)
+    relatedtype = models.IntegerField(db_column='RELATEDTYPE')
+    relatedvl = models.CharField(db_column='RELATEDVL', max_length=255, blank=True, null=True)
+    relatedcp = models.CharField(db_column='RELATEDCP', max_length=255, blank=True, null=True)
+    relatedport = models.CharField(db_column='RELATEDPORT', max_length=255, blank=True, null=True)
+    status = models.CharField(db_column='STATUS', max_length=255)
+
+
+class VLInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_VLINST'
+
+    vlinstanceid = models.CharField(db_column='VLINSTANCEID', max_length=255, primary_key=True)
+    vldid = models.CharField(db_column='VLDID', max_length=255)
+    vlinstancename = models.CharField(db_column='VLINSTANCENAME', max_length=255, blank=True, null=True)
+    ownertype = models.IntegerField(db_column='OWNERTYPE')
+    ownerid = models.CharField(db_column='OWNERID', max_length=255)
+    relatednetworkid = models.CharField(db_column='RELATEDNETWORKID', max_length=255, blank=True, null=True)
+    relatedsubnetworkid = models.CharField(db_column='RELATEDSUBNETWORKID', max_length=255, blank=True, null=True)
+    vltype = models.IntegerField(db_column='VLTYPE', default=0)
+    vimid = models.CharField(db_column='VIMID', max_length=255)
+    tenant = models.CharField(db_column='TENANT', max_length=255)
+    status = models.CharField(db_column='STATUS', max_length=255)
+
+
+class PortInstModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_PORTINST'
+
+    portid = models.CharField(db_column='PORTID', max_length=255, primary_key=True)
+    networkid = models.CharField(db_column='NETWORKID', max_length=255)
+    subnetworkid = models.CharField(db_column='SUBNETWORKID', max_length=255)
+    vimid = models.CharField(db_column='VIMID', max_length=255)
+    resourceid = models.CharField(db_column='RESOURCEID', max_length=255)
+    name = models.CharField(db_column='NAME', max_length=255)
+    instid = models.CharField(db_column='INSTID', max_length=255)
+    cpinstanceid = models.CharField(db_column='CPINSTANCEID', max_length=255)
+    bandwidth = models.CharField(db_column='BANDWIDTH', max_length=255)
+    operationalstate = models.CharField(db_column='OPERATIONALSTATE', max_length=255)
+    ipaddress = models.CharField(db_column='IPADDRESS', max_length=255)
+    macaddress = models.CharField(db_column='MACADDRESS', max_length=255)
+    floatipaddress = models.CharField(db_column='FLOATIPADDRESS', max_length=255)
+    serviceipaddress = models.CharField(db_column='SERVICEIPADDRESS', max_length=255)
+    typevirtualnic = models.CharField(db_column='TYPEVIRTUALNIC', max_length=255)
+    sfcencapsulation = models.CharField(db_column='SFCENCAPSULATION', max_length=255)
+    direction = models.CharField(db_column='DIRECTION', max_length=255)
+    tenant = models.CharField(db_column='TENANT', max_length=255)
+
+
+class JobModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_JOB'
+
+    jobid = models.CharField(db_column='JOBID', primary_key=True, max_length=255)
+    jobtype = models.CharField(db_column='JOBTYPE', max_length=255)
+    jobaction = models.CharField(db_column='JOBACTION', max_length=255)
+    resid = models.CharField(db_column='RESID', max_length=255)
+    status = models.IntegerField(db_column='STATUS', null=True, blank=True)
+    starttime = models.CharField(db_column='STARTTIME', max_length=255, null=True, blank=True)
+    endtime = models.CharField(db_column='ENDTIME', max_length=255, null=True, blank=True)
+    progress = models.IntegerField(db_column='PROGRESS', null=True, blank=True)
+    user = models.CharField(db_column='USER', max_length=255, null=True, blank=True)
+    parentjobid = models.CharField(db_column='PARENTJOBID', max_length=255, null=True, blank=True)
+    resname = models.CharField(db_column='RESNAME', max_length=255, null=True, blank=True)
+
+    def toJSON(self):
+        import json
+        return json.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))
+
+
+class JobStatusModel(models.Model):
+    class Meta:
+        db_table = 'NFVO_JOB_STATUS'
+
+    indexid = models.IntegerField(db_column='INDEXID')
+    jobid = models.CharField(db_column='JOBID', max_length=255)
+    status = models.CharField(db_column='STATUS', max_length=255)
+    progress = models.IntegerField(db_column='PROGRESS', null=True, blank=True)
+    descp = models.TextField(db_column='DESCP', max_length=65535)
+    errcode = models.CharField(db_column='ERRCODE', max_length=255, null=True, blank=True)
+    addtime = models.CharField(db_column='ADDTIME', max_length=255, null=True, blank=True)
+
+    def toJSON(self):
+        import json
+        return json.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))
+
+
+class DefPkgMappingModel(models.Model):
+    class Meta:
+        db_table = 't_lcm_defPackage_mapping'
+
+    service_id = models.CharField(db_column='serviceId', max_length=255, primary_key=True)
+    service_def_id = models.CharField(db_column='serviceDefId', max_length=255)
+    template_id = models.CharField(db_column='templateId', max_length=255)
+    template_name = models.CharField(db_column='templateName', max_length=255)
+
+
+class InputParamMappingModel(models.Model):
+    class Meta:
+        db_table = 't_lcm_inputParam_mapping'
+
+    service_id = models.CharField(db_column='serviceId', max_length=255)
+    input_key = models.CharField(db_column='inputKey', max_length=255)
+    input_value = models.CharField(db_column='inputValue', max_length=255, null=True, blank=True)
+
+
+class ServiceBaseInfoModel(models.Model):
+    class Meta:
+        db_table = 't_lcm_servicebaseinfo'
+
+    service_id = models.CharField(db_column='serviceId', max_length=255, primary_key=True)
+    service_name = models.CharField(db_column='serviceName', max_length=255)
+    service_type = models.CharField(db_column='serviceType', max_length=20)
+    description = models.CharField(db_column='description', max_length=255, null=True, blank=True)
+    active_status = models.CharField(db_column='activeStatus', max_length=20)
+    status = models.CharField(db_column='status', max_length=20)
+    creator = models.CharField(db_column='creator', max_length=50)
+    create_time = models.BigIntegerField(db_column='createTime', max_length=20)
+    
\ No newline at end of file
diff --git a/lcm/pub/exceptions.py b/lcm/pub/exceptions.py
new file mode 100644 (file)
index 0000000..2c3f2ca
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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.
+
+
+class NSLCMException(Exception):
+    pass
diff --git a/lcm/pub/msapi/__init__.py b/lcm/pub/msapi/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/msapi/catalog.py b/lcm/pub/msapi/catalog.py
new file mode 100644 (file)
index 0000000..2444465
--- /dev/null
@@ -0,0 +1,104 @@
+# Copyright 2016 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.utils.restcall import req_by_msb
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.exceptions import NSLCMException
+
+logger = logging.getLogger(__name__)
+
+STATUS_ONBOARDED, STATUS_NON_ONBOARDED = "onBoarded", "non-onBoarded"
+P_STATUS_ENABLED, P_STATUS_DISABLED = "Enabled", "Disabled"
+P_STATUS_NORMAL, P_STATUS_ONBOARDING, P_STATUS_ONBOARDFAILED = "normal", "onBoarding", "onBoardFailed"
+P_STATUS_DELETING, P_STATUS_DELETEFAILED = "deleting", "deleteFailed"
+
+
+def query_csar_from_catalog(csar_id, key=''):
+    ret = req_by_msb("/openoapi/catalog/v1/csars/%s" % csar_id, "GET")
+    if ret[0] != 0:
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        if ret[2] == '404':
+            raise NSLCMException("CSAR(%s) does not exist." % csar_id)
+        raise NSLCMException("Failed to query CSAR(%s) from catalog." % csar_id)
+    csar_info = json.JSONDecoder().decode(ret[1])
+    return ignore_case_get(csar_info, key) if key else csar_info
+
+
+def query_rawdata_from_catalog(csar_id, input_parameters=[]):
+    req_param = json.JSONEncoder().encode({"csarId": csar_id, "inputParameters": input_parameters})
+    ret = req_by_msb("/openoapi/catalog/v1/servicetemplates/queryingrawdata", "POST", req_param)
+    if ret[0] != 0:
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        raise NSLCMException("Failed to query rawdata of CSAR(%s) from catalog." % csar_id)
+    return json.JSONDecoder().decode(ret[1])
+
+
+def set_csar_state(csar_id, prop, val):
+    ret = req_by_msb("/openoapi/catalog/v1/csars/%s?%s=%s" % (csar_id, prop, val), "PUT")
+    if ret[0] != 0:
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        return [1, "Failed to set %s to %s of CSAR(%s)." % (prop, val, csar_id)]
+    return [0, "Set %s to %s of CSAR(%s) successfully." % (prop, val, csar_id)]
+
+
+def delete_csar_from_catalog(csar_id):
+    ret = req_by_msb("/openoapi/catalog/v1/csars/%s" % csar_id, "DELETE")
+    if ret[0] != 0 and ret[2] != '404':
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        set_csar_state(csar_id, "processState", P_STATUS_DELETEFAILED)
+        return [1, "Failed to delete CSAR(%s) from catalog." % csar_id]
+    return [0, "Delete CSAR(%s) successfully." % csar_id]
+
+
+def get_download_url_from_catalog(csar_id, relative_path):
+    ret = req_by_msb("/openoapi/catalog/v1/csars/%s/files?relativePath=%s" % (csar_id, relative_path), "GET")
+    if ret[0] != 0:
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        raise NSLCMException("Failed to get download url of CSAR(%s)." % csar_id)
+    csar_file_info = json.JSONDecoder().decode(ret[1])
+    return ignore_case_get(csar_file_info, "downloadUri"), ignore_case_get(csar_file_info, "localPath")
+
+
+def get_process_id(name, srv_template_id):
+    ret = req_by_msb('/openoapi/catalog/v1/servicetemplates/%s/operations' % srv_template_id, 'GET')
+    if ret[0] != 0:
+        raise NSLCMException('Failed to get service[%s,%s] process id' % (name, srv_template_id))
+    items = json.JSONDecoder().decode(ret[1])
+    for item in items:
+        if name in item['name']:
+            return item['processId']
+    raise NSLCMException('service[%s,%s] process id not exist' % (name, srv_template_id))
+
+def get_servicetemplate_id(nsd_id):
+    ret = req_by_msb('/openoapi/catalog/v1/servicetemplates', 'GET')
+    if ret[0] != 0:
+        raise NSLCMException('Failed to get servicetemplates info')
+    stpls = json.JSONDecoder().decode(ret[1])
+    for stpl in stpls:
+        if stpl.get("id", "") == nsd_id:
+            return stpl["serviceTemplateId"]
+    raise NSLCMException('servicetemplate(%s) does not exist.' % nsd_id)
+    
+def get_servicetemplate(nsd_id):
+    ret = req_by_msb('/openoapi/catalog/v1/servicetemplates', 'GET')
+    if ret[0] != 0:
+        raise NSLCMException('Failed to get servicetemplates info')
+    stpls = json.JSONDecoder().decode(ret[1])
+    for stpl in stpls:
+        if stpl.get("id", "") == nsd_id:
+            return stpl
+    return NSLCMException('servicetemplate(%s) does not exist.' % nsd_id)
diff --git a/lcm/pub/msapi/extsys.py b/lcm/pub/msapi/extsys.py
new file mode 100644 (file)
index 0000000..0b76663
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright 2016 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.utils.restcall import req_by_msb
+
+logger = logging.getLogger(__name__)
+
+
+def get_vims():
+    ret = req_by_msb("/openoapi/extsys/v1/vims", "GET")
+    if ret[0] != 0:
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        raise NSLCMException("Failed to query vims from extsys.")
+    return json.JSONDecoder().decode(ret[1])
+
+
+def get_vim_by_id(vim_id):
+    ret = req_by_msb("/openoapi/extsys/v1/vims/%s" % vim_id, "GET")
+    if ret[0] != 0:
+        logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
+        raise NSLCMException("Failed to query vim(%s) from extsys." % vim_id)
+    return json.JSONDecoder().decode(ret[1])
+
+
+def get_sdn_controller_by_id(sdn_ontroller_id):
+    ret = req_by_msb("/openoapi/extsys/v1/sdncontrollers/%s" % sdn_ontroller_id, "GET")
+    if ret[0] != 0:
+        logger.error("Failed to query sdn ontroller(%s) from extsys. detail is %s.", sdn_ontroller_id, ret[1])
+        raise NSLCMException("Failed to query sdn ontroller(%s) from extsys." % sdn_ontroller_id)
+    return json.JSONDecoder().decode(ret[1])
+
+
+def get_vnfm_by_id(vnfm_inst_id):
+    uri = '/openoapi/extsys/v1/vnfms/%s' % vnfm_inst_id
+    ret = req_by_msb(uri, "GET")
+    if ret[0] > 0:
+        logger.error('Send get VNFM information request to extsys failed.')
+        raise NSLCMException('Send get VNFM information request to extsys failed.')
+    return json.JSONDecoder().decode(ret[1])
+
+def select_vnfm(vnfm_type, vim_id):
+    uri = '/openoapi/extsys/v1/vnfms'
+    ret = req_by_msb(uri, "GET")
+    if ret[0] > 0:
+        logger.error("Failed to call %s: %s", uri, ret[1])
+        raise NSLCMException('Failed to get vnfms from extsys.')
+    vnfms = json.JSONDecoder().decode(ret[1])
+    for vnfm in vnfms:
+        if vnfm["type"] == vnfm_type and vnfm["vimId"] == vim_id:
+            return vnfm
+    raise NSLCMException('No vnfm found with %s in vim(%s)' % (vnfm_type, vim_id))
+
diff --git a/lcm/pub/msapi/nslcm.py b/lcm/pub/msapi/nslcm.py
new file mode 100644 (file)
index 0000000..e62ad4c
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright 2016 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.utils.restcall import req_by_msb
+
+logger = logging.getLogger(__name__)
+
+def call_from_ns_cancel_resource(res_type, instid):
+    method = "DELETE"
+    if res_type == 'vl':
+        uri = '/openoapi/nslcm/v1/ns/vls/%s' % instid
+
+    elif res_type == 'sfc':
+        uri = '/openoapi/nslcm/v1/ns/sfcs/%s' % instid
+    else:
+        # vnf
+        method = "POST"
+        uri = '/openoapi/nslcm/v1/ns/vnfs/%s' % instid
+    req_param = {}
+    ret = req_by_msb(uri, method, json.dumps(req_param))
+    logger.info("[NS terminate] call vnfm [%s] result:%s" % (res_type, ret))
+    return ret
\ No newline at end of file
diff --git a/lcm/pub/msapi/resmgr.py b/lcm/pub/msapi/resmgr.py
new file mode 100644 (file)
index 0000000..d1fcc69
--- /dev/null
@@ -0,0 +1,122 @@
+# Copyright 2016 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.utils.restcall import req_by_msb
+
+logger = logging.getLogger(__name__)
+
+
+def create_vl(req_param):
+    ret = req_by_msb("/openoapi/resmgr/v1/vl", "POST", json.JSONEncoder().encode(req_param))
+    if ret[0] != 0:
+        logger.error("Failed to create vl to resmgr. detail is %s.", ret[1])
+        #raise NSLCMException('Failed to create vl to resmgr.')
+    #return json.JSONDecoder().decode(ret[1])
+
+
+def delete_vl(vl_inst_id):
+    ret = req_by_msb("/openoapi/resmgr/v1/vl/%s" % vl_inst_id, "DELETE")
+    if ret[0] != 0:
+        logger.error("Failed to delete vl(%s) to resmgr. detail is %s.", vl_inst_id, ret[1])
+        #raise NSLCMException("Failed to delete vl(%s) to resmgr." % vl_inst_id)
+
+
+def delete_sfc(sfc_inst_id):
+    ret = req_by_msb("/openoapi/resmgr/v1/sfc/%s" % sfc_inst_id, "DELETE")
+    if ret[0] != 0:
+        logger.error("Failed to delete sfc(%s) to resmgr. detail is %s.", sfc_inst_id, ret[1])
+        #raise NSLCMException("Failed to delete sfc(%s) to resmgr." % sfc_inst_id)
+
+
+def grant_vnf(req_param):
+    grant_data = json.JSONEncoder().encode(req_param)
+    ret = req_by_msb("/openoapi/resmgr/v1/resource/grant", "PUT", grant_data)
+    if ret[0] != 0:
+        logger.error("Failed to grant vnf to resmgr. detail is %s.", ret[1])
+        #raise NSLCMException('Failed to grant vnf to resmgr.')
+        vim_id = ""
+        if "vimId" in req_param:
+            vim_id = req_param["vimId"]
+        elif "additionalparam" in req_param and "vimid" in req_param["additionalparam"]:
+            vim_id = req_param["additionalparam"]["vimid"]
+        try:
+            from lcm.pub.msapi import extsys
+            vim = extsys.get_vim_by_id(vim_id)
+            if isinstance(vim, list):
+                vim = vim[0]
+                vim_id = vim["vimId"]
+            grant_rsp = {
+                "vim": {
+                    "vimid": vim_id,
+                    "accessinfo": {
+                        "tenant": vim["tenant"]
+                    }
+                }
+            }
+            logger.debug("grant_rsp=%s" % grant_rsp)
+            return grant_rsp
+        except:
+            raise NSLCMException('Failed to grant vnf to resmgr.')
+    return json.JSONDecoder().decode(ret[1])
+
+
+def create_vnf(data):
+    uri = '/openoapi/resmgr/v1/vnf'
+    req_param = json.JSONEncoder().encode({
+        'orchVnfInstanceId': data['nf_inst_id'],
+        'vnfInstanceId': data['vnfm_nf_inst_id'],
+        'vnfInstanceName': data['vnf_inst_name'],
+        'nsId': data['ns_inst_id'],
+        'nsName': data['ns_inst_name'],
+        'vnfmId': data['vnfm_inst_id'],
+        'vnfmName': data['vnfm_inst_name'],
+        'vnfPackageName': data['vnfd_name'],
+        'vnfDescriptorName': data['vnfd_id'],
+        'jobId': data['job_id'],
+        'vnfStatus': data['nf_inst_status'],
+        'vnfType': data['vnf_type'],
+        'onboardingId': data['nf_package_id'],
+        'onboardingName': data['vnfd_name']})
+
+    ret = req_by_msb(uri, "POST", req_param)
+    if ret[0] != 0:
+        logger.error('Send create VNF request to resmgr failed.')
+        #raise NSLCMException('Send create VNF request to resmgr failed.')
+
+
+def create_vnf_creation_info(data):
+    uri = '/openoapi/resmgr/v1/vnfinfo'
+    req_param = json.JSONEncoder().encode({
+        'vnfInstanceId': data['nf_inst_id'],
+        'nsId': data['ns_inst_id'],
+        'vnfmId': data['vnfm_inst_id'],
+        'vms': data['vms']})
+
+    ret = req_by_msb(uri, "POST", req_param)
+    if ret[0] > 0:
+        logger.error('Send write vnf creation information to resmgr failed.')
+        #raise NSLCMException('Send write vnf creation information to resmgr failed.')
+
+
+def terminate_vnf(vnf_inst_id):
+    uri = '/openoapi/resmgr/v1/vnf/%s' % vnf_inst_id
+    req_param = {}
+    ret = req_by_msb(uri, "DELETE", json.dumps(req_param))
+    if ret[0] > 0:
+        logger.error('Send terminate VNF request to resmgr failed.')
+        #raise NSLCMException('Send terminate VNF request to resmgr failed.')
\ No newline at end of file
diff --git a/lcm/pub/msapi/sdncdriver.py b/lcm/pub/msapi/sdncdriver.py
new file mode 100644 (file)
index 0000000..f2331ce
--- /dev/null
@@ -0,0 +1,85 @@
+# Copyright 2016 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.utils.restcall import req_by_msb
+
+logger = logging.getLogger(__name__)
+
+
+def delete_port_chain(req_param):
+    url = "/openoapi/sdncdriver/v1/delchain"
+    str = "delete port chain"
+    delete_func(req_param, url, str)
+
+
+def delete_flow_classifier(req_param):
+    url = "/openoapi/sdncdriver/v1/delclassifier"
+    str = "delete flow classifier"
+    delete_func(req_param, url, str)
+
+
+def delete_port_pair_group(req_param):
+    url = "/openoapi/sdncdriver/v1/delportpairgroup"
+    str = "delete port pair"
+    delete_func(req_param, url, str)
+
+
+def delete_port_pair(req_param):
+    url = "/openoapi/sdncdriver/v1/delportpair"
+    str = "delete port pair"
+    delete_func(req_param, url, str)
+
+
+def delete_func(req_param, url, str):
+    ret = req_by_msb(url, "DELETE", json.JSONEncoder().encode(req_param))
+    if ret[0] != 0:
+        logger.error("Failed to %s to sdncdriver. detail is %s.", str, ret[1])
+        raise NSLCMException('Failed to %s to sdncdriver.' % str)
+
+
+def create_flow_classfier(data):
+    url = "/openoapi/ztesdncdriver/v1/createflowclassfier"
+    str = "create flow classfier"
+    return create(data, url, str)
+
+
+def create_port_pair(data):
+    url = "/openoapi/ztesdncdriver/v1/createportpair"
+    str = "create port pair"
+    return create(data, url, str)
+
+
+def create_port_pair_group(data):
+    url = "/openoapi/ztesdncdriver/v1/createportpairgroup"
+    str = "create port pair group"
+    return create(data, url, str)
+
+
+def create_port_chain(data):
+    url = "/openoapi/ztesdncdriver/v1/createportchain"
+    str = "create port chain"
+    return create(data, url, str)
+
+
+def create(req_param, url, str):
+    ret = req_by_msb(url, "POST", json.dumps(req_param))
+    if ret[0] != 0:
+        logger.error("Failed to %s to sdncdriver. detail is %s.", str, ret[1])
+        raise NSLCMException('Failed to %s to sdncdriver.' % str)
+    resp_body = json.loads(ret[1])
+    return resp_body["id"]
diff --git a/lcm/pub/msapi/tosca.py b/lcm/pub/msapi/tosca.py
new file mode 100644 (file)
index 0000000..5db971d
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2016 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
+
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.restcall import req_by_msb
+
+
+def tosca_plan(uri, inputs):
+    """
+    https://wiki.open-o.org/view/Common_TOSCA_API_Documentation
+    """
+    content = {"uri": uri, "inputs": inputs}
+    content_str = json.JSONEncoder().encode(content)
+    ret = req_by_msb("/openoapi/tosca/v1/indirect/instance", "POST", content_str)
+    if ret[0] != 0:
+        raise NSLCMException("status code is %s, detail is %s.", ret[2], ret[1])
+    if ret[2] != '200':
+        raise NSLCMException("tosca error occur when call parser api failed: %s" % content_str)
+    return ret[1]
diff --git a/lcm/pub/msapi/vnfmdriver.py b/lcm/pub/msapi/vnfmdriver.py
new file mode 100644 (file)
index 0000000..5da08d2
--- /dev/null
@@ -0,0 +1,69 @@
+# Copyright 2016 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.utils.restcall import req_by_msb
+from lcm.pub.utils.values import ignore_case_get
+from lcm.pub.msapi.extsys import get_vnfm_by_id
+
+logger = logging.getLogger(__name__)
+
+
+def send_nf_init_request(vnfm_inst_id, req_param):
+    vnfm = get_vnfm_by_id(vnfm_inst_id)
+    uri = '/openoapi/%s/v1/%s/vnfs' % (vnfm["type"], vnfm_inst_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)' % vnfm_inst_id)
+    return json.JSONDecoder().decode(ret[1])
+
+def send_nf_terminate_request(vnfm_inst_id, vnf_inst_id, req_param):
+    vnfm = get_vnfm_by_id(vnfm_inst_id)
+    uri = '/openoapi/%s/v1/%s/vnfs/%s/terminate' % (vnfm["type"], vnfm_inst_id, vnf_inst_id)
+    ret = req_by_msb(uri, "POST", req_param)
+    if ret[0] > 0:
+        logger.error("Failed to send nf terminate req:%s,%s", ret[2], ret[1])
+        raise NSLCMException('Failed to send nf terminate request to VNFM(%s)' % vnfm_inst_id)
+    return json.JSONDecoder().decode(ret[1]) if ret[1] else {}
+
+def query_vnfm_job(vnfm_inst_id, job_id, response_id=0):
+    vnfm = get_vnfm_by_id(vnfm_inst_id)
+    retry_time = 3
+    uri = '/openoapi/%s/v1/%s/jobs/%s?responseId=%s' % (vnfm["type"], 
+        vnfm_inst_id, job_id, response_id)
+    while retry_time > 0:
+        rsp = req_by_msb(uri, "GET")
+        if str(rsp[2]) == '404':
+            return False, ''
+        if rsp[0] != 0:
+            logger.warning('retry_time=%s, detail message:%s' % (retry_time, rsp[1]))
+            retry_time -= 1
+        else:
+            break
+    if retry_time <= 0:
+        logger.error(rsp[1])
+        raise NSLCMException('Failed to query job from VNFM!')
+    return True, json.JSONDecoder().decode(rsp[1])
+
+def send_nf_scaling_request(vnfm_inst_id, vnf_inst_id, req_param):
+    vnfm = get_vnfm_by_id(vnfm_inst_id)
+    uri = '/openoapi/%s/v1/%s/vnfs/%s/scale' % (vnfm["type"], vnfm_inst_id, vnf_inst_id)
+    ret = req_by_msb(uri, "POST", req_param)
+    if ret[0] > 0:
+        logger.error("Failed to send nf scale req:%s,%s", ret[2], ret[1])
+        raise NSLCMException('Failed to send nf scale request to VNFM(%s)' % vnfm_inst_id)
+    return json.JSONDecoder().decode(ret[1])
diff --git a/lcm/pub/msapi/wso2bpel.py b/lcm/pub/msapi/wso2bpel.py
new file mode 100644 (file)
index 0000000..afc1c40
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright 2016 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
+
+from lcm.pub.exceptions import NSLCMException
+from lcm.pub.utils.restcall import req_by_msb
+
+
+def workflow_run(content):
+    content_str = json.JSONEncoder().encode(content)
+    ret = req_by_msb("/openoapi/wso2bpel/v1/process/instance", "POST", content_str)
+    if ret[0] != 0:
+        raise NSLCMException("Status code is %s, detail is %s.", ret[2], ret[1])
+    return json.JSONDecoder().decode(ret[1])
diff --git a/lcm/pub/nfvi/__init__.py b/lcm/pub/nfvi/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/nfvi/vim/__init__.py b/lcm/pub/nfvi/vim/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/nfvi/vim/api/__init__.py b/lcm/pub/nfvi/vim/api/__init__.py
new file mode 100644 (file)
index 0000000..f5e4379
--- /dev/null
@@ -0,0 +1,10 @@
+# Copyright 2016 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/pub/nfvi/vim/api/multivim/__init__.py b/lcm/pub/nfvi/vim/api/multivim/__init__.py
new file mode 100644 (file)
index 0000000..8d66b23
--- /dev/null
@@ -0,0 +1,10 @@
+# Copyright 2017 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/pub/nfvi/vim/api/multivim/api.py b/lcm/pub/nfvi/vim/api/multivim/api.py
new file mode 100644 (file)
index 0000000..f3bdd30
--- /dev/null
@@ -0,0 +1,321 @@
+# Copyright 2017 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.nfvi.vim.lib.vimexception import VimException
+from lcm.pub.utils.restcall import req_by_msb
+from lcm.pub.nfvi.vim import const
+
+logger = logging.getLogger(__name__)
+
+VIM_DRIVER_BASE_URL = "openoapi/multivim/v1"
+
+def call(vim_id, tenant_id, res, method, data=''):
+    if data and not isinstance(data, (str, unicode)):
+        data = json.JSONEncoder().encode(data)
+    url = "{base_url}/{vim_id}{tenant_id}/{res}".format(
+        base_url=VIM_DRIVER_BASE_URL, 
+        vim_id=vim_id,
+        tenant_id="/" + tenant_id if tenant_id else "",
+        res=res)
+    ret = req_by_msb(url, method, data)
+    if ret[0] > 0:
+        raise VimException(ret[1], ret[2])
+    return json.JSONDecoder().decode(ret[1]) if ret[1] else {}
+
+######################################################################
+
+def create_image(vim_id, tenant_id, data):
+    return call(vim_id, tenant_id, "images", "POST", data)
+
+def delete_image(vim_id, tenant_id, image_id):
+    return call(vim_id, tenant_id, "images/%s" % image_id, "DELETE")
+    
+def get_image(vim_id, tenant_id, image_id):
+    return call(vim_id, tenant_id, "images/%s" % image_id, "GET")
+    
+def list_image(vim_id, tenant_id):
+    return call(vim_id, tenant_id, "images", "GET")
+
+######################################################################
+
+def create_network(vim_id, tenant_id, data):
+    return call(vim_id, tenant_id, "networks", "POST", data)
+
+def delete_network(vim_id, tenant_id, network_id):
+    return call(vim_id, tenant_id, "networks/%s" % network_id, "DELETE")
+    
+def get_network(vim_id, tenant_id, network_id):
+    return call(vim_id, tenant_id, "networks/%s" % network_id, "GET")
+    
+def list_network(vim_id, tenant_id):
+    return call(vim_id, tenant_id, "networks", "GET")
+
+######################################################################
+
+def create_subnet(vim_id, tenant_id, data):
+    return call(vim_id, tenant_id, "subnets", "POST", data)
+
+def delete_subnet(vim_id, tenant_id, subnet_id):
+    return call(vim_id, tenant_id, "subnets/%s" % subnet_id, "DELETE")
+    
+def get_subnet(vim_id, tenant_id, subnet_id):
+    return call(vim_id, tenant_id, "subnets/%s" % subnet_id, "GET")
+    
+def list_subnet(vim_id, tenant_id):
+    return call(vim_id, tenant_id, "subnets", "GET")
+
+######################################################################
+
+def create_port(vim_id, tenant_id, data):
+    return call(vim_id, tenant_id, "ports", "POST", data)
+
+def delete_port(vim_id, tenant_id, port_id):
+    return call(vim_id, tenant_id, "ports/%s" % port_id, "DELETE")
+    
+def get_port(vim_id, tenant_id, port_id):
+    return call(vim_id, tenant_id, "ports/%s" % port_id, "GET")
+    
+def list_port(vim_id, tenant_id):
+    return call(vim_id, tenant_id, "ports", "GET")
+
+######################################################################
+
+def create_flavor(vim_id, tenant_id, data):
+    return call(vim_id, tenant_id, "flavors", "POST", data)
+
+def delete_flavor(vim_id, tenant_id, flavor_id):
+    return call(vim_id, tenant_id, "flavors/%s" % flavor_id, "DELETE")
+    
+def get_flavor(vim_id, tenant_id, flavor_id):
+    return call(vim_id, tenant_id, "flavors/%s" % flavor_id, "GET")
+    
+def list_flavor(vim_id, tenant_id):
+    return call(vim_id, tenant_id, "flavors", "GET")
+
+######################################################################
+
+def create_vm(vim_id, tenant_id, data):
+    return call(vim_id, tenant_id, "servers", "POST", data)
+
+def delete_vm(vim_id, tenant_id, vm_id):
+    return call(vim_id, tenant_id, "servers/%s" % vm_id, "DELETE")
+    
+def get_vm(vim_id, tenant_id, vm_id):
+    return call(vim_id, tenant_id, "servers/%s" % vm_id, "GET")
+    
+def list_vm(vim_id, tenant_id):
+    return call(vim_id, tenant_id, "servers", "GET")
+
+######################################################################
+
+def create_volume(vim_id, tenant_id, data):
+    return call(vim_id, tenant_id, "volumes", "POST", data)
+
+def delete_volume(vim_id, tenant_id, volume_id):
+    return call(vim_id, tenant_id, "volumes/%s" % volume_id, "DELETE")
+    
+def get_volume(vim_id, tenant_id, volume_id):
+    return call(vim_id, tenant_id, "volumes/%s" % volume_id, "GET")
+    
+def list_volume(vim_id, tenant_id):
+    return call(vim_id, tenant_id, "volumes", "GET")
+
+######################################################################
+
+def list_tenant(vim_id, tenant_name=""):
+    res = "tenants"
+    if tenant_name:
+        res = "%s?name=%s" % (res, tenant_name)
+    return call(vim_id, "", res, "GET")
+
+######################################################################
+
+
+class MultiVimApi:
+
+    def login(self, connect_info):
+        self.vim_id = connect_info["vimid"]
+        self.tenant_name = connect_info["tenant"]
+        tenants = list_tenant(self.vim_id)
+        for tenant in tenants["tenants"]:
+            if self.tenant_name == tenant["name"]:
+                self.tenant_id = tenant["id"]
+                return [0, connect_info]
+        raise VimException(1, "Tenant(%s) not exist" % self.tenant_name)
+
+    def query_net(self, auth_info, net_id):
+        net = get_network(self.vim_id, self.tenant_id, net_id)
+        return [0, {
+            "id": net.get("id", ""),
+            "name": net.get("name", ""),
+            "status": net.get("status", ""),
+            "admin_state_up": net.get("admin_state_up", True),
+            "network_type": net.get("networkType", ""),
+            "physical_network": net.get("physicalNetwork", ""),
+            "segmentation_id": net.get("segmentationId", ""),
+            "tenant_id": self.tenant_id,
+            "tenant_name": self.tenant_name,
+            "subnets": net.get("subnets", []),
+            "shared": net.get("shared", True),
+            "router_external": net.get("routerExternal", "")
+        }]
+
+    def query_nets(self, auth_info):
+        nets = list_network(self.vim_id, self.tenant_id)
+        return [0, {"networks": [{
+            "id": net.get("id", ""),
+            "name": net.get("name", ""),
+            "status": net.get("status", ""),
+            "admin_state_up": net.get("admin_state_up", True),
+            "network_type": net.get("networkType", ""),
+            "physical_network": net.get("physicalNetwork", ""),
+            "segmentation_id": net.get("segmentationId", ""),
+            "tenant_id": self.tenant_id,
+            "tenant_name": self.tenant_name,
+            "subnets": net.get("subnets", []),
+            "shared": net.get("shared", True),
+            "router_external": net.get("routerExternal", "")
+        } for net in nets["networks"]]}]      
+
+    def query_subnet(self, auth_info, subnet_id):
+        subnet_info = get_subnet(self.vim_id, self.tenant_id, subnet_id)
+        ret = [0, {}]
+        ret[1]["id"] = subnet_id
+        ret[1]["name"] = subnet_info.get("name", "")
+        ret[1]["status"] = ""
+        ret[1]["ip_version"] = subnet_info.get("ipVersion", 4)
+        ret[1]["cidr"] = subnet_info.get("cidr", "")
+        ret[1]["allocation_pools"] = subnet_info.get("allocationPools", [])
+        ret[1]["enable_dhcp"] = subnet_info.get("enableDhcp", False)
+        ret[1]["gateway_ip"] = subnet_info.get("gatewayIp", "")
+        ret[1]["host_routes"] = subnet_info.get("hostRoutes", [])
+        ret[1]["dns_nameservers"] = subnet_info.get("dnsNameservers", [])
+        return ret
+
+    def query_port(self, auth_info, port_id):
+        port_info = get_port(self.vim_id, self.tenant_id, port_id)
+        ret = [0, {}]
+        ret[1]["id"] = port_id
+        ret[1]["name"] = port_info.get("name", "")
+        ret[1]["network_id"] = port_info.get("networkId", "")
+        ret[1]["tenant_id"] = self.tenant_id,
+        ret[1]["ip"] = port_info.get("ip", "")
+        ret[1]["subnet_id"] = port_info.get("subnetId", "")
+        ret[1]["mac_address"] = port_info.get("macAddress", "")
+        ret[1]["status"] = port_info.get("status", "")
+        ret[1]["admin_state_up"] = port_info.get("admin_state_up", True)
+        ret[1]["device_id"] = port_info.get("device_id", "")
+        return ret
+
+    def create_port(self, auth_info, data):
+        return [0, data]
+
+    def delete_port(self, auth_info, port_id):
+        return [0, ""]
+
+    def create_image(self, auth_info, data):
+        image_data = {
+            "name": data["image_name"],
+            "imagePath": data["image_url"],
+            "imageType": data["image_type"],
+            "containerFormat": "bare",
+            "visibility": "public",
+            "properties": [] 
+        }
+        image = create_image(self.vim_id, self.tenant_id, image_data)
+        return [0, {
+            "id": image["id"], 
+            "name": image["name"], 
+            const.RES_TYPE_KEY: image["returnCode"]}]
+
+    def get_image(self, auth_info, image_id):
+        image = get_image(self.vim_id, self.tenant_id, image_id)
+        return [0, {
+            "id": image["id"], 
+            "name": image["name"], 
+            "size": image["size"], 
+            "status": image["status"]}]      
+
+    def get_images(self, auth_info):
+        images = list_image(self.vim_id, self.tenant_id)
+        return [0, {"image_list": [{
+            "id": img["id"], 
+            "name": img["name"], 
+            "size": img["size"], 
+            "status": img["status"]
+            } for img in images["images"]]}]
+
+    def delete_image(self, auth_info, image_id):
+        return [0, ""]
+
+    def create_network(self, auth_info, data):
+        net_data = {
+            "name": data["network_name"],
+            "shared": True,
+            "networkType": data["network_type"]
+        }
+        if "physical_network" in data and data['physical_network']:
+            net_data["physicalNetwork"] = data['physical_network']
+        if "vlan_transparent" in data and data["vlan_transparent"]: 
+            net_data["vlanTransparent"] = data["vlan_transparent"]
+        if "segmentation_id" in data and data['segmentation_id']:
+            net_data["segmentationId"] = data["segmentation_id"]
+        if "routerExternal" in data and data['routerExternal']:
+            net_data["routerExternal"] = data["routerExternal"]
+        net = create_network(self.vim_id, self.tenant_id, net_data)
+        network_id = net["id"]
+        ret_net = {
+            "status": net.get("status", ""),
+            "id": network_id,
+            "name": net.get("name", ""),
+            "provider:segmentation_id": net.get("segmentationId", ""),
+            "provider:network_type": net.get("networkType", ""),
+            const.RES_TYPE_KEY: net["returnCode"],
+            "subnet_list": []
+        }
+        if "subnet_list" in data and data["subnet_list"]:
+            subnet = data["subnet_list"][0]           
+            subnet_data = {
+                "networkId": network_id,
+                "name": subnet["subnet_name"],
+                "cidr": subnet["cidr"],
+                "ipVersion": const.IPV4,
+                "enableDhcp": False           
+            }
+            if "ip_version" in subnet and subnet["ip_version"]:
+                subnet_data["ipVersion"] = int(subnet["ip_version"])
+            if "enable_dhcp" in subnet and subnet["enable_dhcp"]:
+                subnet_data["enableDhcp"] = int(subnet["enable_dhcp"]) == const.ENABLE_DHCP
+            if "gateway_ip" in subnet and subnet["gateway_ip"]:
+                subnet_data["gatewayIp"] = subnet["gateway_ip"]
+            if "dns_nameservers" in subnet and subnet["dns_nameservers"]:
+                subnet_data["dnsNameservers"] = subnet["dns_nameservers"]
+            if "allocation_pools" in subnet and subnet["allocation_pools"]:
+                subnet_data["allocationPools"] = subnet["allocation_pools"]
+            if "host_routes" in subnet and subnet["host_routes"]:
+                subnet_data["hostRoutes"] = subnet["host_routes"]
+            subnet_create = create_subnet(self.vim_id, self.tenant_id, subnet_data)
+            ret_net["subnet_list"].append({
+                "id": subnet_create["id"],
+                "name": subnet_create["name"],
+                const.RES_TYPE_KEY: net["returnCode"]})
+        return [0, ret_net]
+
+    def delete_network(self, auth_info, network_id):
+        return delete_network(self.vim_id, self.tenant_id, network_id)
+
+    def delete_subnet(self, auth_info, subnet_id):
+        return delete_subnet(self.vim_id, self.tenant_id, subnet_id)
diff --git a/lcm/pub/nfvi/vim/api/openstack/__init__.py b/lcm/pub/nfvi/vim/api/openstack/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/nfvi/vim/api/openstack/api.py b/lcm/pub/nfvi/vim/api/openstack/api.py
new file mode 100644 (file)
index 0000000..f781e47
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright 2016 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.nfvi.vim.api.openstack import auth, network, image
+
+
+class OpenstackApi:
+
+    def login(self, connect_info):
+        return auth.login(connect_info)
+
+    def query_net(self, auth_info, net_id):
+        return network.query_net(auth_info, net_id)
+
+    def query_nets(self, auth_info):
+        return network.query_nets(auth_info)
+
+    def query_subnet(self, auth_info, subnet_id):
+        return network.query_subnet(auth_info, subnet_id)
+
+    def query_port(self, auth_info, port_id):
+        return network.query_port(auth_info, port_id)
+
+    def create_port(self, auth_info, data):
+        return network.create_port(auth_info, data)
+
+    def delete_port(self, auth_info, port_id):
+        return network.delete_port(auth_info, port_id)
+
+    def create_image(self, auth_info, data):
+        return image.create_image(auth_info, data)
+
+    def get_image(self, auth_info, image_id):
+        return image.get_image(auth_info, image_id)
+
+    def get_images(self, auth_info):
+        return image.get_images(auth_info)
+
+    def delete_image(self, auth_info, image_id):
+        return image.delete_image(auth_info, image_id)
+
+    def create_network(self, auth_info, data):
+        return network.create_network(auth_info, data)
+
+    def delete_network(self, auth_info, network_id):
+        return network.delete_network(auth_info, network_id)
+
+    def delete_subnet(self, auth_info, subnet_id):
+        return network.delete_subnet(auth_info, subnet_id)
diff --git a/lcm/pub/nfvi/vim/api/openstack/auth.py b/lcm/pub/nfvi/vim/api/openstack/auth.py
new file mode 100644 (file)
index 0000000..b662c51
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright 2016 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 keystoneclient.v2_0 import client
+
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+
+logger = logging.getLogger(__name__)
+
+OPENSTACK_CA_CERT = '/etc/httpd/conf.d/cert/vim/ca.cert'
+OPENSTACK_CLIENT_CERT = '/etc/httpd/conf.d/cert/vim/client.cert'
+OPENSTACK_CLIENT_KEY = '/etc/httpd/conf.d/cert/vim/client.key'
+
+
+def login(connect_info):
+    url, user = connect_info["url"], connect_info["user"]
+    passwd, tenant = connect_info["passwd"], connect_info["tenant"]
+    cacert, clientcert, clientkey = None, None, None
+    insecure = url.startswith('https')
+    logger.info(
+        "[%s]client.Client(auth_url='%s',"
+        "username='%s',password='%s',"
+        "tenant_name='%s',insecure=%s,cert='%s',key='%s',cacert='%s')" %
+        (fun_name(), url, user, passwd, tenant, insecure, clientcert, clientkey, cacert))
+    connect_info["cacert"] = cacert
+    connect_info["clientcert"] = clientcert
+    connect_info["clientkey"] = clientkey
+    connect_info["insecure"] = insecure
+    connect_info["keystone"] = client.Client(auth_url=url, username=user, password=passwd, interface='public',
+                                             tenant_name=tenant, insecure=insecure, cert=clientcert, key=clientkey,
+                                             cacert=cacert, debug=True)
+    ret = [0, connect_info]
+    return ret
diff --git a/lcm/pub/nfvi/vim/api/openstack/glancebase.py b/lcm/pub/nfvi/vim/api/openstack/glancebase.py
new file mode 100644 (file)
index 0000000..cfcde4f
--- /dev/null
@@ -0,0 +1,43 @@
+# Copyright 2016 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
+
+logger = logging.getLogger(__name__)
+
+
+def get_glance(funname, auth_info, ver='v2'):
+    import glanceclient.v1.client as glanceclient1
+    import glanceclient.v2.client as glanceclient2
+    keystone = auth_info["keystone"]
+    cacert = auth_info["cacert"]
+    clientcert = auth_info["clientcert"]
+    clientkey = auth_info["clientkey"]
+    insecure = auth_info["insecure"]
+    glance_endpoint = keystone.service_catalog.url_for(service_type='image')
+    logger.info("[%s]call glanceclient.Client('%s',token='%s',insecure=%s,cert_file='%s',key_file='%s',cacert='%s')"
+                % (funname, glance_endpoint, keystone.auth_token, insecure, clientcert, clientkey, cacert))
+    if 'v1' == ver:
+        logger.info("return glanceclient1")
+        return glanceclient1.Client(glance_endpoint,
+                                    token=keystone.auth_token,
+                                    insecure=insecure,
+                                    cert_file=clientcert,
+                                    key_file=clientkey,
+                                    cacert=cacert)
+    else:
+        logger.info("return glanceclient2")
+        return glanceclient2.Client(glance_endpoint,
+                                    token=keystone.auth_token,
+                                    insecure=insecure,
+                                    cert_file=clientcert,
+                                    key_file=clientkey,
+                                    cacert=cacert)
diff --git a/lcm/pub/nfvi/vim/api/openstack/image.py b/lcm/pub/nfvi/vim/api/openstack/image.py
new file mode 100644 (file)
index 0000000..2a04cb9
--- /dev/null
@@ -0,0 +1,106 @@
+# Copyright 2016 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 sys
+import traceback
+import threading
+
+from lcm.pub.nfvi.vim.api.openstack import glancebase
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim import const
+
+logger = logging.getLogger(__name__)
+
+
+class ImageUploadThread(threading.Thread):
+    def __init__(self, glance, image_id, image_path):
+        threading.Thread.__init__(self)
+        self.glance = glance
+        self.image_id = image_id
+        self.image_path = image_path
+
+    def run(self):
+        try:
+            self.glance.images.upload(self.image_id, open(self.image_path, 'rb'))
+        except Exception as ex:
+            logger.error(traceback.format_exc())
+            err_msg = ex.message if ex.message else str(sys.exc_info())
+            logger.error("Failed to upload image(%s): %s", self.image_id, err_msg)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error("Failed to upload image(%s): [%s]", self.image_id, str(sys.exc_info()))
+
+
+def create_image(auth_info, data):
+    ret = None
+    glance = glancebase.get_glance(fun_name(), auth_info)
+
+    exist_img = [img for img in glance.images.list() if img.name == data["image_name"]]
+    if exist_img:
+        ret = [0, {"id": exist_img[0].id, "name": data["image_name"], const.RES_TYPE_KEY: const.RES_TYPE_EXIST}]
+    else:
+        img = glance.images.create(
+            name=data["image_name"],
+            disk_format=data["image_type"],
+            visibility='public',
+            container_format='bare')
+        ret = [0, {"id": img.id, "name": data["image_name"], const.RES_TYPE_KEY: const.RES_TYPE_NEW}]
+        try:
+            ImageUploadThread(glance, img.id, data["image_path"]).start()
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+    return ret
+
+
+def get_image(auth_info, image_id):
+    from glanceclient.exc import HTTPNotFound
+    glance = glancebase.get_glance(fun_name(), auth_info)
+    img = None
+    try:
+        img = glance.images.get(image_id)
+    except HTTPNotFound:
+        logger.warn("Exception: %s" % str(sys.exc_info()))
+        return [2, "Image(%s) does not exist" % image_id]
+    ret_img_info = get_single_image(img)
+    if 'status' in ret_img_info and 'deleted' == ret_img_info["status"]:
+        return [2, "Image(%s) is deleted" % image_id]
+    return [0, ret_img_info]
+
+
+def delete_image(auth_info, image_id):
+    from glanceclient.exc import HTTPNotFound
+    glance = glancebase.get_glance(fun_name(), auth_info)
+    try:
+        glance.images.delete(image_id)
+    except HTTPNotFound:
+        logger.warn("Exception: %s" % str(sys.exc_info()))
+        return [0, "Image(%s) does not exist" % image_id]
+    return [0, "Image(%s) has been deleted" % image_id]
+
+
+def get_images(auth_info):
+    glance = glancebase.get_glance(fun_name(), auth_info)
+    imgs = glance.images.list()
+    return [0, {"image_list": [get_single_image(img) for img in imgs]}]
+
+
+def get_single_image(img):
+    img_size = 0
+    try:
+        img_size = img.size / 1024
+    except:
+        pass
+    return {"id": img.id, "name": img.name, "size": img_size, "status": img.status}
diff --git a/lcm/pub/nfvi/vim/api/openstack/network.py b/lcm/pub/nfvi/vim/api/openstack/network.py
new file mode 100644 (file)
index 0000000..ebfdf66
--- /dev/null
@@ -0,0 +1,423 @@
+# Copyright 2016 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 sys
+import traceback
+
+from neutronclient.common.exceptions import NeutronClientException
+from neutronclient.common.exceptions import NetworkNotFoundClient
+from neutronclient.common.exceptions import NotFound as SubnetNotFound
+
+from lcm.pub.nfvi.vim.api.openstack import neutronbase
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim.api.openstack import project
+from lcm.pub.nfvi.vim import const
+from lcm.pub.nfvi.vim.lib.vimexception import VimException
+
+logger = logging.getLogger(__name__)
+
+
+def query_net(auth_info, net_id):
+    neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+    net = None
+    try:
+        net = neutron.show_network(net_id)["network"]
+        keystone = auth_info["keystone"]
+        tenant = keystone.tenants.get(tenant_id=net["tenant_id"])
+    except NetworkNotFoundClient as e:
+        logger.warn("NetworkNotFoundClient: %s", e.message)
+        return [2, e.message]
+    return [0, {
+        "id": net["id"],
+        "name": net["name"],
+        "status": net["status"],
+        "admin_state_up": net["admin_state_up"],
+        "network_type": net["provider:network_type"],
+        "physical_network": net["provider:physical_network"],
+        "segmentation_id": net["provider:segmentation_id"],
+        "tenant_id": net["tenant_id"],
+        "tenant_name": tenant.name,
+        "subnets": net["subnets"],
+        "shared": net["shared"],
+        "router_external": net["router:external"]
+        }]
+
+
+def query_nets(auth_info):
+    neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+    keystone = auth_info["keystone"]
+    tenants_map = {}
+    tenants = keystone.tenants.list()
+    for tenant in tenants:
+        tenants_map[tenant.id] = tenant.name
+
+    nets = neutron.list_networks()
+    return [0, {"networks": [{
+        "id": net["id"],
+        "name": net["name"],
+        "status": net["status"],
+        "admin_state_up": net["admin_state_up"],
+        "network_type": net["provider:network_type"],
+        "physical_network": net["provider:physical_network"],
+        "segmentation_id": net["provider:segmentation_id"],
+        "tenant_id": net["tenant_id"],
+        "tenant_name": tenants_map[net["tenant_id"]] if net["tenant_id"] in tenants_map else "unknown",
+        "subnets": net["subnets"],
+        "shared": net["shared"],
+        "router_external": net["router:external"]
+        } for net in nets["networks"]]}]
+
+
+def query_subnet(auth_info, subnet_id):
+    neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+    subnet_info = None
+    try:
+        subnet_info = neutron.show_subnet(subnet_id)["subnet"]
+    except SubnetNotFound as e:
+        logger.warn("SubnetNotFound: %s", e.message)
+        return [2, e.message]
+    ret = [0, {}]
+    ret[1]["id"] = subnet_id
+    ret[1]["name"] = subnet_info["name"]
+    ret[1]["status"] = ""
+    ret[1]["ip_version"] = subnet_info["ip_version"]
+    ret[1]["cidr"] = subnet_info["cidr"]
+    ret[1]["allocation_pools"] = subnet_info["allocation_pools"]
+    ret[1]["enable_dhcp"] = subnet_info["enable_dhcp"]
+    ret[1]["gateway_ip"] = subnet_info["gateway_ip"]
+    ret[1]["host_routes"] = subnet_info["host_routes"]
+    ret[1]["dns_nameservers"] = subnet_info["dns_nameservers"]
+    return ret
+
+
+def query_port(auth_info, port_id):
+    neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+    port_info = None
+    try:
+        port_info = neutron.show_port(port_id)["port"]
+    except NeutronClientException as e:
+        logger.warn("NeutronClientException: %s", e.message)
+        return [2, e.message]
+    ret = [0, {}]
+    ret[1]["id"] = port_id
+    ret[1]["name"] = port_info["name"]
+    ret[1]["network_id"] = port_info["network_id"]
+    ret[1]["tenant_id"] = port_info["tenant_id"]
+    if "fixed_ips" in port_info and port_info["fixed_ips"]:
+        ret[1]["ip"] = port_info["fixed_ips"][0]["ip_address"]
+        ret[1]["subnet_id"] = port_info["fixed_ips"][0]["subnet_id"]
+    else:
+        ret[1]["ip"] = ""
+        ret[1]["subnet_id"] = ""
+    ret[1]["mac_address"] = port_info["mac_address"]
+    ret[1]["status"] = port_info["status"]
+    ret[1]["admin_state_up"] = port_info["admin_state_up"]
+    ret[1]["device_id"] = port_info["device_id"]
+    return ret
+
+
+def get_subnet_id(neutron, data, network_id):
+    subnet_id = None
+    if "subnet_name" in data and data["subnet_name"]:
+        all_subnets = neutron.list_subnets()
+        filter_subnets = [subnet for subnet in all_subnets["subnets"] if subnet["name"] == data["subnet_name"]
+                          and subnet["network_id"] == network_id]
+        count_filter_subnets = len(filter_subnets)
+        if 1 > count_filter_subnets:
+            logger.error("Subnet name(%s) does not exist" % data["subnet_name"])
+            raise VimException("Subnet name(%s) does not exist" % data["subnet_name"])
+        if 1 < count_filter_subnets:
+            for subnet in filter_subnets:
+                logger.error("subnet_id=%s", subnet["id"])
+            raise VimException("%d subnet(%s) exist in network(%s)"
+                               % (count_filter_subnets, data["subnet_name"], data["network_name"]))
+        subnet_id = filter_subnets[0]['id']
+    else:
+        subnets = neutron.list_subnets()
+        filter_subnets = [subnet for subnet in subnets["subnets"] if subnet["network_id"] == network_id]
+        if filter_subnets:
+            subnet_id = filter_subnets[0]["id"]
+    return subnet_id
+
+
+def create_port(auth_info, data):
+    tenant_id = project.get_tenant_id(fun_name(), auth_info, data["tenant_name"])
+
+    neutron_admin = neutronbase.get_neutron_default(fun_name(), auth_info)
+    all_nets = neutron_admin.list_networks()
+    filter_nets = [net for net in all_nets['networks'] if net['name'] == data["network_name"]]
+    sel_nets = [net for net in filter_nets if net['tenant_id'] == tenant_id or
+                (net['tenant_id'] != tenant_id and net['shared'])]
+    count_sel_nets = len(sel_nets)
+    if 1 > count_sel_nets:
+        logger.error("Network(%s) does not exist" % data["network_name"])
+        raise VimException("Network(%s) does not exist" % data["network_name"])
+    if 1 < count_sel_nets:
+        for net in sel_nets:
+            logger.error("net_id=%s", net["id"])
+        raise VimException("%d networks(%s) exist in tenant(%s)"
+                           % (count_sel_nets, data["network_name"], data["tenant_name"]))
+    network_id = sel_nets[0]['id']
+    if tenant_id != sel_nets[0]['tenant_id']:
+        neutron = neutronbase.get_neutron_by_tenant_id(fun_name(), auth_info, sel_nets[0]['tenant_id'])
+    else:
+        neutron = neutronbase.get_neutron(fun_name(), auth_info, data["tenant_name"])
+
+    # get subnet id
+    subnet_id = get_subnet_id(neutron_admin, data, network_id)
+
+    # check port
+    port_data = None
+    ports = neutron.list_ports()
+    sel_ports = [port for port in ports['ports'] if port['tenant_id'] == tenant_id
+                 and port['network_id'] == network_id]
+    filter_ports = []
+    for port in sel_ports:
+        if port['name'] == data["port_name"] and port['fixed_ips']:
+            for fixed_ip in port['fixed_ips']:
+                if fixed_ip['subnet_id'] == subnet_id:
+                    filter_ports.append(port)
+                    break
+    count_filter_ports = len(filter_ports)
+    if 1 < count_filter_ports:
+        for port in filter_ports:
+            logger.error("port_id=%s", port["id"])
+        raise VimException("%d port(%s) exist in subnet(%s)"
+                           % (count_filter_ports, data["port_name"], data["subnet_name"]))
+    if 1 == len(filter_ports):
+        logger.debug("Port(%s) is exist!" % data["port_name"])
+        port_data = {'status': filter_ports[0]['status'],
+                     'id': filter_ports[0]['id'],
+                     'name': filter_ports[0]['name'],
+                     'network_id': filter_ports[0]['network_id'],
+                     const.RES_TYPE_KEY: const.RES_TYPE_EXIST}
+        return [0, port_data]
+
+    # create port
+    create_param = {'port': {
+            'name': data["port_name"],
+            'admin_state_up': True,
+            'network_id': network_id,
+            'security_groups': [],
+            'tenant_id': tenant_id}}
+    if "mac_address" in data and data["mac_address"]:
+        create_param['port']['mac_address'] = data["mac_address"]
+    if "vnic_type" in data and data["vnic_type"]:
+        create_param['port']['binding:vnic_type'] = data["vnic_type"]
+    if "bandwidth" in data and data["bandwidth"]:
+        create_param['port']['bandwidth'] = int(data["bandwidth"])
+    if "bond" in data and data["bond"]:
+        create_param['port']['bond'] = int(data["bond"])
+    if "macbond" in data and data["macbond"]:
+        if 'mac_address' in create_param['port']:
+            create_param['port']['mac_address'] += (',' + data["macbond"])
+        else:
+            create_param['port']['mac_address'] = data["macbond"]
+    if "ip" in data and data["ip"]:
+        if subnet_id:
+            create_param['port']['fixed_ips'] = [{"subnet_id": subnet_id, "ip_address": data["ip"]}]
+
+    if "allowed_address_pairs" in data and data["allowed_address_pairs"]:
+        create_param['port']['allowed_address_pairs'] = data["allowed_address_pairs"]
+    logger.info("[%s]call neutron.create_port(%s)" % (fun_name(), str(create_param)))
+    port_created = None
+    try:
+        port_created = neutron.create_port(create_param)
+    except NeutronClientException as ex:
+        logger.info("create_port exception: %s, %s", str(sys.exc_info()), ex.message)
+        create_param['port'].pop('security_groups')
+        if 'allowed_address_pairs' in create_param['port']:
+            create_param['port'].pop('allowed_address_pairs')
+        logger.info("[%s]recall neutron.create_port(%s)" % (fun_name(), str(create_param)))
+        port_created = neutron.create_port(create_param)
+    if port_created:
+        port_data = {'status': port_created['port']['status'],
+                     'id': port_created['port']['id'],
+                     'name': port_created['port']['name'],
+                     'network_id': port_created['port']['network_id'],
+                     const.RES_TYPE_KEY: const.RES_TYPE_NEW}
+    return [0, port_data]
+
+
+def create_network(auth_info, data):
+    neutron = neutronbase.get_neutron(fun_name(), auth_info, data["tenant"])
+    tenant_id = project.get_tenant_id(fun_name(), auth_info, data["tenant"])
+
+    neutron_admin = neutronbase.get_neutron_default(fun_name(), auth_info)
+    all_nets = neutron_admin.list_networks()
+    filter_nets = [net for net in all_nets['networks'] if net['name'] == data["network_name"]]
+    sel_nets = [net for net in filter_nets if net['tenant_id'] == tenant_id or
+                (net['tenant_id'] != tenant_id and net['shared'])]
+    count_sel_nets = len(sel_nets)
+    if 1 < count_sel_nets:
+        for sel_net in sel_nets:
+            logger.info("net_id=%s, net_tenant_id=%s", sel_net["id"], sel_net['tenant_id'])
+        raise VimException("Already %d networks are found with name %s" % (count_sel_nets, data["network_name"]))
+
+    network_data = None
+    if sel_nets:
+        if sel_nets[0]['tenant_id'] != tenant_id:
+            neutron = neutronbase.get_neutron_by_tenant_id(fun_name(), auth_info, sel_nets[0]['tenant_id'])
+        all_subnets = neutron_admin.list_subnets()
+        filter_subnets = [subnet for subnet in all_subnets["subnets"] if subnet["network_id"] == sel_nets[0]["id"]]
+        network_data = {"status": sel_nets[0]["status"],
+                        "id": sel_nets[0]["id"],
+                        "name": data["network_name"],
+                        "provider:segmentation_id": sel_nets[0]["provider:segmentation_id"],
+                        "provider:network_type": sel_nets[0]["provider:network_type"],
+                        const.RES_TYPE_KEY: const.RES_TYPE_EXIST,
+                        "subnet_list": [{
+                                            "id": subnet["id"],
+                                            "name": subnet["name"],
+                                            const.RES_TYPE_KEY: const.RES_TYPE_EXIST
+                                        } for subnet in filter_subnets]}
+    else:
+        create_params = {
+            'network': {
+                'name': data["network_name"],
+                'admin_state_up': True,
+                'tenant_id': tenant_id,
+                'shared': "shared" in data and int(data["shared"]) == const.SHARED_NET}}
+        if "mtu" in data and int(data["mtu"]) != const.DEFAULT_MTU:
+            create_params['network']['mtu'] = int(data["mtu"])
+        if "vlan_transparent" in data and int(data["vlan_transparent"]) == const.SUPPORT_VLAN_TRANSPARENT:
+            create_params['network']['vlan-transparent'] = True
+        if "network_type" in data and data['network_type']:
+            create_params['network']['provider:network_type'] = data['network_type']
+        if "segmentation_id" in data and data['segmentation_id']:
+            create_params['network']['provider:segmentation_id'] = int(data['segmentation_id'])
+        if "physical_network" in data and data['physical_network']:
+            create_params['network']['provider:physical_network'] = data['physical_network']
+
+        logger.info("[%s]call neutron.create_network(%s)" % (fun_name(), str(create_params)))
+        network_created = neutron.create_network(create_params)
+        network_data = {"status": network_created['network']['status'],
+                        "id": network_created['network']['id'],
+                        "name": data["network_name"],
+                        "provider:segmentation_id": network_created['network']['provider:segmentation_id'],
+                        "provider:network_type": network_created['network']['provider:network_type'],
+                        const.RES_TYPE_KEY: const.RES_TYPE_NEW,
+                        "subnet_list": []}
+
+    # subnet create
+    exist_subnet_names = [subnet["name"] for subnet in network_data["subnet_list"]]
+    need_rollback, ret_error = False, None
+    if "subnet_list" in data and data["subnet_list"]:
+        for subnet_data in data["subnet_list"]:
+            if subnet_data["subnet_name"] in exist_subnet_names:
+                continue
+            ret = create_subnet(neutron, network_data["id"], subnet_data)
+            if ret[0] != 0:
+                need_rollback, ret_error = True, ret
+                break
+            network_data["subnet_list"].append(ret[1])
+
+    # rollback when failed to create subnet
+    if need_rollback:
+        rollback(neutron_admin, network_data)
+        return ret_error
+
+    return [0, network_data]
+
+
+def create_subnet(neutron, network_id, data):
+    all_subnets = neutron.list_subnets()
+    filter_subnets = [subnet for subnet in all_subnets["subnets"]
+                      if subnet["network_id"] == network_id and subnet["name"] == data["subnet_name"]]
+    if filter_subnets:
+        return [0, {
+                    "id": filter_subnets[0]["id"],
+                    "name": data["subnet_name"],
+                    const.RES_TYPE_KEY: const.RES_TYPE_EXIST}]
+    try:
+        create_params = {
+            'subnet': {
+                'network_id': network_id,
+                'name': data["subnet_name"],
+                'cidr': data["cidr"],
+                'ip_version': int(data["ip_version"]) if "ip_version" in data else const.IPV4, }}
+        create_params["subnet"]["enable_dhcp"] = ("enable_dhcp" in data
+                                                  and int(data["enable_dhcp"]) == const.ENABLE_DHCP)
+        if "gateway_ip" in data and data["gateway_ip"]:
+            create_params["subnet"]["gateway_ip"] = data["gateway_ip"]
+        else:
+            create_params["subnet"]["gateway_ip"] = None
+        if "dns_nameservers" in data and data["dns_nameservers"]:
+            create_params["subnet"]["dns_nameservers"] = data["dns_nameservers"]
+        if "allocation_pools" in data and data["allocation_pools"]:
+            create_params["subnet"]["allocation_pools"] = data["allocation_pools"]
+        if "host_routes" in data and data["host_routes"]:
+            create_params["subnet"]["host_routes"] = data["host_routes"]
+
+        logger.info("[%s]call neutron.create_subnet(%s)" % (fun_name(), str(create_params)))
+        subnet_created = neutron.create_subnet(create_params)
+        return [0, {"id": subnet_created["subnet"]["id"],
+                    "name": data["subnet_name"],
+                    const.RES_TYPE_KEY: const.RES_TYPE_NEW}]
+    except Exception as ex:
+        logger.error(traceback.format_exc())
+        logger.error(str(sys.exc_info()))
+        return [1, ex.message if ex.message else str(sys.exc_info())]
+
+
+def rollback(neutron, network_data):
+    for subnet_data in network_data["subnet_list"]:
+        if subnet_data[const.RES_TYPE_KEY] == const.RES_TYPE_NEW:
+            try:
+                logger.info("[%s]call neutron.delete_subnet(%s)" % (fun_name(), subnet_data["id"]))
+                neutron.delete_subnet(subnet_data["subnet_id"])
+            except:
+                logger.error("[%s]%s", fun_name(), str(sys.exc_info()))
+
+    if network_data and network_data[const.RES_TYPE_KEY] == const.RES_TYPE_NEW:
+        try:
+            logger.info("[%s]call neutron.delete_network(%s)" % (fun_name(), network_data["id"]))
+            neutron.delete_network(network_data["id"])
+        except:
+            logger.error("[%s]%s", fun_name(), str(sys.exc_info()))
+
+
+def delete_network(auth_info, network_id):
+    neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+    try:
+        neutron.delete_network(network_id)
+    except Exception as ex:
+        logger.error(traceback.format_exc())
+        msg = ex.message if ex.message else str(sys.exc_info())
+        logger.error(msg)
+        if 404 == ex.status_code:
+            return [0, ex.message]
+        return [1, "Vim exception."]
+    return [0, "Network(%s) is deleted" % network_id]
+
+
+def delete_subnet(auth_info, subnet_id):
+    neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+    try:
+        neutron.delete_subnet(subnet_id)
+    except NeutronClientException as e:
+        logger.warn("[%s]NetworkNotFoundClient: %s", fun_name(), e.message)
+        return [0, e.message]
+    return [0, "Subnet(%s) is deleted" % subnet_id]
+
+
+def delete_port(auth_info, port_id):
+    neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+    try:
+        neutron.delete_port(port_id)
+    except NeutronClientException as e:
+        logger.warn("[%s]NeutronClientException: %s", fun_name(), e.message)
+        return [0, e.message]
+    return [0, "Port(%s) is deleted" % port_id]
diff --git a/lcm/pub/nfvi/vim/api/openstack/neutronbase.py b/lcm/pub/nfvi/vim/api/openstack/neutronbase.py
new file mode 100644 (file)
index 0000000..1a755cc
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright 2016 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 neutronclient.v2_0.client as neutronclient
+
+logger = logging.getLogger(__name__)
+
+
+def get_neutron(funname, auth_info, tenant_name):
+    username = auth_info["user"]
+    passwd = auth_info["passwd"]
+    url = auth_info["url"]
+    cacert = auth_info["cacert"]
+    insecure = auth_info["insecure"]
+    logger.info("[%s]call neutronclient.Client(auth_url='%s',"
+                "username='%s',password='%s',tenant_name='%s',insecure=%s,ca_cert='%s')"
+                % (funname, url, username, passwd, tenant_name, insecure, cacert))
+    return neutronclient.Client(username=username, password=passwd, tenant_name=tenant_name,
+                                insecure=insecure, auth_url=url, ca_cert=cacert)
+
+
+def get_neutron_by_tenant_id(funname, auth_info, tenant_id):
+    username = auth_info["user"]
+    passwd = auth_info["passwd"]
+    url = auth_info["url"]
+    cacert = auth_info["cacert"]
+    logger.info("[%s]call neutronclient.Client(auth_url='%s',"
+                "username='%s',password='%s',tenant_id='%s',ca_cert='%s')"
+                % (funname, url, username, passwd, tenant_id, cacert))
+    return neutronclient.Client(username=username, password=passwd, tenant_id=tenant_id, auth_url=url, ca_cert=cacert)
+
+
+def get_neutron_default(funname, auth_info):
+    return get_neutron(funname, auth_info, auth_info["tenant"])
diff --git a/lcm/pub/nfvi/vim/api/openstack/project.py b/lcm/pub/nfvi/vim/api/openstack/project.py
new file mode 100644 (file)
index 0000000..b0c079a
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright 2016 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.nfvi.vim.lib.vimexception import VimException
+
+
+logger = logging.getLogger(__name__)
+
+
+def get_tenant_id(funname, auth_info, tenant):
+    logger.debug("[%s]call get_tenant_id(%s)", funname, tenant)
+    keystone = auth_info["keystone"]
+    tids = [t.id for t in keystone.tenants.list() if t.name == tenant]
+    if not tids:
+        raise VimException("Tenant(%s) does not exist." % tenant)
+    logger.debug("[%s]tenant_id=%s", funname, tids[0])
+    return tids[0]
diff --git a/lcm/pub/nfvi/vim/const.py b/lcm/pub/nfvi/vim/const.py
new file mode 100644 (file)
index 0000000..e879868
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2016 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.
+
+
+VIM_OPENSTACK = "openstack"
+VIM_VMWARE = "vmware"
+RES_TYPE_KEY = "res_type"
+RES_TYPE_NEW = 1
+RES_TYPE_EXIST = 0
+SHARED_NET = 1
+SUPPORT_VLAN_TRANSPARENT = 1
+DEFAULT_MTU = 1500
+IPV4 = 4
+IPV6 = 6
+ENABLE_DHCP = 1
diff --git a/lcm/pub/nfvi/vim/lib/__init__.py b/lcm/pub/nfvi/vim/lib/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/nfvi/vim/lib/syscomm.py b/lcm/pub/nfvi/vim/lib/syscomm.py
new file mode 100644 (file)
index 0000000..447bf4e
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright 2016 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 inspect
+
+
+def fun_name():
+    return inspect.stack()[1][3]
diff --git a/lcm/pub/nfvi/vim/lib/vimexception.py b/lcm/pub/nfvi/vim/lib/vimexception.py
new file mode 100644 (file)
index 0000000..b2b09cc
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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.
+
+
+class VimException(Exception):
+    pass
diff --git a/lcm/pub/nfvi/vim/test/__init__.py b/lcm/pub/nfvi/vim/test/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/nfvi/vim/test/openstack/__init__.py b/lcm/pub/nfvi/vim/test/openstack/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/nfvi/vim/test/openstack/pub.py b/lcm/pub/nfvi/vim/test/openstack/pub.py
new file mode 100644 (file)
index 0000000..6c36f43
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2016 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.nfvi.vim import const
+
+connect_info = {
+    "vimtype": const.VIM_OPENSTACK,
+    "url": "http://10.43.35.131:5000/v2.0",
+    "user": "admin",
+    "passwd": "keystone",
+    "tenant": "admin"}
diff --git a/lcm/pub/nfvi/vim/test/openstack/test_image.py b/lcm/pub/nfvi/vim/test/openstack/test_image.py
new file mode 100644 (file)
index 0000000..004d737
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright 2016 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 unittest
+import os
+import time
+
+from lcm.pub.nfvi.vim import vimadaptor
+from lcm.pub.nfvi.vim.test.openstack import pub
+from lcm.pub.nfvi.vim import const
+
+
+class TestImage(unittest.TestCase):
+    def setUp(self):
+        self.api = vimadaptor.VimAdaptor(pub.connect_info)
+        self.currentdir = os.path.dirname(os.path.abspath(__file__))
+    def tearDown(self):
+        pass
+    def createImg(self, data):
+        return self.api.create_image(data)
+
+    def test_image_all(self):
+        image_data = {
+            "image_name": "cirros",
+            "image_path": self.currentdir + "/testdata/cirros.qcow2",
+            "image_type": "qcow2"
+        }
+
+        # create image
+        ret = self.createImg(image_data)
+        self.assertEqual(0, ret[0])
+        if ret[1][const.RES_TYPE_KEY] == const.RES_TYPE_EXIST:
+            self.api.delete_image(image_id = ret[1]["id"])
+            ret = self.createImg(image_data)
+        self.assertEqual(0, ret[0])
+        imageid = ret[1]["id"]
+        retryTimes = 0
+        while retryTimes < 10:
+            ret = self.api.get_image(image_id = imageid)
+            self.assertEqual(0, ret[0])
+            if ret[1]["status"] == 'active':
+                break
+            time.sleep(2)
+
+        # image is exist
+        ret = self.createImg(image_data)
+        self.assertEqual(0, ret[0])
+        self.assertEqual(const.RES_TYPE_EXIST, ret[1][const.RES_TYPE_KEY])
+
+        # get all images
+        ret = self.api.get_images()
+        self.assertEqual(0, ret[0])
+        flag = False
+        for image in ret[1]['image_list']:
+            if image_data["image_name"] == image["name"]:
+                flag = True
+                break
+        self.assertTrue(flag)
+
+        # delete image
+        ret = self.api.delete_image(image_id = imageid)
+        self.assertEqual(0, ret[0])
+
+        # get_image except
+        ret = self.api.get_image(image_id = imageid)
+        self.assertEqual(2, ret[0])
+
+        # delete image except
+        ret = self.api.delete_image(image_id = imageid)
+        self.assertEqual(0, ret[0])
+
+        # Exception
+        image_data["image_path"] = "aaaa"
+        ret = self.createImg(image_data)
+        self.assertEqual(0, ret[0])
+
+        imageid = ret[1]["id"]
+        self.api.delete_image(image_id = imageid)
+"""
diff --git a/lcm/pub/nfvi/vim/test/openstack/test_network.py b/lcm/pub/nfvi/vim/test/openstack/test_network.py
new file mode 100644 (file)
index 0000000..54ed68d
--- /dev/null
@@ -0,0 +1,245 @@
+# Copyright 2016 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 unittest
+from lcm.pub.nfvi.vim import vimadaptor
+from lcm.pub.nfvi.vim.api.openstack import neutronbase
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim.test.openstack import pub
+from lcm.pub.nfvi.vim import const
+
+class TestNetwork(unittest.TestCase):
+        def setUp(self):
+        self.api = vimadaptor.VimAdaptor(pub.connect_info)
+        self.network_data = {
+            "tenant": "admin",
+            "network_name": "testnet1",
+            "shared": const.SHARED_NET,
+            "network_type": "",
+            "mtu": 1523,
+            "subnet_list": [{
+                "subnet_name": "subnet1",
+                "cidr": "192.168.1.0/24",
+                "ip_version": const.IPV4,
+                "enable_dhcp": 0,
+                "gateway_ip": "192.168.1.1",
+                "dns_nameservers": [],
+                "allocation_pools":[],
+                "host_routes": []
+            }]
+        }
+
+        self.port_data = {
+            "port_name":"port_test",
+            "tenant_name":"test",
+            "network_name":"testnet1",
+            "mac_address":"fa:16:3e:c9:cb:f5",
+            "vnic_type":"normal",
+            "bandwidth":"100",
+            "bond":"0",
+            "macbond":"",
+            "ip":"192.168.1.10",
+            "subnet_name":"subnet1",
+            "allowed_address_pairs":[{'ip_address':'192.168.1.11','mac_address':'fa:16:3e:c9:cb:f6'}]
+        }
+
+        self.port_data_no_subname = {
+            "port_name":"port_test_no_subname",
+            "tenant_name":"admin",
+            "network_name":"testnet1",
+            "mac_address":"fa:16:3e:c9:cb:f7",
+            "vnic_type":"normal",
+            "bandwidth":"100",
+            "bond":"0",
+            "macbond":"",
+            "ip":"192.168.1.12",
+            "allowed_address_pairs":[{'ip_address':'192.168.1.13','mac_address':'fa:16:3e:c9:cb:f8'}]
+        }
+
+        self.network_data_rollback = {
+            "tenant": "admin",
+            "network_name": "testnet1",
+            "shared": const.SHARED_NET,
+            "network_type": "",
+            "mtu": 1523,
+            "subnet_list": [{
+                "subnet_name": "subnet1",
+                "cidr": "192.168.1.0/24",
+                "ip_version": const.IPV4,
+                "enable_dhcp": 0,
+                "gateway_ip": "192.168.1.1",
+                "dns_nameservers": [],
+                "allocation_pools":[],
+                "host_routes": []
+            },
+                            {
+                "subnet_name": "subnet2",
+                "cidr": "191.168.1.0/24",
+                "ip_version": const.IPV6,
+                "enable_dhcp": 0,
+                "gateway_ip": "191.168.1.1",
+                "dns_nameservers": [],
+                "allocation_pools":[],
+                "host_routes": []
+            }]
+        }
+    def tearDown(self):
+        pass
+
+    def test_network_all(self):
+        neutron = neutronbase.get_neutron_default(fun_name(), pub.connect_info)
+
+        # create network
+        ret = self.api.create_network(self.network_data)
+        self.assertEqual(0, ret[0], ret[1])
+        if ret[1][const.RES_TYPE_KEY] == const.RES_TYPE_EXIST:
+            for subnet in ret[1]["subnet_list"]:
+                ports = neutron.list_ports()
+                for port in ports['ports']:
+                    for fixed_ip in port['fixed_ips']:
+                        if fixed_ip['subnet_id'] == subnet["id"]:
+                            self.api.delete_port(port['id'])
+                            break
+                ret_del = self.api.delete_subnet(subnet_id = subnet["id"])
+                self.assertEqual(0, ret_del[0])
+            ret_del = self.api.delete_network(network_id = ret[1]["id"])
+            self.assertEqual(0, ret_del[0])
+            ret = self.api.create_network(self.network_data)
+            self.assertEqual(0, ret[0])
+
+        # network exist
+        ret = self.api.create_network(self.network_data)
+        self.assertEqual(0, ret[0])
+        self.assertEqual(ret[1][const.RES_TYPE_KEY], const.RES_TYPE_EXIST)
+
+        # query subnet
+        q_subnet_ret = self.api.query_subnet(ret[1]["subnet_list"][0]["id"])
+        self.assertEqual(0, q_subnet_ret[0])
+
+        # query net
+        q_net_ret = self.api.query_net(ret[1]["id"])
+        self.assertEqual(0, q_net_ret[0])
+
+        # query nets
+        q_nets_ret = self.api.query_nets()
+        self.assertEqual(0, q_nets_ret[0])
+        flag = False
+        for network in q_nets_ret[1]['networks']:
+            if ret[1]["id"] == network["id"]:
+                flag = True
+                break
+        self.assertTrue(flag)
+
+        # create port
+        create_port_ret = self.api.create_port(self.port_data)
+        self.assertEqual(0, create_port_ret[0], create_port_ret[1])
+
+        # port exist
+        create_port_ret = self.api.create_port(self.port_data)
+        self.assertEqual(0, create_port_ret[0])
+        self.assertEqual(create_port_ret[1][const.RES_TYPE_KEY], const.RES_TYPE_EXIST)
+
+        # create port no subname
+        ret_no_subname = self.api.create_port(self.port_data_no_subname)
+        self.assertEqual(0, ret_no_subname[0], ret_no_subname[1])
+        self.api.delete_port(ret_no_subname[1]['id'])
+
+        # create port except, networks not exist
+        network_name = self.port_data["network_name"]
+        self.port_data["network_name"] = "no_network"
+        create_port_except_ret = self.api.create_port(self.port_data)
+        self.assertEqual(1, create_port_except_ret[0])
+        self.port_data["network_name"] = network_name
+
+        # create port except, subnet not exist
+        subnet_name = self.port_data["subnet_name"]
+        self.port_data["subnet_name"] = "no_subnet"
+        create_port_except_ret = self.api.create_port(self.port_data)
+        self.assertEqual(1, create_port_except_ret[0])
+        self.port_data["subnet_name"] = subnet_name
+
+        # query port
+        q_port_ret = self.api.query_port(create_port_ret[1]['id'])
+        self.assertEqual(0, q_port_ret[0], q_port_ret[1])
+
+        # delete port
+        ret_port_del = self.api.delete_port(create_port_ret[1]['id'])
+        self.assertEqual(0, ret_port_del[0])
+
+        # delete network
+        for subnet in ret[1]["subnet_list"]:
+            ret_del = self.api.delete_subnet(subnet_id = subnet["id"])
+            self.assertEqual(0, ret_del[0])
+        ret_del = self.api.delete_network(network_id = ret[1]["id"])
+        self.assertEqual(0, ret_del[0])
+
+        # query net except
+        q_net_ret = self.api.query_net(ret[1]["id"])
+        self.assertEqual(2, q_net_ret[0])
+
+        # query subnet except
+        q_subnet_ret = self.api.query_subnet(ret[1]["subnet_list"][0]["id"])
+        self.assertEqual(2, q_subnet_ret[0])
+
+        # rollback test
+        ret_roolback = self.api.create_network(self.network_data_rollback)
+        self.assertEqual(1, ret_roolback[0])
+
+        # delete except
+        ret_del = self.api.delete_subnet(subnet_id = "11111")
+        self.assertEqual(0, ret_del[0])
+
+        ret_del = self.api.delete_network(network_id = "11111")
+        self.assertEqual(0, ret_del[0])
+
+        ret_del = self.api.delete_port(port_id = "11111")
+        self.assertEqual(0, ret_del[0])
+
+        # query except
+        q_del = self.api.query_port(port_id = "11111")
+        self.assertEqual(2, q_del[0])
+
+        # multiple network except
+        tenant = self.network_data["tenant"]
+        network = self.network_data["network_name"]
+        self.network_data["tenant"] = "test"
+        self.network_data["network_name"] = "ut_test_network"
+        ret = self.api.create_network(self.network_data)
+        self.network_data["tenant"] = tenant
+        self.network_data["network_name"] = network
+        self.assertEqual(1, ret[0])
+
+        tenant = self.port_data["tenant_name"]
+        network = self.port_data["network_name"]
+        self.port_data["tenant_name"] = "test"
+        self.port_data["network_name"] = "ut_test_network"
+        ret = self.api.create_port(self.port_data)
+        self.port_data["tenant_name"] = tenant
+        self.port_data["network_name"] = network
+        self.assertEqual(1, ret[0])
+
+        # multiple subnet except
+        tenant = self.port_data["tenant_name"]
+        network = self.port_data["network_name"]
+        subnet = self.port_data["subnet_name"]
+        self.port_data["tenant_name"] = "test"
+        self.port_data["network_name"] = "ut_test_subnet_except"
+        self.port_data["subnet_name"] = "ut_test_same_subnet"
+        ret = self.api.create_port(self.port_data)
+        self.port_data["tenant_name"] = tenant
+        self.port_data["network_name"] = network
+        self.port_data["subnet_name"] = subnet
+        self.assertEqual(1, ret[0])
+"""
diff --git a/lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2 b/lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2
new file mode 100644 (file)
index 0000000..afe3ca3
Binary files /dev/null and b/lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2 differ
diff --git a/lcm/pub/nfvi/vim/vimadaptor.py b/lcm/pub/nfvi/vim/vimadaptor.py
new file mode 100644 (file)
index 0000000..5f08d0b
--- /dev/null
@@ -0,0 +1,120 @@
+# Copyright 2016 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 sys
+import traceback
+
+from requests import RequestException
+
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim import const
+from lcm.pub.nfvi.vim.lib.vimexception import VimException
+
+logger = logging.getLogger(__name__)
+
+
+class VimAdaptor:
+    def __init__(self, connectInfo):
+        logger.info("[VimAdaptor]connectInfo=%s" % connectInfo)
+        self.apiImpl, self.authInfo = None, [1, "No auth info"]
+        self.create_api(connectInfo)
+        self.force_login(connectInfo)
+
+    def create_api(self, connectInfo):
+        vimtype = connectInfo['vimtype'] if 'vimtype' in connectInfo else None
+        logger.info("call %s, vimtype=%s" % (fun_name(), vimtype))
+        if vimtype == const.VIM_OPENSTACK:
+            from lcm.pub.nfvi.vim.api.openstack.api import OpenstackApi
+            self.apiImpl = OpenstackApi()
+        elif vimtype == const.VIM_VMWARE:
+            from lcm.pub.nfvi.vim.api.multivim.api import MultiVimApi
+            self.apiImpl = MultiVimApi()
+        else:
+            self.authInfo = [1, "Unsupported vimtype(%s)" % vimtype]
+
+    def api_call(self, funname, fun, *args):
+        logger.info("call %s%s" % (funname, str(args)))
+        ret = None
+        try:
+            ret = fun(self.authInfo[1], *args) if self.authInfo[0] == 0 else self.authInfo
+        except VimException as e:
+            ret = [1, e.message]
+        except RequestException as e:
+            logger.error("request=%s, url=%s" % (e.request.headers._store, e.request.url))
+            logger.error(traceback.format_exc())
+            ret = [1, e.message if e.message else str(sys.exc_info())]
+        except Exception as ex:
+            logger.error(traceback.format_exc())
+            ret = [1, ex.message if ex.message else str(sys.exc_info())]
+        except:
+            logger.error(traceback.format_exc())
+            ret = [1, str(sys.exc_info())]
+        logger.info("[%s]ret=%s" % (funname, ret))
+        return ret
+
+    def force_login(self, connectInfo):
+        if self.apiImpl:
+            logger.info("call %s(%s)" % (fun_name(), connectInfo))
+            try:
+                self.authInfo = self.apiImpl.login(connectInfo)
+            except VimException as e:
+                self.authInfo = [1, e.message]
+            except Exception as ex:
+                logger.error(traceback.format_exc())
+                logger.error(str(sys.exc_info()))
+                self.authInfo = [1, ex.message if ex.message else str(sys.exc_info())]
+            except:
+                logger.error(traceback.format_exc())
+                self.authInfo = [1, str(sys.exc_info())]
+            logger.info("self.authInfo=%s" % self.authInfo)
+
+    def query_net(self, net_id):
+        return self.api_call(fun_name(), self.apiImpl.query_net, net_id)
+
+    def query_nets(self):
+        return self.api_call(fun_name(), self.apiImpl.query_nets)
+
+    def query_subnet(self, subnet_id):
+        return self.api_call(fun_name(), self.apiImpl.query_subnet, subnet_id)
+
+    def query_port(self, port_id):
+        return self.api_call(fun_name(), self.apiImpl.query_port, port_id)
+
+    def create_image(self, data):
+        return self.api_call(fun_name(), self.apiImpl.create_image, data)
+
+    def get_image(self, image_id):
+        return self.api_call(fun_name(), self.apiImpl.get_image, image_id)
+
+    def get_images(self):
+        return self.api_call(fun_name(), self.apiImpl.get_images)
+
+    def delete_image(self, image_id):
+        return self.api_call(fun_name(), self.apiImpl.delete_image, image_id)
+
+    def create_network(self, data):
+        return self.api_call(fun_name(), self.apiImpl.create_network, data)
+
+    def delete_network(self, network_id):
+        return self.api_call(fun_name(), self.apiImpl.delete_network, network_id)
+
+    def delete_subnet(self, subnet_id):
+        return self.api_call(fun_name(), self.apiImpl.delete_subnet, subnet_id)
+
+    def create_port(self, data):
+        return self.api_call(fun_name(), self.apiImpl.create_port, data)
+
+    def delete_port(self, port_id):
+        return self.api_call(fun_name(), self.apiImpl.delete_port, port_id)
diff --git a/lcm/pub/utils/__init__.py b/lcm/pub/utils/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/pub/utils/enumutil.py b/lcm/pub/utils/enumutil.py
new file mode 100644 (file)
index 0000000..8b263db
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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.
+
+
+def enum(**enums):
+    return type('Enum', (), enums)
diff --git a/lcm/pub/utils/fileutil.py b/lcm/pub/utils/fileutil.py
new file mode 100644 (file)
index 0000000..3568e5e
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright 2016 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 os
+import shutil
+import logging
+import traceback
+import urllib2
+
+logger = logging.getLogger(__name__)
+
+
+def make_dirs(path):
+    if not os.path.exists(path):
+        os.makedirs(path, 0777)
+
+
+def delete_dirs(path):
+    try:
+        if os.path.exists(path):
+            shutil.rmtree(path)
+    except Exception as e:
+        logger.error(traceback.format_exc())
+        logger.error("Failed to delete %s:%s", path, e.message)
+
+
+def download_file_from_http(url, local_dir, file_name):
+    local_file_name = os.path.join(local_dir, file_name)
+    is_download_ok = False
+    try:
+        make_dirs(local_dir)
+        r = urllib2.Request(url)
+        req = urllib2.urlopen(r)
+        save_file = open(local_file_name, 'wb')
+        save_file.write(req.read())
+        save_file.close()
+        req.close()
+        is_download_ok = True
+    except:
+        logger.error(traceback.format_exc())
+        logger.error("Failed to download %s to %s.", url, local_file_name)
+    return is_download_ok, local_file_name
diff --git a/lcm/pub/utils/idutil.py b/lcm/pub/utils/idutil.py
new file mode 100644 (file)
index 0000000..85bebb8
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright 2016 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 redisco import containers as cont
+
+
+def get_auto_id(id_type, id_group="auto_id_hash"):
+    auto_id_hash = cont.Hash(id_group)
+    auto_id_hash.hincrby(id_type, 1)
+    return auto_id_hash.hget(id_type)
diff --git a/lcm/pub/utils/jobutil.py b/lcm/pub/utils/jobutil.py
new file mode 100644 (file)
index 0000000..650d2af
--- /dev/null
@@ -0,0 +1,142 @@
+# Copyright 2016-2017 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 datetime
+import logging
+import uuid
+import traceback
+
+from lcm.pub.database.models import JobStatusModel, JobModel
+from lcm.pub.utils import idutil
+
+logger = logging.getLogger(__name__)
+
+
+def enum(**enums):
+    return type('Enum', (), enums)
+
+
+JOB_STATUS = enum(PROCESSING=0, FINISH=1)
+JOB_MODEL_STATUS = enum(STARTED='started', PROCESSING='processing', FINISHED='finished', ERROR='error',
+                        TIMEOUT='timeout')
+JOB_TYPE = enum(CREATE_VNF="create vnf", TERMINATE_VNF="terminate vnf", GRANT_VNF="grant vnf", MANUAL_SCALE_VNF="manual scale vnf")
+
+
+class JobUtil(object):
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def __gen_job_id(job_name):
+        return "%s-%s" % (job_name if job_name else "UnknownJob", uuid.uuid1())
+
+    @staticmethod
+    def query_job_status(job_id, index_id=-1):
+        #logger.info("Query job status, jobid =[%s], responseid [%d]" % (job_id, index_id))
+        jobs = []
+        if index_id < 0:
+            row = JobStatusModel.objects.filter(jobid=job_id).order_by("-indexid").first()
+            if row:
+                jobs.append(row)
+        else:
+            [jobs.append(job) for job in JobStatusModel.objects.filter(jobid=job_id).order_by("-indexid")
+             if job.indexid > index_id]
+
+        #logger.info("Query job status, rows=%s" % str(jobs))
+        return jobs
+
+    @staticmethod
+    def is_job_exists(job_id):
+        jobs = JobModel.objects.filter(jobid=job_id)
+        return len(jobs) > 0
+
+    @staticmethod
+    def create_job(inst_type, jobaction, inst_id, user='', job_id=None, res_name=''):
+        if job_id is None:
+            job_id = JobUtil.__gen_job_id(
+                '%s-%s-%s' % (str(inst_type).replace(' ', '_'), str(jobaction).replace(' ', '_'), str(inst_id)))
+        job = JobModel()
+        job.jobid = job_id
+        job.jobtype = inst_type
+        job.jobaction = jobaction
+        job.resid = str(inst_id)
+        job.status = JOB_STATUS.PROCESSING
+        job.user = user
+        job.starttime = datetime.datetime.now().strftime('%Y-%m-%d %X')
+        job.progress = 0
+        job.resname = res_name
+        logger.debug("create a new job, jobid=%s, jobtype=%s, jobaction=%s, resid=%s, status=%d" %
+                     (job.jobid, job.jobtype, job.jobaction, job.resid, job.status))
+        job.save()
+        return job_id
+
+    @staticmethod
+    def clear_job(job_id):
+        [job.delete() for job in JobModel.objects.filter(jobid=job_id)]
+        logger.debug("Clear job, job_id=%s" % job_id)
+
+    @staticmethod
+    def add_job_status(job_id, progress, status_decs, error_code=""):
+        jobs = JobModel.objects.filter(jobid=job_id)
+        if not jobs:
+            logger.error("Job[%s] is not exists, please create job first." % job_id)
+            raise Exception("Job[%s] is not exists." % job_id)
+        try:
+            int_progress = int(progress)
+            job_status = JobStatusModel()
+            job_status.indexid = int(idutil.get_auto_id(job_id))
+            job_status.jobid = job_id
+            job_status.status = "processing"
+            job_status.progress = int_progress
+
+            if job_status.progress == 0:
+                job_status.status = "started"
+            elif job_status.progress == 100:
+                job_status.status = "finished"
+            elif job_status.progress == 101:
+                job_status.status = "partly_finished"
+            elif job_status.progress > 101:
+                job_status.status = "error"
+
+            if error_code == "255":
+                job_status.status = "error"
+
+            job_status.descp = status_decs
+            job_status.errcode = error_code
+            job_status.addtime = datetime.datetime.now().strftime('%Y-%m-%d %X')
+            job_status.save()
+            logger.debug("Add a new job status, jobid=%s, indexid=%d,"
+                         " status=%s, description=%s, progress=%d, errcode=%s, addtime=%r" %
+                         (job_status.jobid, job_status.indexid, job_status.status, job_status.descp,
+                          job_status.progress, job_status.errcode, job_status.addtime))
+
+            job = jobs[0]
+            job.progress = int_progress
+            if job_status.progress >= 100:
+                job.status = JOB_STATUS.FINISH
+                job.endtime = datetime.datetime.now().strftime('%Y-%m-%d %X')
+            job.save()
+            logger.debug("update job, jobid=%s, progress=%d" % (job_status.jobid, int_progress))
+        except:
+            logger.error(traceback.format_exc())
+
+    @staticmethod
+    def clear_job_status(job_id):
+        [job.delete() for job in JobStatusModel.objects.filter(jobid=job_id)]
+        logger.debug("Clear job status, job_id=%s" % job_id)
+
+    @staticmethod
+    def get_unfinished_jobs(url_prefix, inst_id, inst_type):
+        jobs = JobModel.objects.filter(resid=inst_id, jobtype=inst_type, status=JOB_STATUS.PROCESSING)
+        progresses = reduce(lambda content, job: content + [url_prefix + "/" + job.jobid], jobs, [])
+        return progresses
diff --git a/lcm/pub/utils/restcall.py b/lcm/pub/utils/restcall.py
new file mode 100644 (file)
index 0000000..bfb02d6
--- /dev/null
@@ -0,0 +1,95 @@
+# Copyright 2016 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 sys
+import traceback
+import logging
+import urllib2
+import uuid
+import httplib2
+
+from lcm.pub.config.config import MSB_SERVICE_IP, MSB_SERVICE_PORT
+
+rest_no_auth, rest_oneway_auth, rest_bothway_auth = 0, 1, 2
+HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT, HTTP_202_ACCEPTED = '200', '201', '204', '202'
+status_ok_list = [HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT, HTTP_202_ACCEPTED]
+HTTP_404_NOTFOUND, HTTP_403_FORBIDDEN, HTTP_401_UNAUTHORIZED, HTTP_400_BADREQUEST = '404', '403', '401', '400'
+
+logger = logging.getLogger(__name__)
+
+
+def call_req(base_url, user, passwd, auth_type, resource, method, content=''):
+    callid = str(uuid.uuid1())
+    logger.debug("[%s]call_req('%s','%s','%s',%s,'%s','%s','%s')" % (
+        callid, base_url, user, passwd, auth_type, resource, method, content))
+    ret = None
+    resp_status = ''
+    try:
+        full_url = combine_url(base_url, resource)
+        headers = {'content-type': 'application/json', 'accept': 'application/json'}
+        if user:
+            headers['Authorization'] = 'Basic ' + ('%s:%s' % (user, passwd)).encode("base64")
+        ca_certs = None
+        for retry_times in range(3):
+            http = httplib2.Http(ca_certs=ca_certs, disable_ssl_certificate_validation=(auth_type == rest_no_auth))
+            http.follow_all_redirects = True
+            try:
+                resp, resp_content = http.request(full_url, method=method.upper(), body=content, headers=headers)
+                resp_status, resp_body = resp['status'], resp_content.decode('UTF-8')
+                logger.debug("[%s][%d]status=%s,resp_body=%s)" % (callid, retry_times, resp_status, resp_body))
+                if resp_status in status_ok_list:
+                    ret = [0, resp_body, resp_status]
+                else:
+                    ret = [1, resp_body, resp_status]
+                break
+            except Exception as ex:
+                if 'httplib.ResponseNotReady' in str(sys.exc_info()):
+                    logger.debug("retry_times=%d", retry_times)
+                    logger.error(traceback.format_exc())
+                    ret = [1, "Unable to connect to %s" % full_url, resp_status]
+                    continue
+                raise ex
+    except urllib2.URLError as err:
+        ret = [2, str(err), resp_status]
+    except Exception as ex:
+        logger.error(traceback.format_exc())
+        logger.error("[%s]ret=%s" % (callid, str(sys.exc_info())))
+        res_info = str(sys.exc_info())
+        if 'httplib.ResponseNotReady' in res_info:
+            res_info = "The URL[%s] request failed or is not responding." % full_url
+        ret = [3, res_info, resp_status]
+    except:
+        logger.error(traceback.format_exc())
+        ret = [4, str(sys.exc_info()), resp_status]
+
+    logger.debug("[%s]ret=%s" % (callid, str(ret)))
+    return ret
+
+
+def req_by_msb(resource, method, content=''):
+    base_url = "http://%s:%s/" % (MSB_SERVICE_IP, MSB_SERVICE_PORT)
+    return call_req(base_url, "", "", rest_no_auth, resource, method, content)
+
+
+def combine_url(base_url, resource):
+    full_url = None
+    if base_url.endswith('/') and resource.startswith('/'):
+        full_url = base_url[:-1] + resource
+    elif base_url.endswith('/') and not resource.startswith('/'):
+        full_url = base_url + resource
+    elif not base_url.endswith('/') and resource.startswith('/'):
+        full_url = base_url + resource
+    else:
+        full_url = base_url + '/' + resource
+    return full_url
diff --git a/lcm/pub/utils/scaleaspect.py b/lcm/pub/utils/scaleaspect.py
new file mode 100644 (file)
index 0000000..dda1797
--- /dev/null
@@ -0,0 +1,140 @@
+# Copyright 2017 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 os
+import logging
+from lcm.pub.exceptions import NSLCMException
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+from rest_framework import status
+from rest_framework.response import Response
+
+logger = logging.getLogger(__name__)
+SCALE_TYPE = ("SCALE_NS", "SCALE_VNF")
+
+scale_vnf_data_mapping = {
+    "vnfInstanceId":"",
+    "scaleByStepData":[
+        {
+            "type":"",
+            "aspectId":"",
+            "numberOfSteps":""
+        }
+    ]
+}
+
+def ignorcase_get(args, key):
+    if not key:
+        return ""
+    if not args:
+        return ""
+    if key in args:
+        return args[key]
+    for old_key in args:
+        if old_key.upper() == key.upper():
+            return args[old_key]
+    return ""
+
+def mapping_conv(keyword_map, rest_return):
+    resp_data = {}
+    for param in keyword_map:
+        if keyword_map[param]:
+            if isinstance(keyword_map[param], dict):
+                resp_data[param] = mapping_conv(keyword_map[param], ignorcase_get(rest_return, param))
+            else:
+                resp_data[param] = ignorcase_get(rest_return, param)
+    return resp_data
+
+def get_vnf_scale_info(filename, ns_instanceId, aspect, step):
+    json_data = get_json_data(filename)
+    scale_options = ignorcase_get(json_data, "scale_options")
+    for i in range(scale_options.__len__()):
+        ns_scale_option = scale_options[i]
+        if (ignorcase_get(ns_scale_option, "ns_instanceId") == ns_instanceId) \
+                and (ignorcase_get(ns_scale_option, "ns_scale_aspect") == aspect):
+            ns_scale_info_list = ignorcase_get(ns_scale_option, "ns_scale_info_list")
+            for j in range(ns_scale_info_list.__len__()):
+                ns_scale_info = ns_scale_info_list[j]
+                if ns_scale_info["step"] == step:
+                    return ns_scale_info["vnf_scale_list"]
+
+    return None
+
+def get_json_data(filename):
+    f = open(filename)
+    json_str = f.read()
+    data = json.JSONDecoder().decode(json_str)
+    f.close()
+    return data
+
+def check_scale_list(vnf_scale_list, ns_instanceId, aspect, step):
+    if vnf_scale_list is None:
+        logger.debug("The scaling option[ns=%s, aspect=%s, step=%s] does not exist. Pls check the config file." %(ns_instanceId, aspect, step))
+        raise Exception("The scaling option[ns=%s, aspect=%s, step=%s] does not exist. Pls check the config file." %(ns_instanceId, aspect, step))
+    else:
+        return vnf_scale_list
+
+def set_scaleVnfData_type(vnf_scale_list, scale_type):
+    logger.debug("vnf_scale_list = %s, type = %s" % (vnf_scale_list, scale_type))
+    scaleVnfDataList = []
+    if vnf_scale_list is not None:
+        for i in range(vnf_scale_list.__len__()):
+            scaleVnfData = scale_vnf_data_mapping
+            scaleVnfData["vnfInstanceId"] = get_vnfInstanceIdByName(vnf_scale_list[i]["vnfInstanceId"])
+            scaleVnfData["scaleByStepData"][0]["type"] = scale_type
+            scaleVnfData["scaleByStepData"][0]["aspectId"] = vnf_scale_list[i]["vnf_scaleAspectId"]
+            scaleVnfData["scaleByStepData"][0]["numberOfSteps"] = vnf_scale_list[i]["numberOfSteps"]
+            scaleVnfDataList.append(scaleVnfData)
+    logger.debug("scaleVnfDataList = %s" % scaleVnfDataList)
+    return scaleVnfDataList
+
+def get_vnfInstanceIdByName(name):
+    return name
+
+def get_vnf_data(filename, ns_instanceId, aspect, step, scale_type):
+
+    vnf_scale_list = get_vnf_scale_info(filename, ns_instanceId, aspect, step)
+    check_scale_list(vnf_scale_list, ns_instanceId, aspect, step)
+    scaleVnfDataList = set_scaleVnfData_type(vnf_scale_list,scale_type)
+    logger.debug("scaleVnfDataList = %s" % scaleVnfDataList)
+    return scaleVnfDataList
+
+    #return Response(data={'error': e.message},status=status.HTTP_204_NO_CONTENT)
+    #return Response(data={'success': 'success'},status=status.HTTP_200_OK)
+
+def get_and_check_params(scaleNsData, ns_InstanceId):
+
+    if scaleNsData is None:
+        pass
+        #raise NSLCMException("Error! scaleNsData in the request is Empty!")
+
+    scaleNsByStepsData = scaleNsData[0]["scaleNsByStepsData"]
+    if scaleNsByStepsData is None:
+        pass
+        #raise NSLCMException("Error! scaleNsByStepsData in the request is Empty!")
+
+    aspect = scaleNsByStepsData[0]["aspectId"]
+    numberOfSteps = scaleNsByStepsData[0]["numberOfSteps"]
+    scale_type = scaleNsByStepsData[0]["scalingDirection"]
+
+    return ns_InstanceId,aspect,numberOfSteps,scale_type
+
+def get_scale_vnf_data(scaleNsData, ns_InstanceId):
+    curdir_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+    filename = curdir_path + "/ns/data/scalemapping.json"
+    logger.debug("filename = %s" % filename)
+    ns_InstanceId,aspect,numberOfSteps,scale_type = get_and_check_params(scaleNsData, ns_InstanceId)
+    return get_vnf_data(filename, ns_InstanceId,aspect,numberOfSteps,scale_type)
diff --git a/lcm/pub/utils/share_lock.py b/lcm/pub/utils/share_lock.py
new file mode 100644 (file)
index 0000000..1e5e555
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright 2016 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 time
+
+import redis
+
+from lcm.pub.config.config import REDIS_HOST, REDIS_PORT, REDIS_PASSWD
+
+
+class SharedLock:
+    def __init__(self, lock_key, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWD, db=9, lock_timeout=5 * 60):
+        self.lock_key = lock_key
+        self.lock_timeout = lock_timeout
+        self.redis = redis.Redis(host=host, port=port, db=db, password=password)
+        self.acquire_time = -1
+
+    def acquire(self):
+        begin = now = int(time.time())
+        while (now - begin) < self.lock_timeout:
+
+            result = self.redis.setnx(self.lock_key, now + self.lock_timeout + 1)
+            if result == 1 or result is True:
+                self.acquire_time = now
+                return True
+
+            current_lock_timestamp = self.redis.get(self.lock_key)
+            if not current_lock_timestamp:
+                time.sleep(1)
+                continue
+
+            current_lock_timestamp = int(current_lock_timestamp)
+
+            if now > current_lock_timestamp:
+                next_lock_timestamp = self.redis.getset(self.lock_key, now + self.lock_timeout + 1)
+                if not next_lock_timestamp:
+                    time.sleep(1)
+                    continue
+                next_lock_timestamp = int(next_lock_timestamp)
+
+                if next_lock_timestamp == current_lock_timestamp:
+                    self.acquire_time = now
+                    return True
+            else:
+                time.sleep(1)
+                continue
+        return False
+
+    def release(self):
+        now = int(time.time())
+        if now > self.acquire_time + self.lock_timeout:
+            # key expired, do nothing and let other clients handle it
+            return
+        self.acquire_time = None
+        self.redis.delete(self.lock_key)
+
+
+def do_biz_with_share_lock(lock_name, callback):
+    lock = SharedLock(lock_name)
+    try:
+        if not lock.acquire():
+            raise Exception(lock_name + " timeout")
+        callback()
+    except Exception as e:
+        raise e
+    finally:
+        lock.release()
diff --git a/lcm/pub/utils/syscomm.py b/lcm/pub/utils/syscomm.py
new file mode 100644 (file)
index 0000000..90e5c34
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright 2016 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 inspect
+
+
+def fun_name():
+    return inspect.stack()[1][3]
diff --git a/lcm/pub/utils/timeutil.py b/lcm/pub/utils/timeutil.py
new file mode 100644 (file)
index 0000000..b703a3c
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright 2016 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 datetime
+
+
+def now_time(fmt="%Y-%m-%d %H:%M:%S"):
+    return datetime.datetime.now().strftime(fmt)
diff --git a/lcm/pub/utils/toscautil.py b/lcm/pub/utils/toscautil.py
new file mode 100644 (file)
index 0000000..f9ac6c1
--- /dev/null
@@ -0,0 +1,2632 @@
+# Copyright 2016-2017 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
+
+def safe_get(key_val, key):
+    return key_val[key] if key in key_val else ""
+
+
+def find_node_name(node_id, node_list):
+    for node in node_list:
+        if node['id'] == node_id:
+            return node['template_name']
+    raise Exception('can not find node(%s).' % node_id)
+
+
+def find_node_type(node_id, node_list):
+    for node in node_list:
+        if node['id'] == node_id:
+            return node['type_name']
+    raise Exception('can not find node(%s).' % node_id)
+
+
+def find_related_node(node_id, src_json_model, requirement_name):
+    related_nodes = []
+    for model_tpl in safe_get(src_json_model, "node_templates"):
+        for rt in safe_get(model_tpl, 'requirement_templates'):
+            if safe_get(rt, 'name') == requirement_name and \
+                safe_get(rt, 'target_node_template_name') == node_id:
+                related_nodes.append(model_tpl['name'])
+    return related_nodes
+
+
+def convert_props(src_node, dest_node):
+    if 'properties' in src_node and src_node['properties']:
+        for prop_name, prop_info in src_node['properties'].items():
+            if 'value' in prop_info:
+                dest_node['properties'][prop_name] = prop_info['value']   
+
+
+def convert_metadata(src_json):
+    return src_json['metadata'] if 'metadata' in src_json else {}
+
+
+def convert_inputs(src_json):
+    inputs = {}
+    if 'inputs' in src_json:
+        src_inputs = src_json['inputs']
+        for param_name, param_info in src_inputs.items():
+            input_param = {}
+            if 'type_name' in param_info:
+                input_param['type'] = param_info['type_name']
+            if 'description' in param_info:
+                input_param['description'] = param_info['description']
+            if 'value' in param_info:
+                input_param['value'] = param_info['value']
+            inputs[param_name] = input_param
+    return inputs
+
+
+def convert_vnf_node(src_node, src_json_model):
+    vnf_node = {'type': src_node['type_name'], 'vnf_id': src_node['template_name'],
+        'description': '', 'properties': {}, 'dependencies': [], 'networks': []}
+    convert_props(src_node, vnf_node)
+    for model_tpl in safe_get(src_json_model, "node_templates"):
+        if model_tpl['name'] != vnf_node['vnf_id']:
+            continue
+        vnf_node['dependencies'] = [{
+            'key_name': requirement['name'],
+            'vl_id': requirement['target_node_template_name']} for \
+            requirement in safe_get(model_tpl, 'requirement_templates') if \
+            safe_get(requirement, 'target_capability_name') == 'virtual_linkable']
+        vnf_node['networks'] = [requirement['target_node_template_name'] for \
+            requirement in safe_get(model_tpl, 'requirement_templates') if \
+            safe_get(requirement, 'name') == 'dependency']
+    return vnf_node
+
+
+def convert_pnf_node(src_node, src_json_model):
+    pnf_node = {'pnf_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, pnf_node)
+    pnf_node['cps'] = find_related_node(src_node['id'], src_json_model, 'virtualbinding')
+    return pnf_node
+
+
+def convert_vl_node(src_node, src_node_list):
+    vl_node = {'vl_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, vl_node)
+    vl_node['route_id'] = ''
+    for relation in safe_get(src_node, 'relationships'):
+        if safe_get(relation, 'type_name').endswith('.VirtualLinksTo'):
+            vl_node['route_id'] = find_node_name(relation['target_node_id'], src_node_list)
+            break
+    vl_node['route_external'] = (src_node['type_name'].find('.RouteExternalVL') > 0)
+    return vl_node
+
+
+def convert_cp_node(src_node, src_node_list, model_type='NSD'):
+    cp_node = {'cp_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, cp_node)
+    src_relationships = src_node['relationships']
+    for relation in src_relationships:
+        if safe_get(relation, 'name') == 'virtualLink':
+            cp_node['vl_id'] = find_node_name(relation['target_node_id'], src_node_list)
+        elif safe_get(relation, 'name') == 'virtualbinding':
+            node_key = 'pnf_id' if model_type == 'NSD' else 'vdu_id'
+            cp_node[node_key] = find_node_name(relation['target_node_id'], src_node_list)
+    return cp_node
+
+
+def convert_router_node(src_node, src_node_list):
+    router_node = {'router_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, router_node)
+    for relation in src_node['relationships']:
+        if safe_get(relation, 'name') != 'external_virtual_link':
+            continue
+        router_node['external_vl_id'] = find_node_name(relation['target_node_id'], src_node_list)
+        router_node['external_ip_addresses'] = []
+        if 'properties' not in relation:
+            continue
+        for prop_name, prop_info in relation['properties'].items():
+            if prop_name == 'router_ip_address':
+                router_node['external_ip_addresses'].append(prop_info['value'])
+        break
+    return router_node
+
+
+def convert_fp_node(src_node, src_node_list, src_json_model):
+    fp_node = {'fp_id': src_node['template_name'], 'description': '', 
+        'properties': {}, 'forwarder_list': []}
+    convert_props(src_node, fp_node)
+    for relation in safe_get(src_node, 'relationships'):
+        if safe_get(relation, 'name') != 'forwarder':
+            continue
+        forwarder_point = {'type': 'vnf'}
+        target_node_type = find_node_type(relation['target_node_id'], src_node_list).upper()
+        if target_node_type.find('.CP.') >= 0 or target_node_type.endswith('.CP'):
+            forwarder_point['type'] = 'cp'
+        forwarder_point['node_name'] = find_node_name(relation['target_node_id'], src_node_list)
+        forwarder_point['capability'] = ''
+        if forwarder_point['type'] == 'vnf':
+            for node_tpl in src_json_model["node_templates"]:
+                if fp_node['fp_id'] != node_tpl["name"]:
+                    continue
+                for r_tpl in safe_get(node_tpl, "requirement_templates"):
+                    if safe_get(r_tpl, "target_node_template_name") != forwarder_point['node_name']:
+                        continue
+                    forwarder_point['capability'] = safe_get(r_tpl, "target_capability_name")
+                    break
+                break
+        fp_node['forwarder_list'].append(forwarder_point)
+    return fp_node
+
+
+def convert_vnffg_group(src_group, src_group_list, src_node_list):
+    vnffg = {'vnffg_id': src_group['template_name'], 'description': '', 
+        'properties': {}, 'members': []}
+    convert_props(src_group, vnffg)
+    for member_node_id in src_group['member_node_ids']:
+        vnffg['members'].append(find_node_name(member_node_id, src_node_list))
+    return vnffg
+
+
+def convert_imagefile_node(src_node, src_node_list):
+    image_node = {'image_file_id': src_node['template_name'], 'description': '', 
+        'properties': {}}
+    convert_props(src_node, image_node)
+    return image_node
+
+
+def convert_localstorage_node(src_node, src_node_list):
+    localstorage_node = {'local_storage_id': src_node['template_name'], 'description': '', 
+        'properties': {}}
+    convert_props(src_node, localstorage_node)
+    return localstorage_node
+
+
+def convert_vdu_node(src_node, src_node_list, src_json_model):
+    vdu_node = {'vdu_id': src_node['template_name'], 'description': '', 'properties': {},
+        'image_file': '', 'local_storages': [], 'dependencies': [], 'nfv_compute': {},
+        'vls': [], 'artifacts': []}
+    convert_props(src_node, vdu_node)
+
+    for relation in src_node['relationships']:
+        r_id, r_name = safe_get(relation, 'target_node_id'), safe_get(relation, 'name')
+        if r_name == 'guest_os':
+            vdu_node['image_file'] = find_node_name(r_id, src_node_list)
+        elif r_name == 'local_storage':
+            vdu_node['local_storages'].append(find_node_name(r_id, src_node_list))
+        elif r_name.endswith('.AttachesTo'):
+            nt = find_node_type(r_id, src_node_list)
+            if nt.endswith('.BlockStorage.Local') or nt.endswith('.LocalStorage'):
+                vdu_node['local_storages'].append(find_node_name(r_id, src_node_list))
+
+    for capability in src_node['capabilities']:
+        if capability['name'] != 'nfv_compute':
+            continue
+        for prop_name, prop_info in capability['properties'].items():
+            if 'value' in prop_info:
+                vdu_node['nfv_compute'][prop_name] = prop_info['value']
+
+    vdu_node['cps'] = find_related_node(src_node['id'], src_json_model, 'virtualbinding')
+
+    for cp_node in vdu_node['cps']:
+        for src_cp_node in src_node_list:
+            if src_cp_node['template_name'] != cp_node:
+                continue
+            for relation in safe_get(src_cp_node, 'relationships'):
+                if relation['name'] != 'virtualLink':
+                    continue
+                vl_node_name = find_node_name(relation['target_node_id'], src_node_list)
+                if vl_node_name not in vdu_node['vls']:
+                    vdu_node['vls'].append(vl_node_name)
+
+    for item in safe_get(src_node, 'artifacts'):
+        artifact = {'artifact_name': item['name'], 'type': item['type_name'], 
+            'file': item['source_path']}
+        vdu_node['artifacts'].append(artifact)
+
+    return vdu_node
+
+
+def convert_exposed_node(src_json, src_nodes, exposed):
+    for item in safe_get(safe_get(src_json, 'substitution'), 'requirements'):
+        exposed['external_cps'].append({'key_name': item['mapped_name'],
+            "cp_id": find_node_name(item['node_id'], src_nodes)})
+    for item in safe_get(safe_get(src_json, 'substitution'), 'capabilities'):
+        exposed['forward_cps'].append({'key_name': item['mapped_name'],
+            "cp_id": find_node_name(item['node_id'], src_nodes)})
+
+
+def convert_vnffgs(src_json_inst, src_nodes):
+    vnffgs = []
+    src_groups = safe_get(src_json_inst, 'groups')
+    for group in src_groups:
+        type_name = group['type_name'].upper()
+        if type_name.find('.VNFFG.') >= 0 or type_name.endswith('.VNFFG'):
+            vnffgs.append(convert_vnffg_group(group, src_groups, src_nodes))
+    return vnffgs
+
+
+def convert_common(src_json, target_json):
+    if isinstance(src_json, (unicode, str)):
+        src_json_dict = json.loads(src_json)
+    else:
+        src_json_dict = src_json
+    src_json_inst = src_json_dict["instance"]
+    src_json_model = src_json_dict["model"] if "model" in src_json_dict else {}
+
+    target_json['metadata'] = convert_metadata(src_json_inst)
+    target_json['inputs'] = convert_inputs(src_json_inst)
+    target_json['vls'] = []
+    target_json['cps'] = []
+    target_json['routers'] = []
+
+    return src_json_inst, src_json_model
+
+def convert_policy_node(src_json):
+    target_json = {'name': src_json['template_name'],'file_url': src_json['properties']['drl_file_url']['value']}
+
+    return target_json
+
+def convert_nsd_model(src_json):
+    target_json = {'vnfs': [], 'pnfs': [], 'fps': [], 'policies': []}
+    src_json_inst, src_json_model = convert_common(src_json, target_json)
+   
+    src_nodes = src_json_inst['nodes']
+    for node in src_nodes:
+        type_name = node['type_name']
+        if type_name.find('.VNF.') > 0 or type_name.endswith('.VNF'):
+            target_json['vnfs'].append(convert_vnf_node(node, src_json_model))
+        elif type_name.find('.PNF.') > 0 or type_name.endswith('.PNF'):
+            target_json['pnfs'].append(convert_pnf_node(node, src_json_model))
+        elif type_name.find('.VL.') > 0 or type_name.endswith('.VL') \
+                or node['type_name'].find('.RouteExternalVL') > 0:
+            target_json['vls'].append(convert_vl_node(node, src_nodes))
+        elif type_name.find('.CP.') > 0 or type_name.endswith('.CP'):
+            target_json['cps'].append(convert_cp_node(node, src_nodes))
+        elif type_name.find('.FP.') > 0 or type_name.endswith('.FP'):
+            target_json['fps'].append(convert_fp_node(node, src_nodes, src_json_model))
+        elif type_name.endswith('.Router'):
+            target_json['routers'].append(convert_router_node(node, src_nodes))
+        elif type_name.endswith('tosca.policies.Drools'):
+            target_json['policies'].append(convert_policy_node(node))
+
+    target_json['vnffgs'] = convert_vnffgs(src_json_inst, src_nodes)
+
+    target_json['ns_exposed'] = {'external_cps': [], 'forward_cps': []}
+    convert_exposed_node(src_json_inst, src_nodes, target_json['ns_exposed'])
+    return json.dumps(target_json)
+
+
+def convert_vnfd_model(src_json):
+    target_json = {'image_files': [], 'local_storages': [], 'vdus': []}
+    src_json_inst, src_json_model = convert_common(src_json, target_json)
+    if "vnfdVersion" in src_json_inst.get("metadata", {}):
+        from . import toscautil_new
+        return toscautil_new.convert_vnfd_model(src_json)
+
+    src_nodes = src_json_inst['nodes']
+    for node in src_nodes:
+        type_name = node['type_name']
+        if type_name.endswith('.ImageFile'):
+            target_json['image_files'].append(convert_imagefile_node(node, src_nodes))
+        elif type_name.endswith('.BlockStorage.Local') or type_name.endswith('.LocalStorage'):
+            target_json['local_storages'].append(convert_localstorage_node(node, src_nodes))
+        elif type_name.find('.VDU.') > 0 or type_name.endswith('.VDU'):
+            target_json['vdus'].append(convert_vdu_node(node, src_nodes, src_json_model))
+        elif type_name.find('.VL.') > 0 or type_name.endswith('.VL') \
+                or node['type_name'].find('.RouteExternalVL') > 0:
+            target_json['vls'].append(convert_vl_node(node, src_nodes))
+        elif type_name.find('.CP.') > 0 or type_name.endswith('.CP'):
+            target_json['cps'].append(convert_cp_node(node, src_nodes, 'VNFD'))
+        elif type_name.endswith('.Router'):
+            target_json['routers'].append(convert_router_node(node, src_nodes))
+    
+    target_json['vnf_exposed'] = {'external_cps': [], 'forward_cps': []}
+    convert_exposed_node(src_json_inst, src_nodes, target_json['vnf_exposed'])
+    return json.dumps(target_json)
+
+if __name__ == '__main__':
+    src_json = json.dumps(
+        {
+            "instance":{
+                "metadata":{
+                    "vendor":"ZTE",
+                    "name":"VCPE_NS",
+                    "csarVersion":"v1.0",
+                    "csarType":"NSAR",
+                    "csarProvider":"ZTE",
+                    "version":1,
+                    "invariant_id":"vcpe_ns_sff_1",
+                    "id":"VCPE_NS",
+                    "description":"vcpe_ns"
+                },
+                "policies:":[
+                    {
+                        "aaa:" : {
+                            "type": "tosca.policies.Drools",
+                            "properties": {
+                                "drl_file_url":"policies/abc.drl"
+                            }
+                        }
+                    }
+                ],
+                "nodes":[
+                    {
+                        "id":"policies",
+                        "type_name":"tosca.policies.Drools",
+                        "template_name":"aaa",
+                        "properties":{
+                            "drl_file_url":{
+                                "type_name":"string",
+                                "value":"policies/abc.drl"
+                            }
+                        }
+                    },
+                    {
+                        "id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                        "type_name":"tosca.nodes.nfv.ext.FP",
+                        "template_name":"path2",
+                        "properties":{
+                            "symmetric":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "policy":{
+                                "type_name":"tosca.datatypes.nfv.ext.FPPolicy",
+                                "value":{
+                                    "type":"ACL",
+                                    "criteria":{
+                                        "dest_port_range":"1-100",
+                                        "ip_protocol":"tcp",
+                                        "source_ip_range":[
+                                            "119.1.1.1-119.1.1.10"
+                                        ],
+                                        "dest_ip_range":[
+                                            {"get_input":"NatIpRange"}
+                                        ],
+                                        "dscp":0,
+                                        "source_port_range":"1-100"
+                                    }
+                                }
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":0,
+                                "target_node_id":"m6000_data_out_qeukdtf6g87cnparxi51fa8s6"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":1,
+                                "target_node_id":"m600_tunnel_cp_imwfk5l48ljz0g9knc6d68hv5"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":2,
+                                "target_node_id":"VNAT_cfdljtspvkp234irka59wgab0",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"path1_bv53fblv26hawr8dj4fxe2rsd",
+                        "type_name":"tosca.nodes.nfv.ext.FP",
+                        "template_name":"path1",
+                        "properties":{
+                            "symmetric":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "policy":{
+                                "type_name":"tosca.datatypes.nfv.ext.FPPolicy",
+                                "value":{
+                                    "type":"ACL",
+                                    "criteria":{
+                                        "dest_port_range":"1-100",
+                                        "ip_protocol":"tcp",
+                                        "source_ip_range":[
+                                            "1-100"
+                                        ],
+                                        "dest_ip_range":[
+                                            "1-100"
+                                        ],
+                                        "dscp":4,
+                                        "source_port_range":"1-100"
+                                    }
+                                }
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":0,
+                                "target_node_id":"m6000_data_in_eldly5txw4frny3cc349uz3nc"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":1,
+                                "target_node_id":"m600_tunnel_cp_imwfk5l48ljz0g9knc6d68hv5"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":2,
+                                "target_node_id":"VFW_57z0ua89aiyl8ncvw7h7mjf34",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":3,
+                                "target_node_id":"VNAT_cfdljtspvkp234irka59wgab0",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":4,
+                                "target_node_id":"m600_tunnel_cp_imwfk5l48ljz0g9knc6d68hv5"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":5,
+                                "target_node_id":"m6000_data_out_qeukdtf6g87cnparxi51fa8s6"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"m6000_data_out_qeukdtf6g87cnparxi51fa8s6",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "template_name":"m6000_data_out",
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"11-22-33-22-11-44"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"xgei-0/4/1/5"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"176.1.1.2"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"virtualbinding",
+                                "source_requirement_index":0,
+                                "target_node_id":"m6000_s_7qtzo5nuocyfmebc6kp9raq18",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "source_requirement_index":1,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":2,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"VFW_57z0ua89aiyl8ncvw7h7mjf34",
+                        "type_name":"tosca.nodes.nfv.ext.zte.VNF.VFW",
+                        "template_name":"VFW",
+                        "properties":{
+                            "is_shared":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "plugin_info":{
+                                "type_name":"string",
+                                "value":"vbrasplugin_1.0"
+                            },
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "request_reclassification":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "vnf_extend_type":{
+                                "type_name":"string",
+                                "value":"driver"
+                            },
+                            "name":{
+                                "type_name":"string",
+                                "value":"VFW"
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "cross_dc":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "vnf_type":{
+                                "type_name":"string",
+                                "value":"VFW"
+                            },
+                            "vnfd_version":{
+                                "type_name":"string",
+                                "value":"1.0.0"
+                            },
+                            "id":{
+                                "type_name":"string",
+                                "value":"vcpe_vfw_zte_1_0"
+                            },
+                            "nsh_aware":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "adjust_vnf_capacity":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "vmnumber_overquota_alarm":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "csarProvider":{
+                                "type_name":"string",
+                                "value":"ZTE"
+                            },
+                            "csarVersion":{
+                                "type_name":"string",
+                                "value":"v1.0"
+                            },
+                            "externalPluginManageNetworkName":{
+                                "type_name":"string",
+                                "value":"vlan_4007_plugin_net"
+                            },
+                            "csarType":{
+                                "type_name":"string",
+                                "value":"NFAR"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            },
+                            {
+                                "name":"vfw_fw_inout",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"vfw_ctrl_by_manager_cp",
+                                "source_requirement_index":0,
+                                "target_node_id":"ext_mnet_net_au2otee5mcy0dnpqykj487zr3",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"vfw_data_cp",
+                                "source_requirement_index":1,
+                                "target_node_id":"sfc_data_network_vx3pc1oahn0k0pa5q722yafee",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "source_requirement_index":2,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":3,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"m600_tunnel_cp_imwfk5l48ljz0g9knc6d68hv5",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "template_name":"m600_tunnel_cp",
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"00-11-00-22-33-00"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"gei-0/4/0/13"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"191.167.100.5"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"virtualLink",
+                                "source_requirement_index":0,
+                                "target_node_id":"ext_datanet_net_qtqzlx5dsthzs883hxjn6hyhd",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"virtualbinding",
+                                "source_requirement_index":1,
+                                "target_node_id":"m6000_s_7qtzo5nuocyfmebc6kp9raq18",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":2,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"ext_mnet_net_au2otee5mcy0dnpqykj487zr3",
+                        "type_name":"tosca.nodes.nfv.ext.VL.Vmware",
+                        "template_name":"ext_mnet_net",
+                        "properties":{
+                            "name":{
+                                "type_name":"string",
+                                "value":"vlan_4008_mng_net"
+                            },
+                            "dhcp_enabled":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "location_info":{
+                                "type_name":"tosca.datatypes.nfv.ext.LocationInfo",
+                                "value":{
+                                    "tenant":"admin",
+                                    "vimid":2,
+                                    "availability_zone":"nova"
+                                }
+                            },
+                            "ip_version":{
+                                "type_name":"integer",
+                                "value":4
+                            },
+                            "mtu":{
+                                "type_name":"integer",
+                                "value":1500
+                            },
+                            "network_name":{
+                                "type_name":"string",
+                                "value":"vlan_4008_mng_net"
+                            },
+                            "network_type":{
+                                "type_name":"string",
+                                "value":"vlan"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtual_linkable",
+                                "type_name":"tosca.capabilities.nfv.VirtualLinkable"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"m6000_data_in_eldly5txw4frny3cc349uz3nc",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "template_name":"m6000_data_in",
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"11-22-33-22-11-41"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"gei-0/4/0/7"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"1.1.1.1"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            },
+                            "bond":{
+                                "type_name":"string",
+                                "value":"none"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"virtualbinding",
+                                "source_requirement_index":0,
+                                "target_node_id":"m6000_s_7qtzo5nuocyfmebc6kp9raq18",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "source_requirement_index":1,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":2,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"ext_datanet_net_qtqzlx5dsthzs883hxjn6hyhd",
+                        "type_name":"tosca.nodes.nfv.ext.VL.Vmware",
+                        "template_name":"ext_datanet_net",
+                        "properties":{
+                            "name":{
+                                "type_name":"string",
+                                "value":"vlan_4004_tunnel_net"
+                            },
+                            "dhcp_enabled":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "location_info":{
+                                "type_name":"tosca.datatypes.nfv.ext.LocationInfo",
+                                "value":{
+                                    "tenant":"admin",
+                                    "vimid":2,
+                                    "availability_zone":"nova"
+                                }
+                            },
+                            "ip_version":{
+                                "type_name":"integer",
+                                "value":4
+                            },
+                            "mtu":{
+                                "type_name":"integer",
+                                "value":1500
+                            },
+                            "network_name":{
+                                "type_name":"string",
+                                "value":"vlan_4004_tunnel_net"
+                            },
+                            "network_type":{
+                                "type_name":"string",
+                                "value":"vlan"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtual_linkable",
+                                "type_name":"tosca.capabilities.nfv.VirtualLinkable"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"m600_mnt_cp_l3488y2a8ilyfdn0l89ni4os7",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "template_name":"m600_mnt_cp",
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"00-11-00-22-33-11"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"gei-0/4/0/1"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"10.46.244.51"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            },
+                            "bond":{
+                                "type_name":"string",
+                                "value":"none"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"virtualLink",
+                                "source_requirement_index":0,
+                                "target_node_id":"ext_mnet_net_au2otee5mcy0dnpqykj487zr3",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"virtualbinding",
+                                "source_requirement_index":1,
+                                "target_node_id":"m6000_s_7qtzo5nuocyfmebc6kp9raq18",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":2,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"sfc_data_network_vx3pc1oahn0k0pa5q722yafee",
+                        "type_name":"tosca.nodes.nfv.ext.zte.VL",
+                        "template_name":"sfc_data_network",
+                        "properties":{
+                            "name":{
+                                "type_name":"string",
+                                "value":"sfc_data_network"
+                            },
+                            "dhcp_enabled":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "is_predefined":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "location_info":{
+                                "type_name":"tosca.datatypes.nfv.ext.LocationInfo",
+                                "value":{
+                                    "tenant":"admin",
+                                    "vimid":2,
+                                    "availability_zone":"nova"
+                                }
+                            },
+                            "ip_version":{
+                                "type_name":"integer",
+                                "value":4
+                            },
+                            "mtu":{
+                                "type_name":"integer",
+                                "value":1500
+                            },
+                            "network_name":{
+                                "type_name":"string",
+                                "value":"sfc_data_network"
+                            },
+                            "network_type":{
+                                "type_name":"string",
+                                "value":"vlan"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtual_linkable",
+                                "type_name":"tosca.capabilities.nfv.VirtualLinkable"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"m6000_s_7qtzo5nuocyfmebc6kp9raq18",
+                        "type_name":"tosca.nodes.nfv.ext.PNF",
+                        "template_name":"m6000_s",
+                        "properties":{
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "request_reclassification":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "pnf_type":{
+                                "type_name":"string",
+                                "value":"m6000s"
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "management_address":{
+                                "type_name":"string",
+                                "value":"111111"
+                            },
+                            "id":{
+                                "type_name":"string",
+                                "value":"m6000_s"
+                            },
+                            "nsh_aware":{
+                                "type_name":"boolean",
+                                "value":False
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtualBinding",
+                                "type_name":"tosca.capabilities.nfv.VirtualBindable"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":0,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    },
+                    {
+                        "id":"VNAT_cfdljtspvkp234irka59wgab0",
+                        "type_name":"tosca.nodes.nfv.ext.zte.VNF.VNAT",
+                        "template_name":"VNAT",
+                        "properties":{
+                            "is_shared":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "plugin_info":{
+                                "type_name":"string",
+                                "value":"vbrasplugin_1.0"
+                            },
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "request_reclassification":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "name":{
+                                "type_name":"string",
+                                "value":"VNAT"
+                            },
+                            "vnf_extend_type":{
+                                "type_name":"string",
+                                "value":"driver"
+                            },
+                            "externalPluginManageNetworkName":{
+                                "type_name":"string",
+                                "value":"vlan_4007_plugin_net"
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "cross_dc":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "vnf_type":{
+                                "type_name":"string",
+                                "value":"VNAT"
+                            },
+                            "vnfd_version":{
+                                "type_name":"string",
+                                "value":"1.0.0"
+                            },
+                            "id":{
+                                "type_name":"string",
+                                "value":"vcpe_vnat_zte_1"
+                            },
+                            "nsh_aware":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "adjust_vnf_capacity":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "vmnumber_overquota_alarm":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "csarProvider":{
+                                "type_name":"string",
+                                "value":"ZTE"
+                            },
+                            "NatIpRange":{
+                                "type_name":"string",
+                                "value":"192.167.0.10-192.168.0.20"
+                            },
+                            "csarVersion":{
+                                "type_name":"string",
+                                "value":"v1.0"
+                            },
+                            "csarType":{
+                                "type_name":"string",
+                                "value":"NFAR"
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"Standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "capabilities":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            },
+                            {
+                                "name":"vnat_fw_inout",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "relationships":[
+                            {
+                                "name":"vnat_ctrl_by_manager_cp",
+                                "source_requirement_index":0,
+                                "target_node_id":"ext_mnet_net_au2otee5mcy0dnpqykj487zr3",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"vnat_data_cp",
+                                "source_requirement_index":1,
+                                "target_node_id":"sfc_data_network_vx3pc1oahn0k0pa5q722yafee",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "source_requirement_index":2,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            },
+                            {
+                                "name":"forwarder",
+                                "source_requirement_index":3,
+                                "target_node_id":"path2_kgmfqr5ldqs9lj3oscrgxqefc",
+                                "target_capability_name":"feature"
+                            }
+                        ]
+                    }
+                ],
+                "groups":[
+                    {
+                        "id":"vnffg1_wk1aqhk6exoh5fmds2unu0uyc",
+                        "type_name":"tosca.groups.nfv.VNFFG",
+                        "template_name":"vnffg1",
+                        "properties":{
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "connection_point":{
+                                "type_name":"list",
+                                "value":[
+                                    "m6000_data_in",
+                                    "m600_tunnel_cp",
+                                    "m6000_data_out"
+                                ]
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "constituent_vnfs":{
+                                "type_name":"list",
+                                "value":[
+                                    "VFW",
+                                    "VNAT"
+                                ]
+                            },
+                            "number_of_endpoints":{
+                                "type_name":"integer",
+                                "value":3
+                            },
+                            "dependent_virtual_link":{
+                                "type_name":"list",
+                                "value":[
+                                    "sfc_data_network",
+                                    "ext_datanet_net",
+                                    "ext_mnet_net"
+                                ]
+                            }
+                        },
+                        "interfaces":[
+                            {
+                                "name":"standard",
+                                "description":"This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                                "type_name":"tosca.interfaces.node.lifecycle.Standard",
+                                "operations":[
+                                    {
+                                        "name":"create",
+                                        "description":"Standard lifecycle create operation."
+                                    },
+                                    {
+                                        "name":"stop",
+                                        "description":"Standard lifecycle stop operation."
+                                    },
+                                    {
+                                        "name":"start",
+                                        "description":"Standard lifecycle start operation."
+                                    },
+                                    {
+                                        "name":"delete",
+                                        "description":"Standard lifecycle delete operation."
+                                    },
+                                    {
+                                        "name":"configure",
+                                        "description":"Standard lifecycle configure operation."
+                                    }
+                                ]
+                            }
+                        ],
+                        "member_node_ids":[
+                            "path1_bv53fblv26hawr8dj4fxe2rsd",
+                            "path2_kgmfqr5ldqs9lj3oscrgxqefc"
+                        ]
+                    }
+                ],
+                "substitution":{
+                    "node_type_name":"tosca.nodes.nfv.NS.VCPE_NS"
+                },
+                "inputs":{
+                    "externalDataNetworkName":{
+                        "type_name":"string",
+                        "value":"vlan_4004_tunnel_net"
+                    },
+                    "sfc_data_network":{
+                        "type_name":"string",
+                        "value":"sfc_data_network"
+                    },
+                    "NatIpRange":{
+                        "type_name":"string",
+                        "value":"192.167.0.10-192.168.0.20"
+                    },
+                    "externalManageNetworkName":{
+                        "type_name":"string",
+                        "value":"vlan_4008_mng_net"
+                    },
+                    "externalPluginManageNetworkName":{
+                        "type_name":"string",
+                        "value":"vlan_4007_plugin_net"
+                    }
+                }
+            },
+            "model":{
+                "metadata":{
+                    "vendor":"ZTE",
+                    "name":"VCPE_NS",
+                    "csarVersion":"v1.0",
+                    "csarType":"NSAR",
+                    "csarProvider":"ZTE",
+                    "version":1,
+                    "invariant_id":"vcpe_ns_sff_1",
+                    "id":"VCPE_NS",
+                    "description":"vcpe_ns"
+                },
+                "node_templates":[
+                    {
+                        "name":"path2",
+                        "type_name":"tosca.nodes.nfv.ext.FP",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "symmetric":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "policy":{
+                                "type_name":"tosca.datatypes.nfv.ext.FPPolicy",
+                                "value":{
+                                    "type":"ACL",
+                                    "criteria":{
+                                        "dest_port_range":"1-100",
+                                        "ip_protocol":"tcp",
+                                        "source_ip_range":[
+                                            "119.1.1.1-119.1.1.10"
+                                        ],
+                                        "dest_ip_range":[
+                                            {"get_input":"NatIpRange"}
+                                        ],
+                                        "dscp":0,
+                                        "source_port_range":"1-100"
+                                    }
+                                }
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ed0288a10>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"m6000_data_out"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"m600_tunnel_cp"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"VNAT",
+                                "target_capability_name":"vnat_fw_inout"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"path1",
+                        "type_name":"tosca.nodes.nfv.ext.FP",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "symmetric":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "policy":{
+                                "type_name":"tosca.datatypes.nfv.ext.FPPolicy",
+                                "value":{
+                                    "type":"ACL",
+                                    "criteria":{
+                                        "dest_port_range":"1-100",
+                                        "ip_protocol":"tcp",
+                                        "source_ip_range":[
+                                            "1-100"
+                                        ],
+                                        "dest_ip_range":[
+                                            "1-100"
+                                        ],
+                                        "dscp":4,
+                                        "source_port_range":"1-100"
+                                    }
+                                }
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ec81df090>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"m6000_data_in"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"m600_tunnel_cp"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"VFW",
+                                "target_capability_name":"vfw_fw_inout"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"VNAT",
+                                "target_capability_name":"vnat_fw_inout"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"m600_tunnel_cp"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_template_name":"m6000_data_out"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"m6000_data_out",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"11-22-33-22-11-44"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"xgei-0/4/1/5"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"176.1.1.2"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ec82c6610>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"virtualbinding",
+                                "target_node_template_name":"m6000_s",
+                                "target_capability_name":"virtualBinding"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"VFW",
+                        "type_name":"tosca.nodes.nfv.ext.zte.VNF.VFW",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "is_shared":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "plugin_info":{
+                                "type_name":"string",
+                                "value":"vbrasplugin_1.0"
+                            },
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "request_reclassification":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "vnf_extend_type":{
+                                "type_name":"string",
+                                "value":"driver"
+                            },
+                            "name":{
+                                "type_name":"string",
+                                "value":"VFW"
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "cross_dc":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "vnf_type":{
+                                "type_name":"string",
+                                "value":"VFW"
+                            },
+                            "vnfd_version":{
+                                "type_name":"string",
+                                "value":"1.0.0"
+                            },
+                            "id":{
+                                "type_name":"string",
+                                "value":"vcpe_vfw_zte_1_0"
+                            },
+                            "nsh_aware":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "adjust_vnf_capacity":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "vmnumber_overquota_alarm":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "csarProvider":{
+                                "type_name":"string",
+                                "value":"ZTE"
+                            },
+                            "csarVersion":{
+                                "type_name":"string",
+                                "value":"v1.0"
+                            },
+                            "externalPluginManageNetworkName":{
+                                "type_name":"string",
+                                "value":"vlan_4007_plugin_net"
+                            },
+                            "csarType":{
+                                "type_name":"string",
+                                "value":"NFAR"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ec8281950>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            },
+                            {
+                                "name":"vfw_fw_inout",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"vfw_ctrl_by_manager_cp",
+                                "target_node_template_name":"ext_mnet_net",
+                                "target_capability_name":"virtual_linkable"
+                            },
+                            {
+                                "name":"vfw_data_cp",
+                                "target_node_template_name":"sfc_data_network",
+                                "target_capability_name":"virtual_linkable"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"m600_tunnel_cp",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"00-11-00-22-33-00"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"gei-0/4/0/13"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"191.167.100.5"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x1ae39d0>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"virtualLink",
+                                "target_node_template_name":"ext_datanet_net",
+                                "target_capability_name":"virtual_linkable"
+                            },
+                            {
+                                "name":"virtualbinding",
+                                "target_node_template_name":"m6000_s",
+                                "target_capability_name":"virtualBinding"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"ext_mnet_net",
+                        "type_name":"tosca.nodes.nfv.ext.VL.Vmware",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "name":{
+                                "type_name":"string",
+                                "value":"vlan_4008_mng_net"
+                            },
+                            "dhcp_enabled":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "location_info":{
+                                "type_name":"tosca.datatypes.nfv.ext.LocationInfo",
+                                "value":{
+                                    "tenant":"admin",
+                                    "vimid":2,
+                                    "availability_zone":"nova"
+                                }
+                            },
+                            "ip_version":{
+                                "type_name":"integer",
+                                "value":4
+                            },
+                            "mtu":{
+                                "type_name":"integer",
+                                "value":1500
+                            },
+                            "network_name":{
+                                "type_name":"string",
+                                "value":"vlan_4008_mng_net"
+                            },
+                            "network_type":{
+                                "type_name":"string",
+                                "value":"vlan"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ed00f89d0>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtual_linkable",
+                                "type_name":"tosca.capabilities.nfv.VirtualLinkable"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"m6000_data_in",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"11-22-33-22-11-41"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"gei-0/4/0/7"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"1.1.1.1"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            },
+                            "bond":{
+                                "type_name":"string",
+                                "value":"none"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x1745710>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"virtualbinding",
+                                "target_node_template_name":"m6000_s",
+                                "target_capability_name":"virtualBinding"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"ext_datanet_net",
+                        "type_name":"tosca.nodes.nfv.ext.VL.Vmware",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "name":{
+                                "type_name":"string",
+                                "value":"vlan_4004_tunnel_net"
+                            },
+                            "dhcp_enabled":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "location_info":{
+                                "type_name":"tosca.datatypes.nfv.ext.LocationInfo",
+                                "value":{
+                                    "tenant":"admin",
+                                    "vimid":2,
+                                    "availability_zone":"nova"
+                                }
+                            },
+                            "ip_version":{
+                                "type_name":"integer",
+                                "value":4
+                            },
+                            "mtu":{
+                                "type_name":"integer",
+                                "value":1500
+                            },
+                            "network_name":{
+                                "type_name":"string",
+                                "value":"vlan_4004_tunnel_net"
+                            },
+                            "network_type":{
+                                "type_name":"string",
+                                "value":"vlan"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8eac063990>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtual_linkable",
+                                "type_name":"tosca.capabilities.nfv.VirtualLinkable"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"m600_mnt_cp",
+                        "type_name":"tosca.nodes.nfv.ext.zte.CP",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "direction":{
+                                "type_name":"string",
+                                "value":"bidirectional"
+                            },
+                            "vnic_type":{
+                                "type_name":"string",
+                                "value":"normal"
+                            },
+                            "bandwidth":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "mac_address":{
+                                "type_name":"string",
+                                "value":"00-11-00-22-33-11"
+                            },
+                            "interface_name":{
+                                "type_name":"string",
+                                "value":"gei-0/4/0/1"
+                            },
+                            "ip_address":{
+                                "type_name":"string",
+                                "value":"10.46.244.51"
+                            },
+                            "order":{
+                                "type_name":"integer",
+                                "value":0
+                            },
+                            "sfc_encapsulation":{
+                                "type_name":"string",
+                                "value":"mac"
+                            },
+                            "bond":{
+                                "type_name":"string",
+                                "value":"none"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ec81264d0>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"virtualLink",
+                                "target_node_template_name":"ext_mnet_net",
+                                "target_capability_name":"virtual_linkable"
+                            },
+                            {
+                                "name":"virtualbinding",
+                                "target_node_template_name":"m6000_s",
+                                "target_capability_name":"virtualBinding"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"sfc_data_network",
+                        "type_name":"tosca.nodes.nfv.ext.zte.VL",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "name":{
+                                "type_name":"string",
+                                "value":"sfc_data_network"
+                            },
+                            "dhcp_enabled":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "is_predefined":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "location_info":{
+                                "type_name":"tosca.datatypes.nfv.ext.LocationInfo",
+                                "value":{
+                                    "tenant":"admin",
+                                    "vimid":2,
+                                    "availability_zone":"nova"
+                                }
+                            },
+                            "ip_version":{
+                                "type_name":"integer",
+                                "value":4
+                            },
+                            "mtu":{
+                                "type_name":"integer",
+                                "value":1500
+                            },
+                            "network_name":{
+                                "type_name":"string",
+                                "value":"sfc_data_network"
+                            },
+                            "network_type":{
+                                "type_name":"string",
+                                "value":"vlan"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ec813c6d0>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtual_linkable",
+                                "type_name":"tosca.capabilities.nfv.VirtualLinkable"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"m6000_s",
+                        "type_name":"tosca.nodes.nfv.ext.PNF",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "request_reclassification":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "pnf_type":{
+                                "type_name":"string",
+                                "value":"m6000s"
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "management_address":{
+                                "type_name":"string",
+                                "value":"111111"
+                            },
+                            "id":{
+                                "type_name":"string",
+                                "value":"m6000_s"
+                            },
+                            "nsh_aware":{
+                                "type_name":"boolean",
+                                "value":False
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ec8132490>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"virtualBinding",
+                                "type_name":"tosca.capabilities.nfv.VirtualBindable"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"forwarder",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            }
+                        ]
+                    },
+                    {
+                        "name":"VNAT",
+                        "type_name":"tosca.nodes.nfv.ext.zte.VNF.VNAT",
+                        "default_instances":1,
+                        "min_instances":0,
+                        "properties":{
+                            "is_shared":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "plugin_info":{
+                                "type_name":"string",
+                                "value":"vbrasplugin_1.0"
+                            },
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "request_reclassification":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "name":{
+                                "type_name":"string",
+                                "value":"VNAT"
+                            },
+                            "vnf_extend_type":{
+                                "type_name":"string",
+                                "value":"driver"
+                            },
+                            "externalPluginManageNetworkName":{
+                                "type_name":"string",
+                                "value":"vlan_4007_plugin_net"
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "cross_dc":{
+                                "type_name":"boolean",
+                                "value":False
+                            },
+                            "vnf_type":{
+                                "type_name":"string",
+                                "value":"VNAT"
+                            },
+                            "vnfd_version":{
+                                "type_name":"string",
+                                "value":"1.0.0"
+                            },
+                            "id":{
+                                "type_name":"string",
+                                "value":"vcpe_vnat_zte_1"
+                            },
+                            "nsh_aware":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "adjust_vnf_capacity":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "vmnumber_overquota_alarm":{
+                                "type_name":"boolean",
+                                "value":True
+                            },
+                            "csarProvider":{
+                                "type_name":"string",
+                                "value":"ZTE"
+                            },
+                            "NatIpRange":{
+                                "type_name":"string",
+                                "value":"192.167.0.10-192.168.0.20"
+                            },
+                            "csarVersion":{
+                                "type_name":"string",
+                                "value":"v1.0"
+                            },
+                            "csarType":{
+                                "type_name":"string",
+                                "value":"NFAR"
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x1bba810>"
+                        ],
+                        "capability_templates":[
+                            {
+                                "name":"feature",
+                                "type_name":"tosca.capabilities.Node"
+                            },
+                            {
+                                "name":"forwarder",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            },
+                            {
+                                "name":"vnat_fw_inout",
+                                "type_name":"tosca.capabilities.nfv.Forwarder"
+                            }
+                        ],
+                        "requirement_templates":[
+                            {
+                                "name":"vnat_ctrl_by_manager_cp",
+                                "target_node_template_name":"ext_mnet_net",
+                                "target_capability_name":"virtual_linkable"
+                            },
+                            {
+                                "name":"vnat_data_cp",
+                                "target_node_template_name":"sfc_data_network",
+                                "target_capability_name":"virtual_linkable"
+                            },
+                            {
+                                "name":"virtualLink",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            },
+                            {
+                                "name":"forwarder",
+                                "target_node_type_name":"tosca.nodes.Root"
+                            }
+                        ]
+                    }
+                ],
+                "group_templates":[
+                    {
+                        "name":"vnffg1",
+                        "type_name":"tosca.groups.nfv.VNFFG",
+                        "properties":{
+                            "vendor":{
+                                "type_name":"string",
+                                "value":"zte"
+                            },
+                            "connection_point":{
+                                "type_name":"list",
+                                "value":[
+                                    "m6000_data_in",
+                                    "m600_tunnel_cp",
+                                    "m6000_data_out"
+                                ]
+                            },
+                            "version":{
+                                "type_name":"string",
+                                "value":"1.0"
+                            },
+                            "constituent_vnfs":{
+                                "type_name":"list",
+                                "value":[
+                                    "VFW",
+                                    "VNAT"
+                                ]
+                            },
+                            "number_of_endpoints":{
+                                "type_name":"integer",
+                                "value":3
+                            },
+                            "dependent_virtual_link":{
+                                "type_name":"list",
+                                "value":[
+                                    "sfc_data_network",
+                                    "ext_datanet_net",
+                                    "ext_mnet_net"
+                                ]
+                            }
+                        },
+                        "interface_templates":[
+                            "<aria.modeling.model_elements.InterfaceTemplate object at 0x7f8ec811cd10>"
+                        ],
+                        "member_node_template_names":[
+                            "path1",
+                            "path2"
+                        ]
+                    }
+                ],
+                "substitution_template":{
+                    "node_type_name":"tosca.nodes.nfv.NS.VCPE_NS"
+                },
+                "inputs":{
+                    "externalDataNetworkName":{
+                        "type_name":"string",
+                        "value":"vlan_4004_tunnel_net"
+                    },
+                    "sfc_data_network":{
+                        "type_name":"string",
+                        "value":"sfc_data_network"
+                    },
+                    "NatIpRange":{
+                        "type_name":"string",
+                        "value":"192.167.0.10-192.168.0.20"
+                    },
+                    "externalManageNetworkName":{
+                        "type_name":"string",
+                        "value":"vlan_4008_mng_net"
+                    },
+                    "externalPluginManageNetworkName":{
+                        "type_name":"string",
+                        "value":"vlan_4007_plugin_net"
+                    }
+                }
+            }
+        }
+    )
+    print convert_nsd_model(src_json)
diff --git a/lcm/pub/utils/toscautil_new.py b/lcm/pub/utils/toscautil_new.py
new file mode 100644 (file)
index 0000000..1b01989
--- /dev/null
@@ -0,0 +1,1458 @@
+# Copyright 2017 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
+
+def safe_get(key_val, key):
+    return key_val[key] if key in key_val else ""
+
+
+def find_node_name(node_id, node_list):
+    for node in node_list:
+        if node['id'] == node_id:
+            return node['template_name']
+    raise Exception('can not find node(%s).' % node_id)
+
+
+def find_node_type(node_id, node_list):
+    for node in node_list:
+        if node['id'] == node_id:
+            return node['type_name']
+    raise Exception('can not find node(%s).' % node_id)
+
+
+def find_related_node(node_id, src_json_model, requirement_name):
+    related_nodes = []
+    for model_tpl in safe_get(src_json_model, "node_templates"):
+        for rt in safe_get(model_tpl, 'requirement_templates'):
+            if safe_get(rt, 'name') == requirement_name and \
+                safe_get(rt, 'target_node_template_name') == node_id:
+                related_nodes.append(model_tpl['name'])
+    return related_nodes
+
+
+def convert_props(src_node, dest_node):
+    if 'properties' in src_node and src_node['properties']:
+        for prop_name, prop_info in src_node['properties'].items():
+            if 'value' in prop_info:
+                dest_node['properties'][prop_name] = prop_info['value']   
+
+
+def convert_metadata(src_json):
+    return src_json['metadata'] if 'metadata' in src_json else {}
+
+def convert_factor_unit(value):
+    if isinstance(value, (str, unicode)):
+        return value
+    return "%s %s" % (value["factor"], value["unit"])
+
+def convert_inputs(src_json):
+    inputs = {}
+    if 'inputs' in src_json:
+        src_inputs = src_json['inputs']
+        for param_name, param_info in src_inputs.items():
+            input_param = {}
+            if 'type_name' in param_info:
+                input_param['type'] = param_info['type_name']
+            if 'description' in param_info:
+                input_param['description'] = param_info['description']
+            if 'value' in param_info:
+                input_param['value'] = param_info['value']
+            inputs[param_name] = input_param
+    return inputs
+
+
+def convert_vnf_node(src_node, src_json_model):
+    vnf_node = {'type': src_node['type_name'], 'vnf_id': src_node['template_name'],
+        'description': '', 'properties': {}, 'dependencies': [], 'networks': []}
+    convert_props(src_node, vnf_node)
+    for model_tpl in safe_get(src_json_model, "node_templates"):
+        if model_tpl['name'] != vnf_node['vnf_id']:
+            continue
+        vnf_node['dependencies'] = [{
+            'key_name': requirement['name'],
+            'vl_id': requirement['target_node_template_name']} for \
+            requirement in safe_get(model_tpl, 'requirement_templates') if \
+            safe_get(requirement, 'target_capability_name') == 'virtual_linkable']
+        vnf_node['networks'] = [requirement['target_node_template_name'] for \
+            requirement in safe_get(model_tpl, 'requirement_templates') if \
+            safe_get(requirement, 'name') == 'dependency']
+    return vnf_node
+
+
+def convert_pnf_node(src_node, src_json_model):
+    pnf_node = {'pnf_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, pnf_node)
+    pnf_node['cps'] = find_related_node(src_node['id'], src_json_model, 'virtualbinding')
+    return pnf_node
+
+
+def convert_vl_node(src_node, src_node_list):
+    vl_node = {'vl_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, vl_node)
+    vl_node['route_id'] = ''
+    for relation in safe_get(src_node, 'relationships'):
+        if safe_get(relation, 'type_name').endswith('.VirtualLinksTo'):
+            vl_node['route_id'] = find_node_name(relation['target_node_id'], src_node_list)
+            break
+    vl_node['route_external'] = (src_node['type_name'].find('.RouteExternalVL') > 0)
+    return vl_node
+
+
+def convert_cp_node(src_node, src_node_list, model_type='NSD'):
+    cp_node = {'cp_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, cp_node)
+    src_relationships = src_node['relationships']
+    for relation in src_relationships:
+        if safe_get(relation, 'name') in ('virtualLink', 'virtual_link'):
+            cp_node['vl_id'] = find_node_name(relation['target_node_id'], src_node_list)
+        elif safe_get(relation, 'name') in ('virtualbinding', 'virtual_binding'):
+            node_key = 'pnf_id' if model_type == 'NSD' else 'vdu_id'
+            cp_node[node_key] = find_node_name(relation['target_node_id'], src_node_list)
+    return cp_node
+
+
+def convert_router_node(src_node, src_node_list):
+    router_node = {'router_id': src_node['template_name'], 'description': '', 'properties': {}}
+    convert_props(src_node, router_node)
+    for relation in src_node['relationships']:
+        if safe_get(relation, 'name') != 'external_virtual_link':
+            continue
+        router_node['external_vl_id'] = find_node_name(relation['target_node_id'], src_node_list)
+        router_node['external_ip_addresses'] = []
+        if 'properties' not in relation:
+            continue
+        for prop_name, prop_info in relation['properties'].items():
+            if prop_name == 'router_ip_address':
+                router_node['external_ip_addresses'].append(prop_info['value'])
+        break
+    return router_node
+
+
+def convert_fp_node(src_node, src_node_list, src_json_model):
+    fp_node = {'fp_id': src_node['template_name'], 'description': '', 
+        'properties': {}, 'forwarder_list': []}
+    convert_props(src_node, fp_node)
+    for relation in safe_get(src_node, 'relationships'):
+        if safe_get(relation, 'name') != 'forwarder':
+            continue
+        forwarder_point = {'type': 'vnf'}
+        target_node_type = find_node_type(relation['target_node_id'], src_node_list).upper()
+        if target_node_type.find('.CP.') >= 0 or target_node_type.endswith('.CP'):
+            forwarder_point['type'] = 'cp'
+        forwarder_point['node_name'] = find_node_name(relation['target_node_id'], src_node_list)
+        forwarder_point['capability'] = ''
+        if forwarder_point['type'] == 'vnf':
+            for node_tpl in src_json_model["node_templates"]:
+                if fp_node['fp_id'] != node_tpl["name"]:
+                    continue
+                for r_tpl in safe_get(node_tpl, "requirement_templates"):
+                    if safe_get(r_tpl, "target_node_template_name") != forwarder_point['node_name']:
+                        continue
+                    forwarder_point['capability'] = safe_get(r_tpl, "target_capability_name")
+                    break
+                break
+        fp_node['forwarder_list'].append(forwarder_point)
+    return fp_node
+
+
+def convert_vnffg_group(src_group, src_group_list, src_node_list):
+    vnffg = {'vnffg_id': src_group['template_name'], 'description': '', 
+        'properties': {}, 'members': []}
+    convert_props(src_group, vnffg)
+    for member_node_id in src_group['member_node_ids']:
+        vnffg['members'].append(find_node_name(member_node_id, src_node_list))
+    return vnffg
+
+
+def convert_imagefile_node(src_node, src_node_list):
+    image_node = {'image_file_id': src_node['template_name'], 'description': '', 
+        'properties': {}}
+    convert_props(src_node, image_node)
+    return image_node
+
+
+def convert_localstorage_node(src_node, src_node_list):
+    localstorage_node = {'local_storage_id': src_node['template_name'], 'description': '', 
+        'properties': {}}
+    convert_props(src_node, localstorage_node)
+    return localstorage_node
+
+def convert_volumestorage_node(src_node, src_node_list):
+    volumestorage_node = {
+        'volume_storage_id': src_node['id'], 
+        'description': "", 
+        'properties': {}}
+    convert_props(src_node, volumestorage_node)
+    volumestorage_node["properties"]["size"] = convert_factor_unit(
+        volumestorage_node["properties"]["size_of_storage"])
+    return volumestorage_node
+
+def convert_vdu_node(src_node, src_node_list, src_json_model):
+    vdu_node = {'vdu_id': src_node['template_name'], 'description': '', 'properties': {},
+        'image_file': '', 'local_storages': [], 'dependencies': [], 'nfv_compute': {},
+        'vls': [], 'artifacts': [], 'volume_storages': []}
+    convert_props(src_node, vdu_node)
+
+    for relation in src_node.get('relationships', ''):
+        r_id, r_name = safe_get(relation, 'target_node_id'), safe_get(relation, 'name')
+        if r_name == 'guest_os':
+            vdu_node['image_file'] = find_node_name(r_id, src_node_list)
+        elif r_name == 'local_storage':
+            vdu_node['local_storages'].append(find_node_name(r_id, src_node_list))
+        elif r_name == 'virtual_storage':
+            vdu_node['volume_storages'].append(r_id)
+        elif r_name.endswith('.AttachesTo'):
+            nt = find_node_type(r_id, src_node_list)
+            if nt.endswith('.BlockStorage.Local') or nt.endswith('.LocalStorage'):
+                vdu_node['local_storages'].append(find_node_name(r_id, src_node_list))
+
+    for capability in src_node['capabilities']:
+        if not capability['type_name'].endswith('.VirtualCompute'):
+            continue
+        vdu_node['nfv_compute']['flavor_extra_specs'] = {}
+        for prop_name, prop_info in capability['properties'].items():
+            if prop_name == "virtual_cpu":
+                vdu_node['nfv_compute']['num_cpus'] = prop_info["value"]["num_virtual_cpu"]
+                if "virtual_cpu_clock" in prop_info["value"]:
+                    vdu_node['nfv_compute']['cpu_frequency'] = convert_factor_unit(
+                        prop_info["value"]["virtual_cpu_clock"])               
+            elif prop_name == "virtual_memory":
+                vdu_node['nfv_compute']['mem_size'] = convert_factor_unit(
+                    prop_info["value"]["virtual_mem_size"])
+            elif prop_name == "requested_additional_capabilities":
+                if prop_info and "value" in prop_info:
+                    for key, val in prop_info["value"].items():
+                        vdu_node['nfv_compute']['flavor_extra_specs'].update(
+                            val["target_performance_parameters"])
+
+    vdu_node['cps'] = find_related_node(src_node['id'], src_json_model, 'virtualbinding')
+
+    for cp_node in vdu_node['cps']:
+        for src_cp_node in src_node_list:
+            if src_cp_node['template_name'] != cp_node:
+                continue
+            for relation in safe_get(src_cp_node, 'relationships'):
+                if relation['name'] != 'virtualLink':
+                    continue
+                vl_node_name = find_node_name(relation['target_node_id'], src_node_list)
+                if vl_node_name not in vdu_node['vls']:
+                    vdu_node['vls'].append(vl_node_name)
+
+    for item in safe_get(src_node, 'artifacts'):
+        artifact = {'artifact_name': item['name'], 'type': item['type_name'], 
+            'file': item['source_path'], 'properties': {}}
+        convert_props(item, artifact)
+        for key in artifact['properties']:
+            if 'factor' in artifact['properties'][key] and 'unit' in artifact['properties'][key]:
+                artifact['properties'][key] = convert_factor_unit(artifact['properties'][key])
+        vdu_node['artifacts'].append(artifact)
+        if artifact["type"].endswith(".SwImage"):
+            vdu_node['image_file'] = artifact["artifact_name"]
+    return vdu_node
+
+
+def convert_exposed_node(src_json, src_nodes, exposed):
+    for item in safe_get(safe_get(src_json, 'substitution'), 'requirements'):
+        exposed['external_cps'].append({'key_name': item['mapped_name'],
+            "cp_id": find_node_name(item['node_id'], src_nodes)})
+    for item in safe_get(safe_get(src_json, 'substitution'), 'capabilities'):
+        exposed['forward_cps'].append({'key_name': item['mapped_name'],
+            "cp_id": find_node_name(item['node_id'], src_nodes)})
+
+
+def convert_vnffgs(src_json_inst, src_nodes):
+    vnffgs = []
+    src_groups = safe_get(src_json_inst, 'groups')
+    for group in src_groups:
+        type_name = group['type_name'].upper()
+        if type_name.find('.VNFFG.') >= 0 or type_name.endswith('.VNFFG'):
+            vnffgs.append(convert_vnffg_group(group, src_groups, src_nodes))
+    return vnffgs
+
+def merge_imagefile_node(img_nodes, vdu_nodes):
+    for vdu_node in vdu_nodes:
+        for artifact in vdu_node.get("artifacts", []):
+            if not artifact["type"].endswith(".SwImage"):
+                continue
+            imgids = [img["image_file_id"] for img in img_nodes]
+            if artifact["artifact_name"] in imgids:
+                continue
+            img_nodes.append({
+                "image_file_id": artifact["artifact_name"],
+                "description": "",
+                "properties": artifact["properties"]
+            })
+
+def convert_common(src_json, target_json):
+    if isinstance(src_json, (unicode, str)):
+        src_json_dict = json.loads(src_json)
+    else:
+        src_json_dict = src_json
+    src_json_inst = src_json_dict["instance"]
+    src_json_model = src_json_dict["model"] if "model" in src_json_dict else {}
+
+    target_json['metadata'] = convert_metadata(src_json_inst)
+    target_json['inputs'] = convert_inputs(src_json_inst)
+    target_json['vls'] = []
+    target_json['cps'] = []
+    target_json['routers'] = []
+
+    return src_json_inst, src_json_model
+
+
+def convert_nsd_model(src_json):
+    target_json = {'vnfs': [], 'pnfs': [], 'fps': []}
+    src_json_inst, src_json_model = convert_common(src_json, target_json)
+   
+    src_nodes = src_json_inst['nodes']
+    for node in src_nodes:
+        type_name = node['type_name']
+        if type_name.find('.VNF.') > 0 or type_name.endswith('.VNF'):
+            target_json['vnfs'].append(convert_vnf_node(node, src_json_model))
+        elif type_name.find('.PNF.') > 0 or type_name.endswith('.PNF'):
+            target_json['pnfs'].append(convert_pnf_node(node, src_json_model))
+        elif type_name.find('.VL.') > 0 or type_name.endswith('.VL') \
+                or node['type_name'].find('.RouteExternalVL') > 0:
+            target_json['vls'].append(convert_vl_node(node, src_nodes))
+        elif type_name.find('.CP.') > 0 or type_name.endswith('.CP'):
+            target_json['cps'].append(convert_cp_node(node, src_nodes))
+        elif type_name.find('.FP.') > 0 or type_name.endswith('.FP'):
+            target_json['fps'].append(convert_fp_node(node, src_nodes, src_json_model))
+        elif type_name.endswith('.Router'):
+            target_json['routers'].append(convert_router_node(node, src_nodes))
+
+    target_json['vnffgs'] = convert_vnffgs(src_json_inst, src_nodes)
+
+    target_json['ns_exposed'] = {'external_cps': [], 'forward_cps': []}
+    convert_exposed_node(src_json_inst, src_nodes, target_json['ns_exposed'])
+    return json.dumps(target_json)
+
+
+def convert_vnfd_model(src_json):
+    target_json = {'image_files': [], 'local_storages': [], 'vdus': [], 'volume_storages': []}
+    src_json_inst, src_json_model = convert_common(src_json, target_json)
+
+    src_nodes = src_json_inst['nodes']
+    for node in src_nodes:
+        type_name = node['type_name']
+        if type_name.endswith('.ImageFile'):
+            target_json['image_files'].append(convert_imagefile_node(node, src_nodes))
+        elif type_name.endswith('.BlockStorage.Local') or type_name.endswith('.LocalStorage'):
+            target_json['local_storages'].append(convert_localstorage_node(node, src_nodes))
+        elif type_name.endswith('VDU.VirtualStorage'):
+            target_json['volume_storages'].append(convert_volumestorage_node(node, src_nodes))
+        elif type_name.endswith('VDU.Compute'):
+            target_json['vdus'].append(convert_vdu_node(node, src_nodes, src_json_model))
+        elif type_name.find('.VL.') > 0 or type_name.endswith('.VL') \
+                or type_name.endswith('.VnfVirtualLinkDesc') \
+                or type_name.endswith('.RouteExternalVL'):
+            target_json['vls'].append(convert_vl_node(node, src_nodes))
+        elif type_name.find('.CP.') > 0 or type_name.endswith('.CP') or type_name.endswith(".VduCpd"):
+            target_json['cps'].append(convert_cp_node(node, src_nodes, 'VNFD'))
+        elif type_name.endswith('.Router'):
+            target_json['routers'].append(convert_router_node(node, src_nodes))
+    
+    target_json['vnf_exposed'] = {'external_cps': [], 'forward_cps': []}
+    convert_exposed_node(src_json_inst, src_nodes, target_json['vnf_exposed'])
+    merge_imagefile_node(target_json['image_files'], target_json['vdus'])
+    return json.dumps(target_json)
+
+if __name__ == '__main__':
+    src_json = json.dumps({
+        "instance": {
+            "metadata": {
+                "vnfSoftwareVersion": "1.0.0",
+                "vnfProductName": "zte",
+                "localizationLanguage": [
+                    "english",
+                    "chinese"
+                ],
+                "vnfProvider": "zte",
+                "vnfmInfo": "zte",
+                "defaultLocalizationLanguage": "english",
+                "vnfdId": "zte-hss-1.0",
+                "vnfProductInfoDescription": "hss",
+                "vnfdVersion": "1.0.0",
+                "vnfProductInfoName": "hss"
+            },
+            "nodes": [
+                {
+                    "id": "vNAT_Storage_6wdgwzedlb6sq18uzrr41sof7",
+                    "type_name": "tosca.nodes.nfv.VDU.VirtualStorage",
+                    "template_name": "vNAT_Storage",
+                    "properties": {
+                        "size_of_storage": {
+                            "type_name": "scalar-unit.size",
+                            "value": {
+                                "value": 10000000000,
+                                "factor": 10,
+                                "unit": "GB",
+                                "unit_size": 1000000000
+                            }
+                        },
+                        "type_of_storage": {
+                            "type_name": "string",
+                            "value": "volume"
+                        },
+                        "rdma_enabled": {
+                            "type_name": "boolean",
+                            "value": False
+                        }
+                    },
+                    "interfaces": [
+                        {
+                            "name": "Standard",
+                            "description": "This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                            "type_name": "tosca.interfaces.node.lifecycle.Standard",
+                            "operations": [
+                                {
+                                    "name": "create",
+                                    "description": "Standard lifecycle create operation."
+                                },
+                                {
+                                    "name": "stop",
+                                    "description": "Standard lifecycle stop operation."
+                                },
+                                {
+                                    "name": "start",
+                                    "description": "Standard lifecycle start operation."
+                                },
+                                {
+                                    "name": "delete",
+                                    "description": "Standard lifecycle delete operation."
+                                },
+                                {
+                                    "name": "configure",
+                                    "description": "Standard lifecycle configure operation."
+                                }
+                            ]
+                        }
+                    ],
+                    "capabilities": [
+                        {
+                            "name": "feature",
+                            "type_name": "tosca.capabilities.Node"
+                        },
+                        {
+                            "name": "virtual_storage",
+                            "type_name": "tosca.capabilities.nfv.VirtualStorage"
+                        }
+                    ]
+                },
+                {
+                    "id": "sriov_link_2610d7gund4e645wo39dvp238",
+                    "type_name": "tosca.nodes.nfv.VnfVirtualLinkDesc",
+                    "template_name": "sriov_link",
+                    "properties": {
+                        "vl_flavours": {
+                            "type_name": "map",
+                            "value": {
+                                "vl_id": "aaaa"
+                            }
+                        },
+                        "connectivity_type": {
+                            "type_name": "tosca.datatypes.nfv.ConnectivityType",
+                            "value": {
+                                "layer_protocol": "ipv4",
+                                "flow_pattern": "flat"
+                            }
+                        },
+                        "description": {
+                            "type_name": "string",
+                            "value": "sriov_link"
+                        },
+                        "test_access": {
+                            "type_name": "list",
+                            "value": [
+                                "test"
+                            ]
+                        }
+                    },
+                    "interfaces": [
+                        {
+                            "name": "Standard",
+                            "description": "This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                            "type_name": "tosca.interfaces.node.lifecycle.Standard",
+                            "operations": [
+                                {
+                                    "name": "create",
+                                    "description": "Standard lifecycle create operation."
+                                },
+                                {
+                                    "name": "stop",
+                                    "description": "Standard lifecycle stop operation."
+                                },
+                                {
+                                    "name": "start",
+                                    "description": "Standard lifecycle start operation."
+                                },
+                                {
+                                    "name": "delete",
+                                    "description": "Standard lifecycle delete operation."
+                                },
+                                {
+                                    "name": "configure",
+                                    "description": "Standard lifecycle configure operation."
+                                }
+                            ]
+                        }
+                    ],
+                    "capabilities": [
+                        {
+                            "name": "feature",
+                            "type_name": "tosca.capabilities.Node"
+                        },
+                        {
+                            "name": "virtual_linkable",
+                            "type_name": "tosca.capabilities.nfv.VirtualLinkable"
+                        }
+                    ]
+                },
+                {
+                    "id": "vdu_vNat_7ozwkcr86sa87fmd2nue2ww07",
+                    "type_name": "tosca.nodes.nfv.VDU.Compute",
+                    "template_name": "vdu_vNat",
+                    "properties": {
+                        "configurable_properties": {
+                            "type_name": "map",
+                            "value": {
+                                "test": {
+                                    "additional_vnfc_configurable_properties": {
+                                        "aaa": "1",
+                                        "bbb": "2",
+                                        "ccc": "3"
+                                    }
+                                }
+                            }
+                        },
+                        "boot_order": {
+                            "type_name": "list",
+                            "value": [
+                                "vNAT_Storage"
+                            ]
+                        },
+                        "name": {
+                            "type_name": "string",
+                            "value": "vNat"
+                        },
+                        "nfvi_constraints": {
+                            "type_name": "list",
+                            "value": [
+                                "test"
+                            ]
+                        },
+                        "description": {
+                            "type_name": "string",
+                            "value": "the virtual machine of vNat"
+                        }
+                    },
+                    "interfaces": [
+                        {
+                            "name": "Standard",
+                            "description": "This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                            "type_name": "tosca.interfaces.node.lifecycle.Standard",
+                            "operations": [
+                                {
+                                    "name": "create",
+                                    "description": "Standard lifecycle create operation."
+                                },
+                                {
+                                    "name": "stop",
+                                    "description": "Standard lifecycle stop operation."
+                                },
+                                {
+                                    "name": "start",
+                                    "description": "Standard lifecycle start operation."
+                                },
+                                {
+                                    "name": "delete",
+                                    "description": "Standard lifecycle delete operation."
+                                },
+                                {
+                                    "name": "configure",
+                                    "description": "Standard lifecycle configure operation."
+                                }
+                            ]
+                        }
+                    ],
+                    "artifacts": [
+                        {
+                            "name": "vNatVNFImage",
+                            "type_name": "tosca.artifacts.nfv.SwImage",
+                            "source_path": "/swimages/vRouterVNF_ControlPlane.qcow2",
+                            "properties": {
+                                "operating_system": {
+                                    "type_name": "string",
+                                    "value": "linux"
+                                },
+                                "sw_image": {
+                                    "type_name": "string",
+                                    "value": "/swimages/vRouterVNF_ControlPlane.qcow2"
+                                },
+                                "name": {
+                                    "type_name": "string",
+                                    "value": "vNatVNFImage"
+                                },
+                                "checksum": {
+                                    "type_name": "string",
+                                    "value": "5000"
+                                },
+                                "min_ram": {
+                                    "type_name": "scalar-unit.size",
+                                    "value": {
+                                        "value": 1000000000,
+                                        "factor": 1,
+                                        "unit": "GB",
+                                        "unit_size": 1000000000
+                                    }
+                                },
+                                "disk_format": {
+                                    "type_name": "string",
+                                    "value": "qcow2"
+                                },
+                                "version": {
+                                    "type_name": "string",
+                                    "value": "1.0"
+                                },
+                                "container_format": {
+                                    "type_name": "string",
+                                    "value": "bare"
+                                },
+                                "min_disk": {
+                                    "type_name": "scalar-unit.size",
+                                    "value": {
+                                        "value": 10000000000,
+                                        "factor": 10,
+                                        "unit": "GB",
+                                        "unit_size": 1000000000
+                                    }
+                                },
+                                "supported_virtualisation_environments": {
+                                    "type_name": "list",
+                                    "value": [
+                                        "test_0"
+                                    ]
+                                },
+                                "size": {
+                                    "type_name": "scalar-unit.size",
+                                    "value": {
+                                        "value": 10000000000,
+                                        "factor": 10,
+                                        "unit": "GB",
+                                        "unit_size": 1000000000
+                                    }
+                                }
+                            }
+                        }
+                    ],
+                    "capabilities": [
+                        {
+                            "name": "feature",
+                            "type_name": "tosca.capabilities.Node"
+                        },
+                        {
+                            "name": "os",
+                            "type_name": "tosca.capabilities.OperatingSystem",
+                            "properties": {
+                                "distribution": {
+                                    "type_name": "string",
+                                    "description": "The Operating System (OS) distribution. Examples of valid values for a \"type\" of \"Linux\" would include: debian, fedora, rhel and ubuntu."
+                                },
+                                "version": {
+                                    "type_name": "version",
+                                    "description": "The Operating System version."
+                                },
+                                "type": {
+                                    "type_name": "string",
+                                    "description": "The Operating System (OS) type. Examples of valid values include: linux, aix, mac, windows, etc."
+                                },
+                                "architecture": {
+                                    "type_name": "string",
+                                    "description": "The Operating System (OS) architecture. Examples of valid values include: x86_32, x86_64, etc."
+                                }
+                            }
+                        },
+                        {
+                            "name": "host",
+                            "type_name": "tosca.capabilities.Container",
+                            "properties": {
+                                "cpu_frequency": {
+                                    "type_name": "scalar-unit.frequency",
+                                    "description": "Specifies the operating frequency of CPU's core. This property expresses the expected frequency of one (1) CPU as provided by the property \"num_cpus\"."
+                                },
+                                "mem_size": {
+                                    "type_name": "scalar-unit.size",
+                                    "description": "Size of memory available to applications running on the Compute node (default unit is MB)."
+                                },
+                                "num_cpus": {
+                                    "type_name": "integer",
+                                    "description": "Number of (actual or virtual) CPUs associated with the Compute node."
+                                },
+                                "disk_size": {
+                                    "type_name": "scalar-unit.size",
+                                    "description": "Size of the local disk available to applications running on the Compute node (default unit is MB)."
+                                }
+                            }
+                        },
+                        {
+                            "name": "binding",
+                            "type_name": "tosca.capabilities.network.Bindable"
+                        },
+                        {
+                            "name": "scalable",
+                            "type_name": "tosca.capabilities.Scalable",
+                            "properties": {
+                                "min_instances": {
+                                    "type_name": "integer",
+                                    "value": 1,
+                                    "description": "This property is used to indicate the minimum number of instances that should be created for the associated TOSCA Node Template by a TOSCA orchestrator."
+                                },
+                                "default_instances": {
+                                    "type_name": "integer",
+                                    "description": "An optional property that indicates the requested default number of instances that should be the starting number of instances a TOSCA orchestrator should attempt to allocate. Note: The value for this property MUST be in the range between the values set for \"min_instances\" and \"max_instances\" properties."
+                                },
+                                "max_instances": {
+                                    "type_name": "integer",
+                                    "value": 1,
+                                    "description": "This property is used to indicate the maximum number of instances that should be created for the associated TOSCA Node Template by a TOSCA orchestrator."
+                                }
+                            }
+                        },
+                        {
+                            "name": "virtual_compute",
+                            "type_name": "tosca.capabilities.nfv.VirtualCompute",
+                            "properties": {
+                                "requested_additional_capabilities": {
+                                    "type_name": "map",
+                                    "value": {
+                                        "ovs_dpdk": {
+                                            "requested_additional_capability_name": "ovs_dpdk",
+                                            "min_requested_additional_capability_version": "1.0",
+                                            "support_mandatory": True,
+                                            "target_performance_parameters": {
+                                                "sw:ovs_dpdk": "true"
+                                            },
+                                            "preferred_requested_additional_capability_version": "1.0"
+                                        },
+                                        "hyper_threading": {
+                                            "requested_additional_capability_name": "hyper_threading",
+                                            "min_requested_additional_capability_version": "1.0",
+                                            "support_mandatory": True,
+                                            "target_performance_parameters": {
+                                                "hw:cpu_cores": "2",
+                                                "hw:cpu_threads": "2",
+                                                "hw:cpu_threads_policy": "isolate",
+                                                "hw:cpu_sockets": "2"
+                                            },
+                                            "preferred_requested_additional_capability_version": "1.0"
+                                        },
+                                        "numa": {
+                                            "requested_additional_capability_name": "numa",
+                                            "min_requested_additional_capability_version": "1.0",
+                                            "support_mandatory": True,
+                                            "target_performance_parameters": {
+                                                "hw:numa_cpus.0": "0,1",
+                                                "hw:numa_cpus.1": "2,3,4,5",
+                                                "hw:numa_nodes": "2",
+                                                "hw:numa_mem.1": "3072",
+                                                "hw:numa_mem.0": "1024"
+                                            },
+                                            "preferred_requested_additional_capability_version": "1.0"
+                                        }
+                                    }
+                                },
+                                "virtual_cpu": {
+                                    "type_name": "tosca.datatypes.nfv.VirtualCpu",
+                                    "value": {
+                                        "num_virtual_cpu": 2,
+                                        "virtual_cpu_clock": {
+                                            "value": 2400000000,
+                                            "factor": 2.4,
+                                            "unit": "GHz",
+                                            "unit_size": 1000000000
+                                        },
+                                        "cpu_architecture": "X86",
+                                        "virtual_cpu_oversubscription_policy": "test",
+                                        "virtual_cpu_pinning": {
+                                            "cpu_pinning_map": {
+                                                "cpu_pinning_0": "1"
+                                            },
+                                            "cpu_pinning_policy": "static"
+                                        }
+                                    }
+                                },
+                                "virtual_memory": {
+                                    "type_name": "tosca.datatypes.nfv.VirtualMemory",
+                                    "value": {
+                                        "virtual_mem_oversubscription_policy": "mem_policy_test",
+                                        "numa_enabled": True,
+                                        "virtual_mem_size": {
+                                            "value": 10000000000,
+                                            "factor": 10,
+                                            "unit": "GB",
+                                            "unit_size": 1000000000
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "name": "virtual_binding",
+                            "type_name": "tosca.capabilities.nfv.VirtualBindable"
+                        }
+                    ],
+                    "relationships": [
+                        {
+                            "name": "virtual_storage",
+                            "source_requirement_index": 0,
+                            "target_node_id": "vNAT_Storage_6wdgwzedlb6sq18uzrr41sof7",
+                            "properties": {
+                                "location": {
+                                    "type_name": "string",
+                                    "value": "/mnt/volume_0",
+                                    "description": "The relative location (e.g., path on the file system), which provides the root location to address an attached node. e.g., a mount point / path such as '/usr/data'. Note: The user must provide it and it cannot be \"root\"."
+                                }
+                            },
+                            "source_interfaces": [
+                                {
+                                    "name": "Configure",
+                                    "description": "The lifecycle interfaces define the essential, normative operations that each TOSCA Relationship Types may support.",
+                                    "type_name": "tosca.interfaces.relationship.Configure",
+                                    "operations": [
+                                        {
+                                            "name": "add_source",
+                                            "description": "Operation to notify the target node of a source node which is now available via a relationship."
+                                        },
+                                        {
+                                            "name": "pre_configure_target",
+                                            "description": "Operation to pre-configure the target endpoint."
+                                        },
+                                        {
+                                            "name": "post_configure_source",
+                                            "description": "Operation to post-configure the source endpoint."
+                                        },
+                                        {
+                                            "name": "target_changed",
+                                            "description": "Operation to notify source some property or attribute of the target changed"
+                                        },
+                                        {
+                                            "name": "pre_configure_source",
+                                            "description": "Operation to pre-configure the source endpoint."
+                                        },
+                                        {
+                                            "name": "post_configure_target",
+                                            "description": "Operation to post-configure the target endpoint."
+                                        },
+                                        {
+                                            "name": "remove_target",
+                                            "description": "Operation to remove a target node."
+                                        },
+                                        {
+                                            "name": "add_target",
+                                            "description": "Operation to notify the source node of a target node being added via a relationship."
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "id": "SRIOV_Port_leu1j6rfdt4c8vta6aec1xe39",
+                    "type_name": "tosca.nodes.nfv.VduCpd",
+                    "template_name": "SRIOV_Port",
+                    "properties": {
+                        "address_data": {
+                            "type_name": "list",
+                            "value": [
+                                {
+                                    "address_type": "ip_address",
+                                    "l3_address_data": {
+                                        "ip_address_type": "ipv4",
+                                        "floating_ip_activated": False,
+                                        "number_of_ip_address": 1,
+                                        "ip_address_assignment": True
+                                    }
+                                }
+                            ]
+                        },
+                        "description": {
+                            "type_name": "string",
+                            "value": "sriov port"
+                        },
+                        "layer_protocol": {
+                            "type_name": "string",
+                            "value": "ipv4"
+                        },
+                        "virtual_network_interface_requirements": {
+                            "type_name": "list",
+                            "value": [
+                                {
+                                    "requirement": {
+                                        "SRIOV": "true"
+                                    },
+                                    "support_mandatory": False,
+                                    "name": "sriov",
+                                    "description": "sriov"
+                                },
+                                {
+                                    "requirement": {
+                                        "SRIOV": "false"
+                                    },
+                                    "support_mandatory": False,
+                                    "name": "normal",
+                                    "description": "normal"
+                                }
+                            ]
+                        },
+                        "role": {
+                            "type_name": "string",
+                            "value": "root"
+                        },
+                        "bitrate_requirement": {
+                            "type_name": "integer",
+                            "value": 10
+                        }
+                    },
+                    "interfaces": [
+                        {
+                            "name": "Standard",
+                            "description": "This lifecycle interface defines the essential, normative operations that TOSCA nodes may support.",
+                            "type_name": "tosca.interfaces.node.lifecycle.Standard",
+                            "operations": [
+                                {
+                                    "name": "create",
+                                    "description": "Standard lifecycle create operation."
+                                },
+                                {
+                                    "name": "stop",
+                                    "description": "Standard lifecycle stop operation."
+                                },
+                                {
+                                    "name": "start",
+                                    "description": "Standard lifecycle start operation."
+                                },
+                                {
+                                    "name": "delete",
+                                    "description": "Standard lifecycle delete operation."
+                                },
+                                {
+                                    "name": "configure",
+                                    "description": "Standard lifecycle configure operation."
+                                }
+                            ]
+                        }
+                    ],
+                    "capabilities": [
+                        {
+                            "name": "feature",
+                            "type_name": "tosca.capabilities.Node"
+                        }
+                    ],
+                    "relationships": [
+                        {
+                            "name": "virtual_binding",
+                            "source_requirement_index": 0,
+                            "target_node_id": "vdu_vNat_7ozwkcr86sa87fmd2nue2ww07",
+                            "source_interfaces": [
+                                {
+                                    "name": "Configure",
+                                    "description": "The lifecycle interfaces define the essential, normative operations that each TOSCA Relationship Types may support.",
+                                    "type_name": "tosca.interfaces.relationship.Configure",
+                                    "operations": [
+                                        {
+                                            "name": "add_source",
+                                            "description": "Operation to notify the target node of a source node which is now available via a relationship."
+                                        },
+                                        {
+                                            "name": "pre_configure_target",
+                                            "description": "Operation to pre-configure the target endpoint."
+                                        },
+                                        {
+                                            "name": "post_configure_source",
+                                            "description": "Operation to post-configure the source endpoint."
+                                        },
+                                        {
+                                            "name": "target_changed",
+                                            "description": "Operation to notify source some property or attribute of the target changed"
+                                        },
+                                        {
+                                            "name": "pre_configure_source",
+                                            "description": "Operation to pre-configure the source endpoint."
+                                        },
+                                        {
+                                            "name": "post_configure_target",
+                                            "description": "Operation to post-configure the target endpoint."
+                                        },
+                                        {
+                                            "name": "remove_target",
+                                            "description": "Operation to remove a target node."
+                                        },
+                                        {
+                                            "name": "add_target",
+                                            "description": "Operation to notify the source node of a target node being added via a relationship."
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            "name": "virtual_link",
+                            "source_requirement_index": 1,
+                            "target_node_id": "sriov_link_2610d7gund4e645wo39dvp238",
+                            "target_capability_name": "feature",
+                            "source_interfaces": [
+                                {
+                                    "name": "Configure",
+                                    "description": "The lifecycle interfaces define the essential, normative operations that each TOSCA Relationship Types may support.",
+                                    "type_name": "tosca.interfaces.relationship.Configure",
+                                    "operations": [
+                                        {
+                                            "name": "add_source",
+                                            "description": "Operation to notify the target node of a source node which is now available via a relationship."
+                                        },
+                                        {
+                                            "name": "pre_configure_target",
+                                            "description": "Operation to pre-configure the target endpoint."
+                                        },
+                                        {
+                                            "name": "post_configure_source",
+                                            "description": "Operation to post-configure the source endpoint."
+                                        },
+                                        {
+                                            "name": "target_changed",
+                                            "description": "Operation to notify source some property or attribute of the target changed"
+                                        },
+                                        {
+                                            "name": "pre_configure_source",
+                                            "description": "Operation to pre-configure the source endpoint."
+                                        },
+                                        {
+                                            "name": "post_configure_target",
+                                            "description": "Operation to post-configure the target endpoint."
+                                        },
+                                        {
+                                            "name": "remove_target",
+                                            "description": "Operation to remove a target node."
+                                        },
+                                        {
+                                            "name": "add_target",
+                                            "description": "Operation to notify the source node of a target node being added via a relationship."
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                }
+            ],
+            "substitution": {
+                "node_type_name": "tosca.nodes.nfv.VNF.vOpenNAT",
+                "requirements": [
+                    {
+                        "mapped_name": "sriov_plane",
+                        "node_id": "SRIOV_Port_leu1j6rfdt4c8vta6aec1xe39",
+                        "name": "virtual_link"
+                    }
+                ]
+            }
+        },
+        "model": {
+            "metadata": {
+                "vnfSoftwareVersion": "1.0.0",
+                "vnfProductName": "openNAT",
+                "localizationLanguage": [
+                    "english",
+                    "chinese"
+                ],
+                "vnfProvider": "intel",
+                "vnfmInfo": "GVNFM",
+                "defaultLocalizationLanguage": "english",
+                "vnfdId": "openNAT-1.0",
+                "vnfProductInfoDescription": "openNAT",
+                "vnfdVersion": "1.0.0",
+                "vnfProductInfoName": "openNAT"
+            },
+            "node_templates": [
+                {
+                    "name": "vNAT_Storage",
+                    "type_name": "tosca.nodes.nfv.VDU.VirtualStorage",
+                    "default_instances": 1,
+                    "min_instances": 0,
+                    "properties": {
+                        "size_of_storage": {
+                            "type_name": "scalar-unit.size",
+                            "value": {
+                                "value": 10000000000,
+                                "factor": 10,
+                                "unit": "GB",
+                                "unit_size": 1000000000
+                            }
+                        },
+                        "type_of_storage": {
+                            "type_name": "string",
+                            "value": "volume"
+                        },
+                        "rdma_enabled": {
+                            "type_name": "boolean",
+                            "value": False
+                        }
+                    },
+                    "interface_templates": [
+                        ""
+                    ],
+                    "capability_templates": [
+                        {
+                            "name": "feature",
+                            "type_name": "tosca.capabilities.Node"
+                        },
+                        {
+                            "name": "virtual_storage",
+                            "type_name": "tosca.capabilities.nfv.VirtualStorage"
+                        }
+                    ]
+                },
+                {
+                    "name": "vdu_vNat",
+                    "type_name": "tosca.nodes.nfv.VDU.Compute",
+                    "default_instances": 1,
+                    "min_instances": 0,
+                    "properties": {
+                        "configurable_properties": {
+                            "type_name": "map",
+                            "value": {
+                                "test": {
+                                    "additional_vnfc_configurable_properties": {
+                                        "aaa": "1",
+                                        "bbb": "2",
+                                        "ccc": "3"
+                                    }
+                                }
+                            }
+                        },
+                        "boot_order": {
+                            "type_name": "list",
+                            "value": [
+                                "vNAT_Storage"
+                            ]
+                        },
+                        "name": {
+                            "type_name": "string",
+                            "value": "vNat"
+                        },
+                        "nfvi_constraints": {
+                            "type_name": "list",
+                            "value": [
+                                "test"
+                            ]
+                        },
+                        "description": {
+                            "type_name": "string",
+                            "value": "the virtual machine of vNat"
+                        }
+                    },
+                    "interface_templates": [
+                        ""
+                    ],
+                    "artifact_templates": [
+                        ""
+                    ],
+                    "capability_templates": [
+                        {
+                            "name": "feature",
+                            "type_name": "tosca.capabilities.Node"
+                        },
+                        {
+                            "name": "os",
+                            "type_name": "tosca.capabilities.OperatingSystem",
+                            "properties": {
+                                "distribution": {
+                                    "type_name": "string",
+                                    "description": "The Operating System (OS) distribution. Examples of valid values for a \"type\" of \"Linux\" would include: debian, fedora, rhel and ubuntu."
+                                },
+                                "version": {
+                                    "type_name": "version",
+                                    "description": "The Operating System version."
+                                },
+                                "type": {
+                                    "type_name": "string",
+                                    "description": "The Operating System (OS) type. Examples of valid values include: linux, aix, mac, windows, etc."
+                                },
+                                "architecture": {
+                                    "type_name": "string",
+                                    "description": "The Operating System (OS) architecture. Examples of valid values include: x86_32, x86_64, etc."
+                                }
+                            }
+                        },
+                        {
+                            "name": "host",
+                            "type_name": "tosca.capabilities.Container",
+                            "valid_source_node_type_names": [
+                                "tosca.nodes.SoftwareComponent"
+                            ],
+                            "properties": {
+                                "cpu_frequency": {
+                                    "type_name": "scalar-unit.frequency",
+                                    "description": "Specifies the operating frequency of CPU's core. This property expresses the expected frequency of one (1) CPU as provided by the property \"num_cpus\"."
+                                },
+                                "mem_size": {
+                                    "type_name": "scalar-unit.size",
+                                    "description": "Size of memory available to applications running on the Compute node (default unit is MB)."
+                                },
+                                "num_cpus": {
+                                    "type_name": "integer",
+                                    "description": "Number of (actual or virtual) CPUs associated with the Compute node."
+                                },
+                                "disk_size": {
+                                    "type_name": "scalar-unit.size",
+                                    "description": "Size of the local disk available to applications running on the Compute node (default unit is MB)."
+                                }
+                            }
+                        },
+                        {
+                            "name": "binding",
+                            "type_name": "tosca.capabilities.network.Bindable"
+                        },
+                        {
+                            "name": "scalable",
+                            "type_name": "tosca.capabilities.Scalable",
+                            "properties": {
+                                "min_instances": {
+                                    "type_name": "integer",
+                                    "value": 1,
+                                    "description": "This property is used to indicate the minimum number of instances that should be created for the associated TOSCA Node Template by a TOSCA orchestrator."
+                                },
+                                "default_instances": {
+                                    "type_name": "integer",
+                                    "description": "An optional property that indicates the requested default number of instances that should be the starting number of instances a TOSCA orchestrator should attempt to allocate. Note: The value for this property MUST be in the range between the values set for \"min_instances\" and \"max_instances\" properties."
+                                },
+                                "max_instances": {
+                                    "type_name": "integer",
+                                    "value": 1,
+                                    "description": "This property is used to indicate the maximum number of instances that should be created for the associated TOSCA Node Template by a TOSCA orchestrator."
+                                }
+                            }
+                        },
+                        {
+                            "name": "virtual_compute",
+                            "type_name": "tosca.capabilities.nfv.VirtualCompute",
+                            "properties": {
+                                "requested_additional_capabilities": {
+                                    "type_name": "map",
+                                    "value": {
+                                        "ovs_dpdk": {
+                                            "requested_additional_capability_name": "ovs_dpdk",
+                                            "min_requested_additional_capability_version": "1.0",
+                                            "support_mandatory": True,
+                                            "target_performance_parameters": {
+                                                "sw:ovs_dpdk": "true"
+                                            },
+                                            "preferred_requested_additional_capability_version": "1.0"
+                                        },
+                                        "hyper_threading": {
+                                            "requested_additional_capability_name": "hyper_threading",
+                                            "min_requested_additional_capability_version": "1.0",
+                                            "support_mandatory": True,
+                                            "target_performance_parameters": {
+                                                "hw:cpu_cores": "2",
+                                                "hw:cpu_threads": "2",
+                                                "hw:cpu_threads_policy": "isolate",
+                                                "hw:cpu_sockets": "2"
+                                            },
+                                            "preferred_requested_additional_capability_version": "1.0"
+                                        },
+                                        "numa": {
+                                            "requested_additional_capability_name": "numa",
+                                            "min_requested_additional_capability_version": "1.0",
+                                            "support_mandatory": True,
+                                            "target_performance_parameters": {
+                                                "hw:numa_cpus.0": "0,1",
+                                                "hw:numa_cpus.1": "2,3,4,5",
+                                                "hw:numa_nodes": "2",
+                                                "hw:numa_mem.1": "3072",
+                                                "hw:numa_mem.0": "1024"
+                                            },
+                                            "preferred_requested_additional_capability_version": "1.0"
+                                        }
+                                    }
+                                },
+                                "virtual_cpu": {
+                                    "type_name": "tosca.datatypes.nfv.VirtualCpu",
+                                    "value": {
+                                        "num_virtual_cpu": 2,
+                                        "virtual_cpu_clock": {
+                                            "value": 2400000000,
+                                            "factor": 2.4,
+                                            "unit": "GHz",
+                                            "unit_size": 1000000000
+                                        },
+                                        "cpu_architecture": "X86",
+                                        "virtual_cpu_oversubscription_policy": "test",
+                                        "virtual_cpu_pinning": {
+                                            "cpu_pinning_map": {
+                                                "cpu_pinning_0": "1"
+                                            },
+                                            "cpu_pinning_policy": "static"
+                                        }
+                                    }
+                                },
+                                "virtual_memory": {
+                                    "type_name": "tosca.datatypes.nfv.VirtualMemory",
+                                    "value": {
+                                        "virtual_mem_oversubscription_policy": "mem_policy_test",
+                                        "numa_enabled": True,
+                                        "virtual_mem_size": {
+                                            "value": 10000000000,
+                                            "factor": 10,
+                                            "unit": "GB",
+                                            "unit_size": 1000000000
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "name": "virtual_binding",
+                            "type_name": "tosca.capabilities.nfv.VirtualBindable"
+                        }
+                    ],
+                    "requirement_templates": [
+                        {
+                            "name": "virtual_storage",
+                            "target_node_template_name": "vNAT_Storage",
+                            "relationship_template": {
+                                "type_name": "tosca.relationships.nfv.VDU.AttachedTo",
+                                "properties": {
+                                    "location": {
+                                        "type_name": "string",
+                                        "value": "/mnt/volume_0",
+                                        "description": "The relative location (e.g., path on the file system), which provides the root location to address an attached node. e.g., a mount point / path such as '/usr/data'. Note: The user must provide it and it cannot be \"root\"."
+                                    }
+                                },
+                                "source_interface_templates": [
+                                    ""
+                                ]
+                            }
+                        }
+                    ]
+                },
+                {
+                    "name": "SRIOV_Port",
+                    "type_name": "tosca.nodes.nfv.VduCpd",
+                    "default_instances": 1,
+                    "min_instances": 0,
+                    "properties": {
+                        "address_data": {
+                            "type_name": "list",
+                            "value": [
+                                {
+                                    "address_type": "ip_address",
+                                    "l3_address_data": {
+                                        "ip_address_type": "ipv4",
+                                        "floating_ip_activated": False,
+                                        "number_of_ip_address": 1,
+                                        "ip_address_assignment": True
+                                    }
+                                }
+                            ]
+                        },
+                        "description": {
+                            "type_name": "string",
+                            "value": "sriov port"
+                        },
+                        "layer_protocol": {
+                            "type_name": "string",
+                            "value": "ipv4"
+                        },
+                        "virtual_network_interface_requirements": {
+                            "type_name": "list",
+                            "value": [
+                                {
+                                    "requirement": {
+                                        "SRIOV": "true"
+                                    },
+                                    "support_mandatory": False,
+                                    "name": "sriov",
+                                    "description": "sriov"
+                                },
+                                {
+                                    "requirement": {
+                                        "SRIOV": "false"
+                                    },
+                                    "support_mandatory": False,
+                                    "name": "normal",
+                                    "description": "normal"
+                                }
+                            ]
+                        },
+                        "role": {
+                            "type_name": "string",
+                            "value": "root"
+                        },
+                        "bitrate_requirement": {
+                            "type_name": "integer",
+                            "value": 10
+                        }
+                    },
+                    "interface_templates": [
+                        ""
+                    ],
+                    "capability_templates": [
+                        {
+                            "name": "feature",
+                            "type_name": "tosca.capabilities.Node"
+                        }
+                    ],
+                    "requirement_templates": [
+                        {
+                            "name": "virtual_binding",
+                            "target_node_template_name": "vdu_vNat",
+                            "relationship_template": {
+                                "type_name": "tosca.relationships.nfv.VirtualBindsTo",
+                                "source_interface_templates": [
+                                    ""
+                                ]
+                            }
+                        },
+                        {
+                            "name": "virtual_link",
+                            "target_node_type_name": "tosca.nodes.nfv.VnfVirtualLinkDesc",
+                            "relationship_template": {
+                                "type_name": "tosca.relationships.nfv.VirtualLinksTo",
+                                "source_interface_templates": [
+                                    ""
+                                ]
+                            }
+                        }
+                    ]
+                }
+            ],
+            "substitution_template": {
+                "node_type_name": "tosca.nodes.nfv.VNF.vOpenNAT",
+                "requirement_templates": [
+                    {
+                        "mapped_name": "sriov_plane",
+                        "node_template_name": "SRIOV_Port",
+                        "name": "virtual_link"
+                    }
+                ]
+            }
+        }
+    })
+    print convert_vnfd_model(src_json)
+
+
+
+
diff --git a/lcm/pub/utils/values.py b/lcm/pub/utils/values.py
new file mode 100644 (file)
index 0000000..27d71a5
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright 2016 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.
+
+
+def ignore_case_get(args, key, def_val=""):
+    if not key:
+        return def_val
+    if key in args:
+        return args[key]
+    for old_key in args:
+        if old_key.upper() == key.upper():
+            return args[old_key]
+    return def_val
+
diff --git a/lcm/samples/__init__.py b/lcm/samples/__init__.py
new file mode 100644 (file)
index 0000000..5580cc3
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2016 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/samples/tests.py b/lcm/samples/tests.py
new file mode 100644 (file)
index 0000000..79301f1
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright 2016 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 unittest
+import json
+from django.test import Client
+from rest_framework import status
+
+
+class SampleViewTest(unittest.TestCase):
+    def setUp(self):
+        self.client = Client()
+
+    def tearDown(self):
+        pass
+
+    def test_sample(self):
+        response = self.client.get("/samples/")
+        self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
+        resp_data = json.loads(response.content)
+        self.assertEqual({"status": "active"}, resp_data)
diff --git a/lcm/samples/urls.py b/lcm/samples/urls.py
new file mode 100644 (file)
index 0000000..41f7f38
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright 2016 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 lcm.samples import views
+
+urlpatterns = [
+    url(r'^openoapi/nslcm/v1/mandb/(?P<modelName>[a-zA-Z\-]+)$', views.TablesList.as_view()),
+    url(r'^samples/$', views.SampleList.as_view()), ]
diff --git a/lcm/samples/views.py b/lcm/samples/views.py
new file mode 100644 (file)
index 0000000..0e3c6ac
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright 2016 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 rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+from lcm.pub.database import models
+
+
+logger = logging.getLogger(__name__)
+
+
+class SampleList(APIView):
+    """
+    List all samples.
+    """
+    def get(self, request, format=None):
+        logger.debug("get")
+        return Response({"status": "active"})
+
+class TablesList(APIView):
+    def delete(self, request, modelName):
+        logger.debug("Start delete model %s", modelName)
+        try:
+            modelNames = modelName.split("-")
+            for name in modelNames:
+                model_obj = eval("models.%s.objects" % name)
+                model_obj.filter().delete()
+                logger.debug("End delete model %s", name)
+        except:
+            logger.error(traceback.format_exc())
+            return Response(data={"error": "failed"}, 
+                status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        return Response(data={}, status=status.HTTP_204_NO_CONTENT)
+
+
+    def get(self, request, modelName):
+        logger.debug("Get model %s", modelName)
+        count = 0
+        try:
+            model_obj = eval("models.%s.objects" % modelName)
+            count = len(model_obj.filter())
+        except:
+            logger.error(traceback.format_exc())
+            return Response(data={"error": "failed"}, 
+                status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+        return Response(data={"count": count}, status=status.HTTP_200_OK)
+
+
+
+
diff --git a/lcm/settings.py b/lcm/settings.py
new file mode 100644 (file)
index 0000000..45ebfee
--- /dev/null
@@ -0,0 +1,144 @@
+# Copyright 2016 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 os
+import sys
+
+import redisco
+
+from lcm.pub.config.config import REDIS_HOST, REDIS_PORT, REDIS_PASSWD
+from lcm.pub.config.config import DB_NAME, DB_IP, DB_USER, DB_PASSWD, DB_PORT
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '3o-wney!99y)^h3v)0$j16l9=fdjxcb+a8g+q3tfbahcnu2b0o'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+# Application definition
+
+INSTALLED_APPS = [
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'rest_framework',
+    'lcm.pub.database',
+    'lcm.samples'
+]
+
+MIDDLEWARE_CLASSES = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'lcm.urls'
+
+WSGI_APPLICATION = 'lcm.wsgi.application'
+
+REST_FRAMEWORK = {
+    'DEFAULT_RENDERER_CLASSES': (
+        'rest_framework.renderers.JSONRenderer',
+    ),
+
+    'DEFAULT_PARSER_CLASSES': (
+        'rest_framework.parsers.JSONParser',
+        'rest_framework.parsers.MultiPartParser',
+        # 'rest_framework.parsers.FormParser',
+        # 'rest_framework.parsers.FileUploadParser',
+    )
+}
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.mysql',
+        'NAME': DB_NAME,
+        'HOST': DB_IP,
+        'PORT': DB_PORT,
+        'USER': DB_USER,
+        'PASSWORD': DB_PASSWD,
+    },
+}
+
+redisco.connection_setup(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWD, db=0)
+# CACHE_BACKEND = 'redis_cache.cache://%s@%s:%s' % (REDIS_PASSWD, REDIS_HOST, REDIS_PORT)
+
+TIME_ZONE = 'UTC'
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.6/howto/static-files/
+
+STATIC_URL = '/static/'
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': True,
+    'formatters': {
+        'standard': {
+            'format': '%(asctime)s:[%(name)s]:[%(filename)s]-[%(lineno)d] [%(levelname)s]:%(message)s',
+        },
+    },
+    'filters': {
+    },
+    'handlers': {
+        'lcm_handler': {
+            'level': 'DEBUG',
+            'class': 'logging.handlers.RotatingFileHandler',
+            'filename': os.path.join(BASE_DIR, 'logs/runtime_lcm.log'),
+            'formatter': 'standard',
+            'maxBytes': 1024 * 1024 * 50,
+            'backupCount': 5,
+        },
+    },
+
+    'loggers': {
+        'lcm': {
+            'handlers': ['lcm_handler'],
+            'level': 'DEBUG',
+            'propagate': False
+        },
+    }
+}
+
+if 'test' in sys.argv:
+    from lcm.pub.config import config
+    config.REG_TO_MSB_WHEN_START = False
+    DATABASES = {}
+    DATABASES['default'] = {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': ':memory:',
+    }
+    REST_FRAMEWORK = {}
+    import platform
+
+    if platform.system() == 'Linux':
+        TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
+        TEST_OUTPUT_VERBOSE = True
+        TEST_OUTPUT_DESCRIPTIONS = True
+        TEST_OUTPUT_DIR = 'test-reports'
diff --git a/lcm/urls.py b/lcm/urls.py
new file mode 100644 (file)
index 0000000..c9a808b
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright 2016 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 include, url
+from lcm.pub.config.config import REG_TO_MSB_WHEN_START, REG_TO_MSB_REG_URL, REG_TO_MSB_REG_PARAM
+
+urlpatterns = [
+    url(r'^', include('lcm.samples.urls')),
+    url(r'^', include('lcm.packages.urls')),
+    url(r'^', include('lcm.ns.vnfs.urls')),
+    url(r'^', include('lcm.ns.vls.urls')),
+    url(r'^', include('lcm.ns.sfcs.urls')),
+    url(r'^', include('lcm.ns.urls')),
+    url(r'^', include('lcm.jobs.urls')),
+]
+
+# regist to MSB when startup
+if REG_TO_MSB_WHEN_START:
+    import json
+    from lcm.pub.utils.restcall import req_by_msb
+    req_by_msb(REG_TO_MSB_REG_URL, "POST", json.JSONEncoder().encode(REG_TO_MSB_REG_PARAM))
diff --git a/lcm/wsgi.py b/lcm/wsgi.py
new file mode 100644 (file)
index 0000000..f1c80c4
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright 2016 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 os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lcm.settings")
+
+application = get_wsgi_application()
diff --git a/logs/empty.txt b/logs/empty.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/manage.py b/manage.py
new file mode 100644 (file)
index 0000000..5e92478
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,22 @@
+# Copyright 2016 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 os
+import sys
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lcm.settings")
+
+if __name__ == "__main__":
+    from django.core.management import execute_from_command_line
+    execute_from_command_line(sys.argv)
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..1c5f788
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!--
+    Copyright 2016 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.openo.nfvo</groupId>
+        <artifactId>nfvo-root</artifactId>
+        <version>1.1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.openo.nfvo</groupId>
+    <artifactId>nfvo-lcm</artifactId>
+    <version>1.1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>nfvo/lcm</name>
+    <description>nfvo lcm</description>
+    <build>
+      <plugins>
+        <plugin>
+            <artifactId>maven-assembly-plugin</artifactId>
+            <configuration>
+                <appendAssemblyId>false</appendAssemblyId>
+                <descriptors>
+                    <descriptor>assembly.xml</descriptor>
+                </descriptors>
+            </configuration>
+            <executions>
+                <execution>
+                    <id>make-assembly</id>
+                    <phase>package</phase>
+                    <goals>
+                        <goal>single</goal>
+                    </goals>
+                </execution>
+            </executions>
+        </plugin>
+      </plugins>
+    </build>
+</project>
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..2590479
--- /dev/null
@@ -0,0 +1,26 @@
+# rest framework
+Django==1.9.6
+djangorestframework==3.3.3
+
+# for access MySQL
+MySQL-python==1.2.5
+
+# redis cache
+redis==2.10.5
+
+# for access redis cache
+redisco==0.1.4
+django-redis-cache==0.13.1
+
+# for call rest api
+httplib2==0.9.2
+
+# for call openstack api
+python-keystoneclient==3.6.0
+python-glanceclient==2.5.0
+python-neutronclient==6.0.0
+
+# for unit test
+coverage==4.2
+mock==2.0.0
+unittest_xml_reporting==1.12.0
diff --git a/run.sh b/run.sh
new file mode 100644 (file)
index 0000000..e94f1bb
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright 2016 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.
+sip=127.0.0.1
+nohup python manage.py runserver $sip:8403 > /dev/null &
diff --git a/stop.sh b/stop.sh
new file mode 100644 (file)
index 0000000..5674b46
--- /dev/null
+++ b/stop.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright 2016 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.
+sip=127.0.0.1
+ps auxww | grep "manage.py runserver $sip:8403" | awk '{print $2}' | xargs kill -9
diff --git a/tox.ini b/tox.ini
new file mode 100644 (file)
index 0000000..baf2214
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,10 @@
+[tox]
+envlist = py27
+skipsdist = true
+
+[tox:jenkins]
+downloadcache = ~/cache/pip
+
+[testenv]
+deps = -r{toxinidir}/requirements.txt
+commands = coverage run --branch manage.py test lcm