summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--zte/vmanager/.idea/workspace.xml262
-rw-r--r--zte/vmanager/assembly.xml51
-rw-r--r--zte/vmanager/driver/__init__.py13
-rw-r--r--zte/vmanager/driver/interfaces/__init__.py13
-rw-r--r--zte/vmanager/driver/interfaces/tests.py425
-rw-r--r--zte/vmanager/driver/interfaces/urls.py36
-rw-r--r--zte/vmanager/driver/interfaces/views.py516
-rw-r--r--zte/vmanager/driver/pub/__init__.py13
-rw-r--r--zte/vmanager/driver/pub/config/__init__.py13
-rw-r--r--zte/vmanager/driver/pub/config/config.py33
-rw-r--r--zte/vmanager/driver/pub/database/__init__.py13
-rw-r--r--zte/vmanager/driver/pub/database/models.py13
-rw-r--r--zte/vmanager/driver/pub/utils/__init__.py13
-rw-r--r--zte/vmanager/driver/pub/utils/restcall.py95
-rw-r--r--zte/vmanager/driver/settings.py124
-rw-r--r--zte/vmanager/driver/swagger/__init__.py13
-rw-r--r--zte/vmanager/driver/swagger/swagger.json545
-rw-r--r--zte/vmanager/driver/swagger/tests.py31
-rw-r--r--zte/vmanager/driver/swagger/urls.py20
-rw-r--r--zte/vmanager/driver/swagger/views.py29
-rw-r--r--zte/vmanager/driver/urls.py26
-rw-r--r--zte/vmanager/driver/wsgi.py22
-rw-r--r--zte/vmanager/initialize.sh16
-rw-r--r--zte/vmanager/logs/empty.txt0
-rw-r--r--zte/vmanager/manage.py23
-rw-r--r--zte/vmanager/pom.xml53
-rw-r--r--zte/vmanager/requirements.txt11
-rw-r--r--zte/vmanager/run.sh16
-rw-r--r--zte/vmanager/stop.sh16
-rw-r--r--zte/vmanager/tox.ini7
30 files changed, 2461 insertions, 0 deletions
diff --git a/zte/vmanager/.idea/workspace.xml b/zte/vmanager/.idea/workspace.xml
new file mode 100644
index 00000000..68e827d7
--- /dev/null
+++ b/zte/vmanager/.idea/workspace.xml
@@ -0,0 +1,262 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ChangeListManager">
+ <list default="true" id="6d1646d8-eb46-431d-9ff7-452938d22ec7" name="Default" comment="" />
+ <ignored path="vmanager.iws" />
+ <ignored path=".idea/workspace.xml" />
+ <ignored path=".idea/dataSources.local.xml" />
+ <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
+ <option name="TRACKING_ENABLED" value="true" />
+ <option name="SHOW_DIALOG" value="false" />
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+ <option name="LAST_RESOLUTION" value="IGNORE" />
+ </component>
+ <component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
+ <component name="CreatePatchCommitExecutor">
+ <option name="PATCH_PATH" value="" />
+ </component>
+ <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
+ <component name="FavoritesManager">
+ <favorites_list name="vmanager" />
+ </component>
+ <component name="FileEditorManager">
+ <leaf>
+ <file leaf-file-name="views.py" pinned="false" current-in-tab="true">
+ <entry file="file://$PROJECT_DIR$/driver/interfaces/views.py">
+ <provider selected="true" editor-type-id="text-editor">
+ <state relative-caret-position="210">
+ <caret line="120" column="37" selection-start-line="120" selection-start-column="37" selection-end-line="120" selection-end-column="37" />
+ <folding />
+ </state>
+ </provider>
+ </entry>
+ </file>
+ </leaf>
+ </component>
+ <component name="IdeDocumentHistory">
+ <option name="CHANGED_PATHS">
+ <list>
+ <option value="$PROJECT_DIR$/driver/interfaces/views.py" />
+ </list>
+ </option>
+ </component>
+ <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
+ <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
+ <component name="JsGulpfileManager">
+ <detection-done>true</detection-done>
+ <sorting>DEFINITION_ORDER</sorting>
+ </component>
+ <component name="ProjectFrameBounds">
+ <option name="x" value="-8" />
+ <option name="y" value="-8" />
+ <option name="width" value="1612" />
+ <option name="height" value="876" />
+ </component>
+ <component name="ProjectLevelVcsManager" settingsEditedManually="false">
+ <OptionsSetting value="true" id="Add" />
+ <OptionsSetting value="true" id="Remove" />
+ <OptionsSetting value="true" id="Checkout" />
+ <OptionsSetting value="true" id="Update" />
+ <OptionsSetting value="true" id="Status" />
+ <OptionsSetting value="true" id="Edit" />
+ <ConfirmationsSetting value="0" id="Add" />
+ <ConfirmationsSetting value="0" id="Remove" />
+ </component>
+ <component name="ProjectView">
+ <navigator currentView="ProjectPane" proportions="" version="1">
+ <flattenPackages />
+ <showMembers />
+ <showModules />
+ <showLibraryContents />
+ <hideEmptyPackages />
+ <abbreviatePackageNames />
+ <autoscrollToSource />
+ <autoscrollFromSource />
+ <sortByType />
+ <manualOrder />
+ <foldersAlwaysOnTop value="true" />
+ </navigator>
+ <panes>
+ <pane id="Scratches" />
+ <pane id="Scope" />
+ <pane id="ProjectPane">
+ <subPane>
+ <PATH>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="vmanager" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
+ </PATH_ELEMENT>
+ </PATH>
+ <PATH>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="vmanager" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
+ </PATH_ELEMENT>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="vmanager" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
+ </PATH_ELEMENT>
+ </PATH>
+ <PATH>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="vmanager" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
+ </PATH_ELEMENT>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="vmanager" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
+ </PATH_ELEMENT>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="driver" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
+ </PATH_ELEMENT>
+ </PATH>
+ <PATH>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="vmanager" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
+ </PATH_ELEMENT>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="vmanager" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
+ </PATH_ELEMENT>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="driver" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
+ </PATH_ELEMENT>
+ <PATH_ELEMENT>
+ <option name="myItemId" value="interfaces" />
+ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
+ </PATH_ELEMENT>
+ </PATH>
+ </subPane>
+ </pane>
+ </panes>
+ </component>
+ <component name="PropertiesComponent">
+ <property name="options.splitter.main.proportions" value="0.3" />
+ <property name="options.lastSelected" value="preferences.sourceCode" />
+ <property name="options.splitter.details.proportions" value="0.2" />
+ <property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
+ <property name="settings.editor.splitter.proportion" value="0.2" />
+ <property name="last_opened_file_path" value="$PROJECT_DIR$" />
+ <property name="WebServerToolWindowFactoryState" value="false" />
+ </component>
+ <component name="RunManager" selected="Django server.vmanager">
+ <configuration default="true" type="Python.DjangoServer" factoryName="Django server">
+ <option name="INTERPRETER_OPTIONS" value="" />
+ <option name="PARENT_ENVS" value="true" />
+ <envs>
+ <env name="PYTHONUNBUFFERED" value="1" />
+ </envs>
+ <option name="SDK_HOME" value="" />
+ <option name="WORKING_DIRECTORY" value="" />
+ <option name="IS_MODULE_SDK" value="false" />
+ <option name="ADD_CONTENT_ROOTS" value="true" />
+ <option name="ADD_SOURCE_ROOTS" value="true" />
+ <module name="vmanager" />
+ <option name="launchJavascriptDebuger" value="false" />
+ <option name="port" value="8000" />
+ <option name="host" value="" />
+ <option name="additionalOptions" value="" />
+ <option name="browserUrl" value="" />
+ <option name="runTestServer" value="false" />
+ <option name="runNoReload" value="false" />
+ <option name="useCustomRunCommand" value="false" />
+ <option name="customRunCommand" value="" />
+ <method />
+ </configuration>
+ <configuration default="false" name="vmanager" type="Python.DjangoServer" factoryName="Django server">
+ <option name="INTERPRETER_OPTIONS" value="" />
+ <option name="PARENT_ENVS" value="true" />
+ <envs>
+ <env name="PYTHONUNBUFFERED" value="1" />
+ </envs>
+ <option name="SDK_HOME" value="" />
+ <option name="WORKING_DIRECTORY" value="" />
+ <option name="IS_MODULE_SDK" value="false" />
+ <option name="ADD_CONTENT_ROOTS" value="true" />
+ <option name="ADD_SOURCE_ROOTS" value="true" />
+ <module name="vmanager" />
+ <option name="launchJavascriptDebuger" value="false" />
+ <option name="port" value="8000" />
+ <option name="host" value="" />
+ <option name="additionalOptions" value="" />
+ <option name="browserUrl" value="" />
+ <option name="runTestServer" value="false" />
+ <option name="runNoReload" value="false" />
+ <option name="useCustomRunCommand" value="false" />
+ <option name="customRunCommand" value="" />
+ <method />
+ </configuration>
+ <list size="1">
+ <item index="0" class="java.lang.String" itemvalue="Django server.vmanager" />
+ </list>
+ </component>
+ <component name="ShelveChangesManager" show_recycled="false">
+ <option name="remove_strategy" value="false" />
+ </component>
+ <component name="SvnConfiguration" cleanupOnStartRun="true">
+ <configuration>C:\Users\10191177\AppData\Roaming\Subversion</configuration>
+ </component>
+ <component name="TaskManager">
+ <task active="true" id="Default" summary="Default task">
+ <changelist id="6d1646d8-eb46-431d-9ff7-452938d22ec7" name="Default" comment="" />
+ <created>1491809875990</created>
+ <option name="number" value="Default" />
+ <option name="presentableId" value="Default" />
+ <updated>1491809875990</updated>
+ </task>
+ <servers />
+ </component>
+ <component name="ToolWindowManager">
+ <frame x="-8" y="-8" width="1612" height="876" extended-state="1" />
+ <editor active="false" />
+ <layout>
+ <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25322166" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
+ <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
+ <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
+ <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
+ <window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
+ <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
+ <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+ <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
+ <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
+ <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
+ <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
+ <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
+ <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
+ <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+ <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
+ <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
+ <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+ <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
+ </layout>
+ </component>
+ <component name="Vcs.Log.UiProperties">
+ <option name="RECENTLY_FILTERED_USER_GROUPS">
+ <collection />
+ </option>
+ <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
+ <collection />
+ </option>
+ </component>
+ <component name="VcsContentAnnotationSettings">
+ <option name="myLimit" value="2678400000" />
+ </component>
+ <component name="XDebuggerManager">
+ <breakpoint-manager />
+ <watches-manager />
+ </component>
+ <component name="editorHistoryManager">
+ <entry file="file://$PROJECT_DIR$/driver/interfaces/views.py">
+ <provider selected="true" editor-type-id="text-editor">
+ <state relative-caret-position="210">
+ <caret line="120" column="37" selection-start-line="120" selection-start-column="37" selection-end-line="120" selection-end-column="37" />
+ <folding />
+ </state>
+ </provider>
+ </entry>
+ </component>
+</project> \ No newline at end of file
diff --git a/zte/vmanager/assembly.xml b/zte/vmanager/assembly.xml
new file mode 100644
index 00000000..cd9eda87
--- /dev/null
+++ b/zte/vmanager/assembly.xml
@@ -0,0 +1,51 @@
+<!--
+ 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>drivers-vnfm-svnfm-zte-vmanager</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <fileSets>
+ <fileSet>
+ <directory>driver</directory>
+ <outputDirectory>/driver</outputDirectory>
+ <includes>
+ <include>**/*.py</include>
+ <include>**/*.json</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>
+ </includes>
+ </fileSet>
+ </fileSets>
+ <baseDirectory>nfvo/drivers/vnfm/svnfm/zte/vmanager</baseDirectory>
+</assembly>
diff --git a/zte/vmanager/driver/__init__.py b/zte/vmanager/driver/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/zte/vmanager/driver/__init__.py
@@ -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/zte/vmanager/driver/interfaces/__init__.py b/zte/vmanager/driver/interfaces/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/zte/vmanager/driver/interfaces/__init__.py
@@ -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/zte/vmanager/driver/interfaces/tests.py b/zte/vmanager/driver/interfaces/tests.py
new file mode 100644
index 00000000..0fc179fd
--- /dev/null
+++ b/zte/vmanager/driver/interfaces/tests.py
@@ -0,0 +1,425 @@
+# 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 django.test import Client
+from django.test import TestCase
+from rest_framework import status
+from driver.pub.utils import restcall
+
+
+class InterfacesTest(TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ def tearDown(self):
+ pass
+
+ @mock.patch.object(restcall, 'call_req')
+ def test_instantiate_vnf_001(self, mock_call_req):
+ """
+ Initate_VNF
+ """
+ vnfm_info = {u'userName': u'admin',
+ u'vendor': u'ZTE',
+ u'name': u'ZTE_VNFM_237_62',
+ u'vimId': u'516cee95-e8ca-4d26-9268-38e343c2e31e',
+ u'url': u'http://192.168.237.165:2324',
+ u'certificateUrl': u'',
+ u'version': u'V1.0',
+ u'vnfmId': u'b0797c9b-3da9-459c-b25c-3813e9d8fd70',
+ u'password': u'admin',
+ u'type': u'ztevmanagerdriver',
+ u'createTime': u'2016-10-31 11:08:39',
+ u'description': u''}
+ vnfd_info = {u'vnfInstanceInfo': [{u'vnfInstanceId': u'59b79a9f-9e37-4f6c-acaf-5f41d9cb3f76',
+ u'vnfInstanceName': u'VFW_59b79a9f-9e37-4f6c-acaf-5f41d9cb3f76'},
+ {u'vnfInstanceId': u'6c5e4bd3-e8a6-42d8-a7a4-53a8ef74c6ac',
+ u'vnfInstanceName': u'VFW_6c5e4bd3-e8a6-42d8-a7a4-53a8ef74c6ac'},
+ {u'vnfInstanceId': u'930de5c9-8043-41df-ace8-ede2262a3713',
+ u'vnfInstanceName': u'VFW_930de5c9-8043-41df-ace8-ede2262a3713'},
+ {u'vnfInstanceId': u'c677a305-a7bd-4baf-9eee-c383c588bb3c',
+ u'vnfInstanceName': u'VFW_c677a305-a7bd-4baf-9eee-c383c588bb3c'},
+ {u'vnfInstanceId': u'e708e5c5-bdf4-436a-b928-826887806d82',
+ u'vnfInstanceName': u'VFW_e708e5c5-bdf4-436a-b928-826887806d82'}],
+ u'csarId': u'd852e1be-0aac-48f1-b1a4-cd825f6cdf9a',
+ u'imageInfo': [
+ {u'status': u'Enable', u'index': u'0',
+ u'vimId': u'516cee95-e8ca-4d26-9268-38e343c2e31e',
+ u'fileName': u'VFW_IMAGE_VCPE_ZTE',
+ u'vimUser': u'admin',
+ u'imageId': u'd2b73154-0414-466a-a1e6-51b9461b753a',
+ u'tenant': u'admin'}],
+ u'packageInfo': {u'usageState': u'NotInUse',
+ u'onBoardState': u'onBoarded',
+ u'name': u'VFW',
+ u'format': u'yaml',
+ u'provider': u'ZTE',
+ u'vnfdProvider': u'zte',
+ u'vnfdId': u'vcpe_vfw_zte_1_0',
+ u'deletionPending': False,
+ u'version': u'v1.0',
+ u'vnfVersion': u'1.0',
+ u'vnfdVersion': u'1.0.0',
+ u'processState': u'normal',
+ u'modifyTime': u'2016-10-31 16:21:32',
+ u'downloadUri': u'http://192.168.233.226:80/',
+ u'operationalState': u'Disabled',
+ u'createTime': u'2016-10-31 16:21:11',
+ u'size': u'12.1 MB'}}
+ packageInfo = {u'usageState': u'NotInUse',
+ u'onBoardState': u'onBoarded',
+ u'name': u'VFW',
+ u'format': u'yaml',
+ u'provider': u'ZTE',
+ u'vnfdProvider': u'zte',
+ u'vnfdId': u'vcpe_vfw_zte_1_0',
+ u'deletionPending': False,
+ u'version': u'v1.0',
+ u'vnfVersion': u'1.0',
+ u'vnfdVersion': u'1.0.0',
+ u'processState': u'normal',
+ u'modifyTime': u'2016-10-31 16:21:32',
+ u'downloadUri': u'http://192.168.233.226:80/files/catalog-http/NFAR/ZTE/VFW/v1.0/VFW.csar',
+ u'operationalState': u'Disabled',
+ u'createTime': u'2016-10-31 16:21:11', u'size': u'12.1 MB'}
+
+ ret = [0, json.JSONEncoder().encode({"vnfInstanceId":"8",
+ "jobid":"NF-CREATE-8-b384535c-9f45-11e6-8749-fa163e91c2f9"}),
+ '200']
+
+ r1 = [0, json.JSONEncoder().encode(vnfm_info), "200"]
+
+ r2 = [0, json.JSONEncoder().encode(vnfd_info), "200"]
+
+ r3 = [0, json.JSONEncoder().encode(packageInfo), "200"]
+
+
+ mock_call_req.side_effect = [r1, r2, r3, ret]
+
+ req_data = {'vnfInstanceName': 'VFW_f88c0cb7-512a-44c4-bd09-891663f19367',
+ 'vnfPackageId': 'd852e1be-0aac-48f1-b1a4-cd825f6cdf9a',
+ 'vnfDescriptorId': 'vcpe_vfw_zte_1_0',
+ 'additionalParam': {'sdncontroller': 'e4d637f1-a4ec-4c59-8b20-4e8ab34daba9',
+ 'NatIpRange': '192.167.0.10-192.168.0.20',
+ 'm6000_mng_ip': '192.168.11.11',
+ 'externalPluginManageNetworkName': 'plugin_net_2014',
+ 'location': '516cee95-e8ca-4d26-9268-38e343c2e31e',
+ 'externalManageNetworkName': 'mng_net_2017',
+ 'sfc_data_network': 'sfc_data_net_2016',
+ 'externalDataNetworkName': 'Flow_out_net',
+ 'inputs':{}}}
+
+ response = self.client.post("/openoapi/ztevnfm/v1/ztevnfmid/vnfs",
+ data=json.dumps(req_data), content_type="application/json")
+ self.assertEqual(str(status.HTTP_200_OK), response.status_code)
+ expect_resp_data = {"jobid": "NF-CREATE-8-b384535c-9f45-11e6-8749-fa163e91c2f9", "vnfInstanceId": "8"}
+ self.assertEqual(expect_resp_data, response.data)
+
+ @mock.patch.object(restcall, 'call_req')
+ def test_terminate_vnf__002(self, mock_call_req):
+ """
+ Terminate_VNF
+ """
+ r1 = [0, json.JSONEncoder().encode({
+ "vnfmId": "19ecbb3a-3242-4fa3-9926-8dfb7ddc29ee",
+ "name": "g_vnfm",
+ "type": "vnfm",
+ "vimId": "",
+ "vendor": "ZTE",
+ "version": "v1.0",
+ "description": "vnfm",
+ "certificateUrl": "",
+ "url": "http://10.74.44.11",
+ "userName": "admin",
+ "password": "admin",
+ "createTime": "2016-07-06 15:33:18"}), "200"]
+
+ r2 = [0, json.JSONEncoder().encode({"vnfInstanceId": "1", "JobId": "1"}), "200"]
+ mock_call_req.side_effect = [r1, r2]
+
+ response = self.client.post("/openoapi/ztevnfm/v1/ztevnfmid/vnfs/vbras_innstance_id/terminate")
+
+ self.assertEqual(str(status.HTTP_200_OK), response.status_code)
+ expect_resp_data = {"jobid": "1", "vnfInstanceId": "1"}
+ self.assertEqual(expect_resp_data, response.data)
+
+ @mock.patch.object(restcall, 'call_req')
+ def test_query_vnf_003(self, mock_call_req):
+ """
+ Query_VNF
+ """
+ r1 = [0, json.JSONEncoder().encode({
+ "vnfmId": "19ecbb3a-3242-4fa3-9926-8dfb7ddc29ee",
+ "name": "g_vnfm",
+ "type": "vnfm",
+ "vimId": "",
+ "vendor": "ZTE",
+ "version": "v1.0",
+ "description": "vnfm",
+ "certificateUrl": "",
+ "url": "http://10.74.44.11",
+ "userName": "admin",
+ "password": "admin",
+ "createTime": "2016-07-06 15:33:18"}), "200"]
+
+ r2 = [0, json.JSONEncoder().encode({"vnfinstancestatus": "1"}), "200"]
+ mock_call_req.side_effect = [r1, r2]
+
+ response = self.client.get("/openoapi/ztevnfm/v1/ztevnfmid/vnfs/vbras_innstance_id")
+
+ self.assertEqual(str(status.HTTP_200_OK), response.status_code)
+
+ expect_resp_data = {"vnfInfo": {"vnfStatus": "1"}}
+ self.assertEqual(expect_resp_data, response.data)
+
+ @mock.patch.object(restcall, 'call_req')
+ def test_operation_status_004(self, mock_call_req):
+ """
+ Operation_status
+ """
+ vnfm_info = {u'userName': u'admin',
+ u'vendor': u'ZTE',
+ u'name': u'ZTE_VNFM_237_62',
+ u'vimId': u'516cee95-e8ca-4d26-9268-38e343c2e31e',
+ u'url': u'http://192.168.237.165:2324',
+ u'certificateUrl': u'',
+ u'version': u'V1.0',
+ u'vnfmId': u'b0797c9b-3da9-459c-b25c-3813e9d8fd70',
+ u'password': u'admin',
+ u'type': u'ztevmanagerdriver',
+ u'createTime': u'2016-10-31 11:08:39',
+ u'description': u''}
+ resp_body = {"responsedescriptor":
+ {"status": "processing", "responsehistorylist": [
+ {"status": "error",
+ "progress": 255,
+ "errorcode": "",
+ "responseid": 20,
+ "statusdescription": "'JsonParser' object has no attribute 'parser_info'"}],
+ "responseid": 21,
+ "errorcode": "",
+ "progress": 40,
+ "statusdescription": "Create nf apply resource failed"},
+ "jobid": "NF-CREATE-11-ec6c2f2a-9f48-11e6-9405-fa163e91c2f9"}
+ r1 = [0, json.JSONEncoder().encode(vnfm_info), '200']
+ r2 = [0, json.JSONEncoder().encode(resp_body), '200']
+ mock_call_req.side_effect = [r1, r2]
+ response = self.client.get("/openoapi/ztevmanagerdriver/v1/{vnfmid}/jobs/{jobid}?responseId={responseId}".
+ format(
+ vnfmid=vnfm_info["vnfmId"],
+ jobid=resp_body["jobid"],
+ responseId=resp_body["responsedescriptor"]["responseid"]))
+
+ self.assertEqual(str(status.HTTP_200_OK), response.status_code)
+
+ expect_resp_data = resp_body
+ self.assertDictEqual(expect_resp_data, response.data)
+
+ @mock.patch.object(restcall, 'call_req')
+ def test_grantvnf_005(self, mock_call_req):
+ """
+ Grant_VNF
+ """
+ ret = [0,
+ '{"vim":{"accessinfo":{"tenant":"admin"},"vimid":"516cee95-e8ca-4d26-9268-38e343c2e31e"}}',
+ '201']
+
+ req_data = {
+ "vnfmid": "13232222",
+ "nfvoid": "03212234",
+ "vimid": "12345678",
+ "exvimidlist ":
+ ["exvimid"],
+ "tenant": " tenant1",
+ "vnfistanceid": "1234",
+ "operationright": "0",
+ "vmlist": [
+ {
+ "vmflavor": "SMP",
+ "vmnumber": "3"},
+ {
+ "vmflavor": "CMP",
+ "vmnumber": "3"}
+ ]}
+
+ mock_call_req.return_value = ret
+ response = self.client.put("/openoapi/ztevmanagerdriver/v1/resource/grant",
+ data=json.dumps(req_data), content_type='application/json')
+
+ self.assertEqual(str(status.HTTP_201_CREATED), response.status_code)
+
+ expect_resp_data = {
+ "vimid": "516cee95-e8ca-4d26-9268-38e343c2e31e",
+ "tenant": "admin"}
+ self.assertDictEqual(expect_resp_data, response.data)
+
+ @mock.patch.object(restcall, 'call_req')
+ def test_notify_006(self, mock_call_req):
+ """
+ Notification
+ """
+ r1 = [0, json.JSONEncoder().encode({
+ "vnfmId": "19ecbb3a-3242-4fa3-9926-8dfb7ddc29ee",
+ "name": "g_vnfm",
+ "type": "vnfm",
+ "vimId": "",
+ "vendor": "ZTE",
+ "version": "v1.0",
+ "description": "vnfm",
+ "certificateUrl": "",
+ "url": "http://10.74.44.11",
+ "userName": "admin",
+ "password": "admin",
+ "createTime": "2016-07-06 15:33:18"}), "200"]
+
+ r2 = [0, json.JSONEncoder().encode(
+ {"vim":
+ {
+ "vimInfoId": "111111",
+ "vimId": "12345678",
+ "interfaceInfo": {
+ "vimType": "vnf",
+ "apiVersion": "v1",
+ "protocolType": "None"},
+ "accessInfo": {
+ "tenant": "tenant1",
+ "username": "admin",
+ "password": "password"},
+ "interfaceEndpoint": "http://127.0.0.1/api/v1"},
+ "zone": "",
+ "addResource": {
+ "resourceDefinitionId": "xxxxx",
+ "vimId": "12345678",
+ "zoneId": "000"},
+ "removeResource": "",
+ "vimAssets": {
+ "computeResourceFlavour": {
+ "vimId": "12345678",
+ "vduId": "sdfasdf",
+ "vimFlavourId": "12"},
+ "softwareImage": {
+ "vimId": "12345678",
+ "imageName": "AAA",
+ "vimImageId": ""}},
+ "additionalParam": ""
+ }), "200"]
+
+ req_data = {
+ "nfvoid": "1",
+ "vnfmid": "876543211",
+ "vimid": "6543211",
+ "timestamp": "1234567890",
+ "vnfinstanceid": "1",
+ "eventtype": "0",
+ "vmlist":
+ [
+ {
+ "vmflavor": "SMP",
+ "vmnumber": "3",
+ "vmidlist ": ["vmuuid"]},
+ {
+ "vmflavor": "CMP",
+ "vmnumber": "3",
+ "vmidlist ": ["vmuuid"]}]}
+ mock_call_req.side_effect = [r1, r2]
+ response = self.client.post("/openoapi/ztevmanagerdriver/v1/vnfs/lifecyclechangesnotification",
+ data=json.dumps(req_data), content_type='application/json')
+
+ self.assertEqual(str(status.HTTP_200_OK), response.status_code)
+
+ expect_resp_data = None
+ self.assertEqual(expect_resp_data, response.data)
+
+ '''
+ @mock.patch.object(restcall, 'call_req')
+ def test_scale(self,mock_call_req):
+ job_info = {"jobid":"801","nfInstanceId":"101"}
+ vnfm_info = {u'userName': u'admin',
+ u'vendor': u'ZTE',
+ u'name': u'ZTE_VNFM_237_62',
+ u'vimId': u'516cee95-e8ca-4d26-9268-38e343c2e31e',
+ u'url': u'http://192.168.237.165:2324',
+ u'certificateUrl': u'',
+ u'version': u'V1.0',
+ u'vnfmId': u'b0797c9b-3da9-459c-b25c-3813e9d8fd70',
+ u'password': u'admin',
+ u'type': u'ztevmanagerdriver',
+ u'createTime': u'2016-10-31 11:08:39',
+ u'description': u''}
+
+ ret = [0, json.JSONEncoder().encode(job_info), "202"]
+ ret_vnfm = [0,json.JSONEncoder().encode(job_info), "200"]
+ mock_call_req.side_effect = [ret_vnfm, ret]
+
+ 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"],
+ }
+ ]
+ }
+
+ scale_vnf_data = {
+ "type":"SCALE_OUT",
+ "aspectId":"demo_aspect",
+ "numberOfSteps":"3",
+ "additionalParam":{
+ "vnfdModel":vnfd_info
+ }
+ }
+
+
+ response = self.client.post("/openoapi/ztevnfm/v1/vnfmid/vnfs/101/scale",
+ data=json.dumps(scale_vnf_data), content_type='application/json')
+
+ self.assertEqual(str(status.HTTP_202_ACCEPTED), response.status_code)
+
+ expect_resp_data = {"jobid":"801","nfInstanceId":"101"}
+ self.assertDictEqual(expect_resp_data, response.data)
+ '''
diff --git a/zte/vmanager/driver/interfaces/urls.py b/zte/vmanager/driver/interfaces/urls.py
new file mode 100644
index 00000000..43eb40a3
--- /dev/null
+++ b/zte/vmanager/driver/interfaces/urls.py
@@ -0,0 +1,36 @@
+# 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 url
+
+from driver.interfaces import views
+
+urlpatterns = [
+ url(r'^openoapi/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs$', views.instantiate_vnf,
+ name='instantiate_vnf'),
+ url(
+ r'^openoapi/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs/(?P<vnfInstanceId>'
+ r'[0-9a-zA-Z\-\_]+)/terminate$',
+ views.terminate_vnf, name='terminate_vnf'),
+ url(
+ r'^openoapi/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs/(?P<vnfInstanceId>'
+ r'[0-9a-zA-Z\-\_]+)$',
+ views.query_vnf, name='query_vnf'),
+ url(r'^openoapi/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/jobs/(?P<jobid>[0-9a-zA-Z\-\_]+)$',
+ views.operation_status, name='operation_status'),
+ url(r'^openoapi/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/resource/grant$', views.grantvnf, name='grantvnf'),
+ url(r'^openoapi/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/vnfs/lifecyclechangesnotification$', views.notify, name='notify'),
+ url(r'^openoapi/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs/(?P<nfInstanceId>[0-9a-zA-Z\-\_]+)/scale$',
+ views.scale, name='scale'),
+ url(r'^samples/$', views.samples, name='samples'), ]
diff --git a/zte/vmanager/driver/interfaces/views.py b/zte/vmanager/driver/interfaces/views.py
new file mode 100644
index 00000000..af316f01
--- /dev/null
+++ b/zte/vmanager/driver/interfaces/views.py
@@ -0,0 +1,516 @@
+# 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 inspect
+import json
+import logging
+import traceback
+
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+
+from driver.pub.utils import restcall
+from driver.pub.utils.restcall import req_by_msb
+
+logger = logging.getLogger(__name__)
+
+
+def fun_name():
+ return "=================%s==================" % inspect.stack()[1][3]
+
+
+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]:
+ resp_data[keyword_map[param]] = ignorcase_get(rest_return, param)
+ return resp_data
+
+
+query_vnfd_url = "openoapi/nslcm/v1/vnfpackage/%s"
+query_vnfm_url = "openoapi/extsys/v1/vnfms/%s"
+query_package_url = "openoapi/nslcm/v1/vnfpackage/%s"
+
+
+# Query VNFM by VNFMID
+def vnfm_get(vnfmid):
+ ret = req_by_msb("openoapi/extsys/v1/vnfms/%s" % vnfmid, "GET")
+ return ret
+
+
+def vnfd_get(vnfpackageid):
+ ret = req_by_msb("openoapi/nslcm/v1/vnfpackage/%s" % vnfpackageid, "GET")
+ return ret
+
+
+def vnfpackage_get(csarid):
+ ret = req_by_msb("openoapi/nslcm/v1/vnfpackage/%s" % csarid, "GET")
+ return ret
+
+
+# ==================================================
+create_vnf_url = "v1/vnfs"
+create_vnf_param_mapping = {
+ "packageUrl": "",
+ "instantiateUrl": "",
+ "instantiationLevel": "",
+ "vnfInstanceName": "",
+ "vnfPackageId": "",
+ "vnfDescriptorId": "",
+ "flavorId": "",
+ "vnfInstanceDescription": "",
+ "extVirtualLink": "",
+ "additionalParam": ""}
+create_vnf_resp_mapping = {
+ "VNFInstanceID": "vnfInstanceId",
+ "JobId": "jobid",}
+
+
+@api_view(http_method_names=['POST'])
+def instantiate_vnf(request, *args, **kwargs):
+ try:
+ logger.debug("[%s] request.data=%s", fun_name(), request.data)
+ vnfm_id = ignorcase_get(kwargs, "vnfmid")
+ ret = vnfm_get(vnfm_id)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ vnfm_info = json.JSONDecoder().decode(ret[1])
+ logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
+ vnf_package_id = ignorcase_get(request.data, "vnfPackageId")
+ ret = vnfd_get(vnf_package_id)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ vnfd_info = json.JSONDecoder().decode(ret[1])
+ logger.debug("[%s] vnfd_info=%s", fun_name(), vnfd_info)
+ csar_id = ignorcase_get(vnfd_info, "csarId")
+ ret = vnfpackage_get(csar_id)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ vnf_package_info = json.JSONDecoder().decode(ret[1])
+ packageInfo = ignorcase_get(vnf_package_info, "packageInfo")
+ logger.debug("[%s] packageInfo=%s", fun_name(), packageInfo)
+ data = {}
+ data["NFVOID"] = 1
+ data["VNFMID"] = vnfm_id
+ # data["VNFD"] = ignorcase_get(packageInfo, "downloadUri")
+ # data["VNFURL"] = ignorcase_get(packageInfo, "downloadUri")
+ vnfdId = ignorcase_get(packageInfo, "vnfdId")
+ from urlparse import urlparse
+ vnfm_ip = urlparse(ignorcase_get(vnfm_info, "url")).netloc.split(':')[0]
+ if "vCSCF_NF_ZTE" == vnfdId:
+ data["VNFD"] = "ftp://VMVERSION:vmversion@" + "192.168.128.159" + ":21/CSCF"
+ data["VNFURL"] = "ftp://VMVERSION:vmversion@" + "192.168.128.159" + ":21/CSCF"
+ elif "vPCRF_NF_ZTE" == vnfdId:
+ data["VNFD"] = "ftp://VMVERSION:vmversion@" + "192.168.128.159" + ":21/PCRF"
+ data["VNFURL"] = "ftp://VMVERSION:vmversion@" + "192.168.128.159" + ":21/PCRF"
+ elif "vTAS_NF_ZTE" == vnfdId:
+ data["VNFD"] = "ftp://VMVERSION:vmversion@" + "192.168.128.159" + ":21/SSS"
+ data["VNFURL"] = "ftp://VMVERSION:vmversion@" + "192.168.128.159" + ":21/SSS"
+ elif "vSPGW_NF_ZTE" == vnfdId:
+ data["VNFD"] = "ftp://VMVERSION:vmversion@" + "192.168.237.159" + ":21/vgw31"
+ data["VNFURL"] = "ftp://VMVERSION:vmversion@" + "192.168.237.159" + ":21/vgw31"
+ else:
+ data["VNFD"] = ignorcase_get(packageInfo, "downloadUri")
+ data["VNFURL"] = ignorcase_get(packageInfo, "downloadUri")
+
+ data["extension"] = {}
+ inputs = []
+ for name, value in ignorcase_get(ignorcase_get(request.data, "additionalParam"), "inputs").items():
+ inputs.append({"name": name, "value": value})
+
+ logger.info(
+ "ignorcase_get(request.data, \"additionalParam\") = %s" % ignorcase_get(request.data, "additionalParam"))
+ data["extension"]["inputs"] = json.dumps(inputs)
+ data["extension"]["extVirtualLinks"] = ignorcase_get(
+ ignorcase_get(request.data, "additionalParam"), "extVirtualLinks")
+ data["extension"]["vnfinstancename"] = ignorcase_get(request.data, "vnfInstanceName")
+ data["extension"]["vnfid"] = data["VNFD"]
+ data["extension"]["multivim"] = 0
+ logger.debug("[%s] call_req data=%s", fun_name(), data)
+ ret = restcall.call_req(
+ base_url=ignorcase_get(vnfm_info, "url"),
+ user=ignorcase_get(vnfm_info, "userName"),
+ passwd=ignorcase_get(vnfm_info, "password"),
+ auth_type=restcall.rest_no_auth,
+ resource=create_vnf_url,
+ method='post',
+ content=json.JSONEncoder().encode(data))
+ logger.debug("[%s] call_req ret=%s", fun_name(), ret)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ resp = json.JSONDecoder().decode(ret[1])
+ resp_data = mapping_conv(create_vnf_resp_mapping, resp)
+ logger.info("[%s]resp_data=%s", fun_name(), resp_data)
+ except Exception as e:
+ logger.error("Error occurred when instantiating VNF")
+ raise e
+ return Response(data=resp_data, status=ret[2])
+
+
+# ==================================================
+vnf_delete_url = "v1/vnfs/%s"
+vnf_delete_param_mapping = {
+ "terminationType": "terminationType",
+ "gracefulTerminationTimeout": "gracefulTerminationTimeout"}
+vnf_delete_resp_mapping = {
+ "vnfInstanceId": "vnfInstanceId",
+ "JobId": "jobid"}
+
+
+@api_view(http_method_names=['POST'])
+def terminate_vnf(request, *args, **kwargs):
+ try:
+ logger.debug("[%s] request.data=%s", fun_name(), request.data)
+ vnfm_id = ignorcase_get(kwargs, "vnfmid")
+ ret = vnfm_get(vnfm_id)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ vnfm_info = json.JSONDecoder().decode(ret[1])
+ logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
+ data = {}
+ logger.debug("[%s]req_data=%s", fun_name(), data)
+ ret = restcall.call_req(
+ base_url=ignorcase_get(vnfm_info, "url"),
+ user=ignorcase_get(vnfm_info, "userName"),
+ passwd=ignorcase_get(vnfm_info, "password"),
+ auth_type=restcall.rest_no_auth,
+ resource=vnf_delete_url % (ignorcase_get(kwargs, "vnfInstanceID")),
+ method='delete',
+ content=json.JSONEncoder().encode(data))
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ resp = json.JSONDecoder().decode(ret[1])
+ resp_data = mapping_conv(vnf_delete_resp_mapping, resp)
+ logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
+ except Exception as e:
+ logger.error("Error occurred when terminating VNF")
+ raise e
+ return Response(data=resp_data, status=ret[2])
+
+
+# ==================================================
+
+
+vnf_detail_url = "v1/vnfs/%s"
+vnf_detail_resp_mapping = {
+ "VNFInstanseStatus": "status",}
+
+
+@api_view(http_method_names=['GET'])
+def query_vnf(request, *args, **kwargs):
+ try:
+ logger.debug("[%s] request.data=%s", fun_name(), request.data)
+ vnfm_id = ignorcase_get(kwargs, "vnfmid")
+ ret = vnfm_get(vnfm_id)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ vnfm_info = json.JSONDecoder().decode(ret[1])
+ logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
+ data = {}
+ ret = restcall.call_req(
+ base_url=ignorcase_get(vnfm_info, "url"),
+ user=ignorcase_get(vnfm_info, "userName"),
+ passwd=ignorcase_get(vnfm_info, "password"),
+ auth_type=restcall.rest_no_auth,
+ resource=vnf_detail_url % (ignorcase_get(kwargs, "vnfInstanceID")),
+ method='get',
+ content=json.JSONEncoder().encode(data))
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ resp = json.JSONDecoder().decode(ret[1])
+ vnf_status = ignorcase_get(resp, "vnfinstancestatus")
+ resp_data = {"vnfInfo": {"vnfStatus": vnf_status}}
+ logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
+ except Exception as e:
+ logger.error("Error occurred when querying VNF information.")
+ raise e
+ return Response(data=resp_data, status=ret[2])
+
+
+# Get Operation Status
+operation_status_url = '/v1/jobs/{jobId}?NFVOID={nfvoId}&VNFMID={vnfmId}&ResponseID={responseId}'
+operation_status_resp_map = {
+ "JobId": "jobId",
+ "Status": "status",
+ "Progress": "progress",
+ "StatusDescription": "currentStep",
+ "ErrorCode": "errorCode",
+ "ResponseId": "responseId",
+ "ResponseHistoryList": "responseHistoryList",
+ "ResponseDescriptor": "responseDescriptor",}
+
+
+@api_view(http_method_names=['GET'])
+def operation_status(request, *args, **kwargs):
+ data = {}
+ try:
+ logger.debug("[%s] request.data=%s", fun_name(), request.data)
+ vnfm_id = ignorcase_get(kwargs, "vnfmid")
+ ret = vnfm_get(vnfm_id)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ vnfm_info = json.JSONDecoder().decode(ret[1])
+ logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
+ ret = restcall.call_req(
+ base_url=ignorcase_get(vnfm_info, 'url'),
+ user=ignorcase_get(vnfm_info, 'userName'),
+ passwd=ignorcase_get(vnfm_info, 'password'),
+ auth_type=restcall.rest_no_auth,
+ resource=operation_status_url.format(jobId=ignorcase_get(kwargs, 'jobid'), nfvoId=1,
+ vnfmId=ignorcase_get(kwargs, 'vnfmid'),
+ responseId=ignorcase_get(request.GET, 'responseId')),
+ method='get',
+ content=json.JSONEncoder().encode(data))
+
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ resp_data = json.JSONDecoder().decode(ret[1])
+ logger.info("[%s]resp_data=%s", fun_name(), resp_data)
+ except Exception as e:
+ logger.error("Error occurred when getting operation status information.")
+ raise e
+ return Response(data=resp_data, status=ret[2])
+
+
+# Grant VNF Lifecycle Operation
+grant_vnf_url = 'openoapi/nslcm/v1/ns/grantvnf'
+grant_vnf_param_map = {
+ "VNFMID": "",
+ "NFVOID": "",
+ "VIMID": "",
+ "ExVIMIDList": "",
+ "ExVIMID": "",
+ "Tenant": "",
+ "VNFInstanceID": "vnfInstanceId",
+ "OperationRight": "",
+ "VMList": "",
+ "VMFlavor": "",
+ "VMNumber": ""}
+
+
+@api_view(http_method_names=['PUT'])
+def grantvnf(request, *args, **kwargs):
+ logger.info("=====grantvnf=====")
+ try:
+ resp_data = {}
+ logger.info("req_data = %s", request.data)
+ data = mapping_conv(grant_vnf_param_map, request.data)
+ logger.info("grant_vnf_url = %s", grant_vnf_url)
+ data["vnfDescriptorId"] = ""
+ if ignorcase_get(request.data, "operationright") == 0:
+ data["lifecycleOperation"] = "Instantiate"
+ data["addresource"] = []
+ for vm in ignorcase_get(request.data, "vmlist"):
+ for i in range(int(ignorcase_get(vm, "vmnumber"))):
+ data["addresource"].append(
+ {"type": "vdu",
+ "resourceDefinitionId": i,
+ "vdu": ignorcase_get(vm, "vmflavor"),
+ "vimid": ignorcase_get(vm, "vimid"),
+ "tenant": ignorcase_get(vm, "tenant")
+ })
+
+ data["additionalparam"] = {}
+ data["additionalparam"]["vnfmid"] = ignorcase_get(request.data, "vnfmid")
+ data["additionalparam"]["vimid"] = ignorcase_get(request.data, "vimid")
+ data["additionalparam"]["tenant"] = ignorcase_get(request.data, "tenant")
+
+ logger.info("data = %s", data)
+ ret = req_by_msb(grant_vnf_url, "POST", content=json.JSONEncoder().encode(data))
+ logger.info("ret = %s", ret)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ resp = json.JSONDecoder().decode(ret[1])
+
+ resp_data['vimid'] = ignorcase_get(resp['vim'], 'vimid')
+ resp_data['tenant'] = ignorcase_get(ignorcase_get(resp['vim'], 'accessinfo'), 'tenant')
+
+ logger.info("[%s]resp_data=%s", fun_name(), resp_data)
+ except Exception as e:
+ logger.error("Error occurred in Grant VNF.")
+ raise e
+ return Response(data=resp_data, status=ret[2])
+
+
+# Notify LCM Events
+notify_url = 'openoapi/nslcm/v1/ns/{vnfmid}/vnfs/{vnfInstanceId}/Notify'
+notify_param_map = {
+ "NFVOID": "",
+ "VNFMID": "VNFMID",
+ "VIMID": "vimid",
+ "VNFInstanceID": "vnfInstanceId",
+ "TimeStamp": "",
+ "EventType": "operation",
+ "VMList": "",
+ "VMFlavor": "",
+ "VMNumber": "",
+ "VMIDlist": "",
+ "VMUUID": "",}
+
+
+@api_view(http_method_names=['POST'])
+def notify(request, *args, **kwargs):
+ try:
+ logger.info("[%s]req_data = %s", fun_name(), request.data)
+ data = mapping_conv(notify_param_map, request.data)
+ logger.info("[%s]data = %s", fun_name(), data)
+
+ data["status"] = "result"
+ data["jobId"] = "notMust"
+ data["affectedVnfc"] = []
+ data["affectedVl"] = []
+ data["affectedVirtualStorage"] = []
+ data["affectedCp"] = []
+
+ affectedvnfcs = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvnfc")
+ affectedvls = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvl")
+ affectedcps = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedcp")
+ vnfdmodule = ignorcase_get(ignorcase_get(request.data, "extension"), "vnfdmodule")
+
+ data["vnfdmodule"] = vnfdmodule
+
+ for affectedvnfc in affectedvnfcs:
+ data["affectedVnfc"].append({
+ "vnfcInstanceId": ignorcase_get(affectedvnfc, "vnfcinstanceid"),
+ "vduId": ignorcase_get(affectedvnfc, "vduId"),
+ "changeType": ignorcase_get(affectedvnfc, "changeType"),
+ "vimid": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "vimid"),
+ "vmId": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "resourceid"),
+ "vmName": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "resourcename")
+ })
+
+ for affectedvl in affectedvls:
+ data["affectedVl"].append({
+ "vlInstanceId": ignorcase_get(affectedvl, "virtuallinkinstanceid"),
+ "vimid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "vimid"),
+ "vldid": ignorcase_get(affectedvl, "virtuallinkdescid"),
+ "vllid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourceid"),
+ "vlName": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourcename")
+ })
+
+ for affectedcp in affectedcps:
+ data["affectedCp"].append(affectedcp)
+ # {
+ # "virtualLinkInstanceId": ignorcase_get(affectedcp, "virtuallinkinstanceid"),
+ # "ownerId": ignorcase_get(affectedcp, "ownerId"),
+ # "ownerType": ignorcase_get(affectedcp, "ownerType")
+ # }
+ ret = req_by_msb(notify_url.format(vnfmid=ignorcase_get(data, 'VNFMID'),
+ vnfInstanceId=ignorcase_get(data, 'vnfinstanceid')),
+ "POST", content=json.JSONEncoder().encode(data))
+
+ logger.info("[%s]data = %s", fun_name(), ret)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ except Exception as e:
+ logger.error("Error occurred in LCM notification.")
+ raise e
+ return Response(data=None, status=ret[2])
+
+
+nf_scaling_url = '/v1/vnfs/{vnfInstanceID}/scale'
+
+
+@api_view(http_method_names=['POST'])
+def scale(request, *args, **kwargs):
+ logger.info("====scale_vnf===")
+ try:
+ logger.info("request.data = %s", request.data)
+ logger.info("requested_url = %s", request.get_full_path())
+ vnfm_id = ignorcase_get(kwargs, "vnfmid")
+ nf_instance_id = ignorcase_get(kwargs, "nfInstanceId")
+ ret = vnfm_get(vnfm_id)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=ret[2])
+ vnfm_info = json.JSONDecoder().decode(ret[1])
+ scale_type = ignorcase_get(request.data, "type")
+ aspect_id = ignorcase_get(request.data, "aspectId")
+ number_of_steps = ignorcase_get(request.data, "numberOfSteps")
+ extension = ignorcase_get(request.data, "additionalParam")
+ vnfd_model = ignorcase_get(extension, "vnfdModel")
+ data = {
+ 'vnfmid': vnfm_id,
+ 'nfvoid': 1,
+ 'scaletype': '0' if scale_type == 'SCALE_OUT' else '1',
+ 'vmlist': [{'VMNumber':number_of_steps,'VMFlavor':aspect_id}],
+ 'extension':''
+ }
+ '''
+ for vdu_id in get_vdus(vnfd_model, aspect_id):
+ data['vmlist'].append({
+ "VMFlavor": vdu_id,
+ "VMNumber": number_of_steps
+ })
+ '''
+ logger.info("data = %s", data)
+ ret = restcall.call_req(
+ base_url=ignorcase_get(vnfm_info, "url"),
+ user=ignorcase_get(vnfm_info, "userName"),
+ passwd=ignorcase_get(vnfm_info, "password"),
+ auth_type=restcall.rest_no_auth,
+ resource=nf_scaling_url.format(vnfInstanceID=nf_instance_id),
+ method='put', # POST
+ content=json.JSONEncoder().encode(data))
+ logger.info("ret=%s", ret)
+ if ret[0] != 0:
+ return Response(data={'error':'scale error'}, status=ret[2])
+ resp_data = json.JSONDecoder().decode(ret[1])
+ jobId = resp_data["jobid"]
+ logger.info("resp_data=%s", resp_data)
+ except Exception as e:
+ logger.error("Error occurred when scaling VNF")
+ logger.error(traceback.format_exc())
+ return Response(data={'error':'scale expection'}, status='500')
+ return Response(data=resp_data, status=ret[2])
+
+
+#@staticmethod
+def get_vdus(nf_model, aspect_id):
+ associated_group = ''
+ members = []
+ vnf_flavours = nf_model['vnf_flavours']
+ for vnf_flaour in vnf_flavours:
+ scaling_aspects = vnf_flaour['scaling_aspects']
+ for aspect in scaling_aspects:
+ if aspect_id == aspect['id']:
+ associated_group = aspect['associated_group']
+ break
+ if not associated_group:
+ logger.error('Cannot find the corresponding element group')
+ raise Exception('Cannot find the corresponding element group')
+ for element_group in nf_model['element_groups']:
+ if element_group['group_id'] == associated_group:
+ members = element_group['members']
+ if not members:
+ logger.error('Cannot find the corresponding members')
+ raise Exception('Cannot find the corresponding members')
+ return members
+
+
+@api_view(http_method_names=['GET'])
+def samples(request, *args, **kwargs):
+ return Response(data={"status": "ok"})
diff --git a/zte/vmanager/driver/pub/__init__.py b/zte/vmanager/driver/pub/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/zte/vmanager/driver/pub/__init__.py
@@ -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/zte/vmanager/driver/pub/config/__init__.py b/zte/vmanager/driver/pub/config/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/zte/vmanager/driver/pub/config/__init__.py
@@ -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/zte/vmanager/driver/pub/config/config.py b/zte/vmanager/driver/pub/config/config.py
new file mode 100644
index 00000000..206e851a
--- /dev/null
+++ b/zte/vmanager/driver/pub/config/config.py
@@ -0,0 +1,33 @@
+# 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.
+
+# [MSB]
+MSB_SERVICE_IP = '127.0.0.1'
+MSB_SERVICE_PORT = '80'
+
+# [register]
+REG_TO_MSB_WHEN_START = True
+REG_TO_MSB_REG_URL = "/openoapi/microservices/v1/services"
+REG_TO_MSB_REG_PARAM = {
+ "serviceName": "ztevmanagerdriver",
+ "version": "v1",
+ "url": "/openoapi/ztevmanagerdriver/v1",
+ "protocol": "REST",
+ "visualRange": "1",
+ "nodes": [{
+ "ip": "127.0.0.1",
+ "port": "8410",
+ "ttl": 0
+ }]
+}
diff --git a/zte/vmanager/driver/pub/database/__init__.py b/zte/vmanager/driver/pub/database/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/zte/vmanager/driver/pub/database/__init__.py
@@ -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/zte/vmanager/driver/pub/database/models.py b/zte/vmanager/driver/pub/database/models.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/zte/vmanager/driver/pub/database/models.py
@@ -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/zte/vmanager/driver/pub/utils/__init__.py b/zte/vmanager/driver/pub/utils/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/zte/vmanager/driver/pub/utils/__init__.py
@@ -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/zte/vmanager/driver/pub/utils/restcall.py b/zte/vmanager/driver/pub/utils/restcall.py
new file mode 100644
index 00000000..ffde14da
--- /dev/null
+++ b/zte/vmanager/driver/pub/utils/restcall.py
@@ -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 driver.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/zte/vmanager/driver/settings.py b/zte/vmanager/driver/settings.py
new file mode 100644
index 00000000..8fec618f
--- /dev/null
+++ b/zte/vmanager/driver/settings.py
@@ -0,0 +1,124 @@
+# 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
+
+# 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',
+ 'driver.pub.database',
+ 'driver.interfaces'
+ ]
+
+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 = 'driver.urls'
+
+WSGI_APPLICATION = 'driver.wsgi.application'
+
+
+REST_FRAMEWORK = {
+ 'DEFAULT_RENDERER_CLASSES': (
+ 'rest_framework.renderers.JSONRenderer',),
+
+ 'DEFAULT_PARSER_CLASSES': (
+ 'rest_framework.parsers.MultiPartParser',
+ 'rest_framework.parsers.JSONParser')}
+"""
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.mysql',
+ 'NAME': 'vmanager',
+ 'HOST': 'localhost',
+ 'USER': 'root',
+ 'PASSWORD':'password',
+ },
+}
+
+redis_client = redis.StrictRedis(host='127.0.0.1', port=6379, password='', db=1)
+"""
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }}
+
+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': {
+ 'driver_handler': {
+ 'level': 'DEBUG',
+ 'class': 'logging.handlers.RotatingFileHandler',
+ 'filename': os.path.join(BASE_DIR, 'logs/runtime_driver.log'),
+ 'formatter': 'standard',
+ 'maxBytes': 1024 * 1024 * 50,
+ 'backupCount': 5, }, },
+
+ 'loggers': {
+ 'driver': {
+ 'handlers': ['driver_handler'],
+ 'level': 'DEBUG',
+ 'propagate': False}, }}
+
+if 'test' in sys.argv:
+ 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/zte/vmanager/driver/swagger/__init__.py b/zte/vmanager/driver/swagger/__init__.py
new file mode 100644
index 00000000..c7b6818e
--- /dev/null
+++ b/zte/vmanager/driver/swagger/__init__.py
@@ -0,0 +1,13 @@
+# 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/zte/vmanager/driver/swagger/swagger.json b/zte/vmanager/driver/swagger/swagger.json
new file mode 100644
index 00000000..c15aa313
--- /dev/null
+++ b/zte/vmanager/driver/swagger/swagger.json
@@ -0,0 +1,545 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "version": "1.0.0",
+ "title": "ZTE VNFM Driver Service rest API"
+ },
+ "basePath": "/openoapi/{vnfmtype}/v1",
+ "tags": [
+ {
+ "name": "ztevmanagerdriver"
+ }
+ ],
+ "paths": {
+ "/{vnfmid}/vnfs": {
+ "post": {
+ "tags": [
+ "vnf instantiate"
+ ],
+ "summary": "instantiate the vnf",
+ "description": "",
+ "operationId": "instantiate_vnf",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "vnfmid",
+ "in": "path",
+ "description": "vnfm instance id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "body",
+ "in": "body",
+ "description": "request parameters",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/VnfRequestParams"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/VnfResult"
+ }
+ },
+ "404": {
+ "description": "the vnfm instance id is wrong"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/{vnfmid}/vnfs/{vnfInstanceId}/terminate": {
+ "post": {
+ "tags": [
+ "vnf terminate"
+ ],
+ "summary": "terminate the vnf",
+ "description": "",
+ "operationId": "terminate_vnf",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "vnfmid",
+ "in": "path",
+ "description": "vnfm instance id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "vnfInstanceId",
+ "in": "path",
+ "description": "vnf instance id",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/VnfResult"
+ }
+ },
+ "404": {
+ "description": "the vnfmid and vnfInstanceId are wrong"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/{vnfmid}/vnfs/{vnfInstanceId}": {
+ "get": {
+ "tags": [
+ "query vnf"
+ ],
+ "summary": "query the vnf",
+ "description": "",
+ "operationId": "query_vnf",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "vnfmid",
+ "in": "path",
+ "description": "vnfm instance id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "vnfInstanceId",
+ "in": "path",
+ "description": "vnf instance id",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/returnVnfInfo"
+ }
+ },
+ "404": {
+ "description": "the vnfmid and vnfInstanceId are wrong"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/{vnfmid}/jobs/{jobid}": {
+ "get": {
+ "tags": [
+ "operation status"
+ ],
+ "summary": "operation status",
+ "description": "",
+ "operationId": "operation_status",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "vnfmid",
+ "in": "path",
+ "description": "vnfm instance id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "jobid",
+ "in": "path",
+ "description": "vnf job id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "responseId",
+ "in": "path",
+ "description": "vnf response id",
+ "required": true,
+ "type": "integer"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/OperationStatusInfo"
+ }
+ },
+ "404": {
+ "description": "the vnfmid ,jobid and responseId are wrong"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/resource/grant": {
+ "put": {
+ "tags": [
+ "grant vnf"
+ ],
+ "summary": "grant the vnf",
+ "description": "",
+ "operationId": "grant_vnf",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "body",
+ "in": "body",
+ "description": "request data for grant the vnf",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/RequestGrantParams"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "successful grant",
+ "schema": {
+ "$ref": "#/definitions/responseGrantResult"
+ }
+ },
+ "404": {
+ "description": "the request body is wrong"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/vnfs/lifecyclechangesnotification": {
+ "post": {
+ "tags": [
+ "life cycle changes notification"
+ ],
+ "summary": "life cycle changes notification",
+ "description": "",
+ "operationId": "lifecyclechangesnotification",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "body",
+ "in": "body",
+ "description": "request data for grant the vnf",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/RequestNotifyParams"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "successful Notify",
+ "schema": {
+ "$ref": "#/definitions/ResponseNotifyResult"
+ }
+ },
+ "404": {
+ "description": "the request body is wrong"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/{vnfmid}/vnfs/{nfInstanceId}/scale": {
+ "post": {
+ "tags": [
+ "scale vnf"
+ ],
+ "summary": "scale vnf",
+ "description": "",
+ "operationId": "scale_vnf",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "vnfmid",
+ "in": "path",
+ "description": "vnfm instance id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "nfInstanceId",
+ "in": "path",
+ "description": "nf instance id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "body",
+ "in": "body",
+ "description": "request data for grant the vnf",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/RequestScaleParams"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "successful scale",
+ "schema": {
+ "$ref": "#/definitions/ResponseScaleResult"
+ }
+ },
+ "404": {
+ "description": "the request body is wrong"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "VnfRequestParams": {
+ "type": "object",
+ "properties": {
+ "vnfInstanceName": {
+ "type": "string"
+ },
+ "vnfPackageId": {
+ "type": "string"
+ },
+ "vnfDescriptorId": {
+ "type": "string"
+ },
+ "additionalParam": {
+ "type": "object",
+ "properties": {
+ "sdncontroller": {
+ "type": "string"
+ },
+ "NatIpRange": {
+ "type": "string"
+ },
+ "m6000_mng_ip": {
+ "type": "string"
+ },
+ "externalPluginManageNetworkName": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ },
+ "externalManageNetworkName": {
+ "type": "string"
+ },
+ "sfc_data_network": {
+ "type": "string"
+ },
+ "externalDataNetworkName": {
+ "type": "string"
+ },
+ "inputs": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ },
+ "VnfResult": {
+ "type": "object",
+ "properties": {
+ "vnfInstanceId": {
+ "type": "string"
+ },
+ "jobid": {
+ "type": "string"
+ }
+ }
+ },
+ "returnVnfInfo": {
+ "type": "object",
+ "properties": {
+ "vnfInfo": {
+ "type": "object",
+ "properties": {
+ "vnfStatus": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "OperationStatusInfo": {
+ "type": "object",
+ "properties": {
+ "responsedescriptor": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "responsehistorylist": {
+ "type": "string"
+ },
+ "responseid": {
+ "type": "integer"
+ },
+ "errorcode": {
+ "type": "string"
+ },
+ "progress": {
+ "type": "integer"
+ },
+ "statusdescription": {
+ "type": "string"
+ }
+ }
+ },
+ "jobid": {
+ "type": "string"
+ }
+ }
+ },
+ "RequestGrantParams": {
+ "type": "object",
+ "properties": {
+ "vnfmid": {
+ "type": "string"
+ },
+ "nfvoid": {
+ "type": "string"
+ },
+ "vimid": {
+ "type": "string"
+ },
+ "exvimidlist": {
+ "type": "string"
+ },
+ "tenant": {
+ "type": "string"
+ },
+ "vnfistanceid": {
+ "type": "string"
+ },
+ "operationright": {
+ "type": "string"
+ },
+ "vmlist": {
+ "type": "string"
+ }
+ }
+ },
+ "responseGrantResult": {
+ "type": "object",
+ "properties": {
+ "vimid": {
+ "type": "string"
+ },
+ "tenant": {
+ "type": "string"
+ }
+ }
+ },
+ "RequestNotifyParams": {
+ "type": "object",
+ "properties": {
+ "nfvoid": {
+ "type": "string"
+ },
+ "vnfmid": {
+ "type": "string"
+ },
+ "vimid": {
+ "type": "string"
+ },
+ "timestamp": {
+ "type": "string"
+ },
+ "vnfinstanceid": {
+ "type": "string"
+ },
+ "eventtype": {
+ "type": "string"
+ },
+ "vmlist": {
+ "type": "string"
+ }
+ }
+ },
+ "ResponseNotifyResult": {
+ "type": "object"
+ },
+ "RequestScaleParams": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "aspectId": {
+ "type": "string"
+ },
+ "numberOfSteps": {
+ "type": "string"
+ },
+ "additionalParam": {
+ "type": "object"
+ }
+ }
+ },
+ "ResponseScaleResult": {
+ "type": "object",
+ "properties": {
+ "jobid": {
+ "type": "string"
+ },
+ "nfInstanceId": {
+ "type": "string"
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/zte/vmanager/driver/swagger/tests.py b/zte/vmanager/driver/swagger/tests.py
new file mode 100644
index 00000000..2bc8f8c0
--- /dev/null
+++ b/zte/vmanager/driver/swagger/tests.py
@@ -0,0 +1,31 @@
+# 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 unittest
+import json
+from django.test import Client
+from rest_framework import status
+
+
+class SwaggerViewTest(unittest.TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ def tearDown(self):
+ pass
+
+ def test_sample(self):
+ response = self.client.get("/openoapi/ztevmanagerdriver/v1/swagger.json")
+ self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
+
diff --git a/zte/vmanager/driver/swagger/urls.py b/zte/vmanager/driver/swagger/urls.py
new file mode 100644
index 00000000..48378707
--- /dev/null
+++ b/zte/vmanager/driver/swagger/urls.py
@@ -0,0 +1,20 @@
+# 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.conf.urls import url
+from driver.swagger import views
+
+urlpatterns = [
+ url(r'^openoapi/ztevmanagerdriver/v1/swagger.json$', views.SwaggerView.as_view()),
+]
diff --git a/zte/vmanager/driver/swagger/views.py b/zte/vmanager/driver/swagger/views.py
new file mode 100644
index 00000000..e9c96043
--- /dev/null
+++ b/zte/vmanager/driver/swagger/views.py
@@ -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.
+import os
+import json
+from rest_framework.views import APIView
+from rest_framework.response import Response
+
+
+class SwaggerView(APIView):
+ """
+ Show rest api swagger.
+ """
+ def get(self, request, format=None):
+ 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)
diff --git a/zte/vmanager/driver/urls.py b/zte/vmanager/driver/urls.py
new file mode 100644
index 00000000..94164d1b
--- /dev/null
+++ b/zte/vmanager/driver/urls.py
@@ -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.
+
+from driver.pub.config.config import REG_TO_MSB_WHEN_START, REG_TO_MSB_REG_URL, REG_TO_MSB_REG_PARAM
+from django.conf.urls import include, url
+urlpatterns = [
+ url(r'^', include('driver.interfaces.urls')),
+ url(r'^', include('driver.swagger.urls')),
+]
+
+# regist to MSB when startup
+if REG_TO_MSB_WHEN_START:
+ import json
+ from driver.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/zte/vmanager/driver/wsgi.py b/zte/vmanager/driver/wsgi.py
new file mode 100644
index 00000000..68fc46c6
--- /dev/null
+++ b/zte/vmanager/driver/wsgi.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
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "driver.settings")
+
+application = get_wsgi_application()
diff --git a/zte/vmanager/initialize.sh b/zte/vmanager/initialize.sh
new file mode 100644
index 00000000..8f6a0003
--- /dev/null
+++ b/zte/vmanager/initialize.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.
+
+pip install -r requirements.txt
diff --git a/zte/vmanager/logs/empty.txt b/zte/vmanager/logs/empty.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/zte/vmanager/logs/empty.txt
diff --git a/zte/vmanager/manage.py b/zte/vmanager/manage.py
new file mode 100644
index 00000000..401f8008
--- /dev/null
+++ b/zte/vmanager/manage.py
@@ -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.
+
+import os
+import sys
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "driver.settings")
+
+# load initial configuration
+if __name__ == "__main__":
+ from django.core.management import execute_from_command_line
+ execute_from_command_line(sys.argv)
diff --git a/zte/vmanager/pom.xml b/zte/vmanager/pom.xml
new file mode 100644
index 00000000..b61939c3
--- /dev/null
+++ b/zte/vmanager/pom.xml
@@ -0,0 +1,53 @@
+<?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>
+ <relativePath>../../../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.openo.nfvo</groupId>
+ <artifactId>drivers-vnfm-svnfm-zte-vmanager</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>nfvo/drivers/vnfm/svnfm/zte/vmanager</name>
+ <description>nfvo drivers-vnfm-svnfm-zte-vmanager</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/zte/vmanager/requirements.txt b/zte/vmanager/requirements.txt
new file mode 100644
index 00000000..49f0e42e
--- /dev/null
+++ b/zte/vmanager/requirements.txt
@@ -0,0 +1,11 @@
+# rest framework
+Django==1.9.6
+djangorestframework==3.3.3
+
+# for call rest api
+httplib2==0.9.2
+
+# for unit test
+coverage==4.2
+mock==2.0.0
+unittest_xml_reporting==1.12.0
diff --git a/zte/vmanager/run.sh b/zte/vmanager/run.sh
new file mode 100644
index 00000000..8c0b4fa6
--- /dev/null
+++ b/zte/vmanager/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:8410 > /dev/null &
diff --git a/zte/vmanager/stop.sh b/zte/vmanager/stop.sh
new file mode 100644
index 00000000..528da95c
--- /dev/null
+++ b/zte/vmanager/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:8410" | awk '{print $2}' | xargs kill -9
diff --git a/zte/vmanager/tox.ini b/zte/vmanager/tox.ini
new file mode 100644
index 00000000..4e62baf4
--- /dev/null
+++ b/zte/vmanager/tox.ini
@@ -0,0 +1,7 @@
+[tox]
+envlist = py27
+skipsdist = true
+
+[testenv]
+deps = -r{toxinidir}/requirements.txt
+commands = coverage run --branch manage.py test